hedera-web/js/vn/compiler-object.js

270 lines
5.3 KiB
JavaScript

var VnObject = require ('./object');
var Compiler = require ('./compiler');
var Component = require ('./component');
var Type = require ('./type');
var kebabToCamel = require ('./string-util').kebabToCamel;
var specialAttrs = {
id : 1,
property : 1
};
/**
* Compiles a @Vn.Object from element tag.
*/
module.exports = new Class
({
Extends: Compiler
,_links: []
,compile: function (builder, node, tagName)
{
var klass = vnCustomTags[tagName];
if (!klass)
return null;
var props = {};
var objectProps = {};
var funcProps = {};
var childs = [];
var events = {};
var context = {
klass: klass,
props: props,
objectProps: objectProps,
funcProps: funcProps,
childs: childs,
events: events,
custom: null
};
var a = node.attributes;
for (var i = 0; i < a.length; i++)
{
var attribute = a[i].nodeName;
var value = a[i].nodeValue;
if (this.isEvent (attribute))
events[attribute.substr (3)] = value;
else if (!specialAttrs[attribute])
this.propCompile (context, klass, node, attribute, value);
}
var childNodes = node.childNodes;
if (childNodes)
for (var i = 0; i < childNodes.length; i++)
{
var child = childNodes[i];
var childContext = null;
var childTagName = null;
if (child.nodeType === Node.ELEMENT_NODE)
childTagName = child.tagName.toLowerCase ();
if (childTagName === 'pointer')
{
this.addLink (context, null, child.getAttribute ('object'));
}
else if (childTagName === 'custom')
{
context.custom = child;
}
else if (childContext = builder._compile (child))
{
var prop = null;
if (childTagName)
prop = child.getAttribute ('property');
if (prop)
{
prop = kebabToCamel (prop);
objectProps[prop] = childContext.id;
}
else
childs.push (childContext.id);
}
}
return context;
}
,propCompile: function (context, klass, node, attribute, value)
{
var isLink = false;
var propError = false;
var newValue = null;
var propName = kebabToCamel (attribute);
var propInfo = klass.Properties[propName];
if (!propInfo)
{
this.showError ('Attribute \'%s\' not valid for tag \'%s\'',
attribute, node.tagName);
return;
}
if (!value)
{
this.showError ('Attribute \'%s\' empty on tag \'%s\'',
attribute, node.tagName);
return;
}
if (this._interpoler.compile (context, propName, value))
return;
switch (propInfo.type)
{
case null:
newValue = value;
break;
case Boolean:
newValue = (/^(true|1)$/i).test (value);
break;
case Number:
newValue = 0 + new Number (value);
break;
case String:
newValue = this.translateValue (value);
break;
case Function:
context.funcProps[propName] = value;
break;
case Type:
newValue = window[value];
break;
default:
if (propInfo.enumType)
newValue = propInfo.enumType[value];
else if (propInfo.type instanceof Function)
isLink = true;
else
propError = true;
}
if (isLink)
this.addLink (context, propName, value);
else if (newValue != null)
context.props[propName] = newValue;
else if (propError)
this.showError ('Attribute \'%s\' invalid for tag \'%s\'',
attribute, node.tagName);
}
,addLink: function (context, prop, objectId)
{
this._links.push ({
context: context
,prop: prop
,objectId: kebabToCamel (objectId)
});
}
,instantiate: function (doc, context, scope)
{
var object = new context.klass ();
object.setProperties (context.props);
if (context.nodeId && object instanceof Component)
{
var id = context.nodeId;
object.htmlId = scope.getHtmlId (id);
object.className = '_'+ id +' '+ object.className;
}
return object;
}
,setProperty: function (object, data, value)
{
object[data] = value;
}
,preLink: function (scope)
{
var objects = scope.objects;
var links = this._links;
for (var i = links.length - 1; i >= 0; i--)
{
var link = links[i];
var object = objects[link.context.id];
var objectRef = scope.$[link.objectId];
if (objectRef === undefined)
{
this.showError ('Referenced unexistent object with id \'%s\'',
link.objectId);
continue;
}
if (link.prop)
object[link.prop] = objectRef;
else
object.appendChild (objectRef);
}
}
,link: function (context, object, objects, scope)
{
var objectProps = context.objectProps;
for (var prop in objectProps)
object[prop] = objects[objectProps[prop]];
var childs = context.childs;
for (var i = 0; i < childs.length; i++)
object.appendChild (objects[childs[i]]);
if (context.custom)
object.loadXml (scope, context.custom);
}
,connect: function (context, object, objects, scope)
{
var funcProps = context.funcProps;
for (var prop in funcProps)
{
var method = scope.getMethod (funcProps[prop], true);
if (method)
object[prop] = method;
}
var events = context.events;
for (var event in events)
{
var method = scope.getMethod (events[event]);
if (method)
object.on (event, method, scope.thisArg);
}
}
,free: function (scope)
{
var objects = scope.objects;
for (var i = objects.length; i--;)
{
var object = objects[i];
if (object instanceof VnObject)
{
object.disconnectByInstance (scope.thisArg);
object.unref ();
}
}
}
,_replaceFunc: function (token)
{
return token.charAt(1).toUpperCase ();
}
});