hedera-web/web/js/vn/builder.js

330 lines
6.1 KiB
JavaScript
Executable File

/**
* Creates a object from a XML specification.
**/
Vn.Builder = new Class
({
Extends: Vn.Object
,objectMap: {}
,tags: {}
,loadXml: function (xmlDoc)
{
if (!xmlDoc)
return false;
var docElement = xmlDoc.documentElement;
if (docElement.tagName !== 'vn')
return false;
this.contexts = [];
var childs = docElement.childNodes;
if (childs)
for (var i = 0; i < childs.length; i++)
this.loadNode (childs[i], null);
this.resolveProperties ();
delete this.contexts;
return true;
}
,loadXmlFromNode: function (node)
{
this.contexts = [];
var mainNode = this.loadNode (node);
this.resolveProperties ();
delete this.contexts;
return mainNode;
}
,add: function (id, object)
{
this.objectMap[id] = object;
}
,loadNode: function (node)
{
var customNode;
var htmlNode = null;
var tagName = null;
if (node.tagName)
tagName = node.tagName.toLowerCase ();
if (tagName === 't')
{
htmlNode = document.createTextNode (_(node.firstChild.textContent));
}
else if (!tagName)
{
htmlNode = document.importNode (node, false);
}
else if ((customNode = this.loadCustomNode (node, null)))
{
if (customNode instanceof Htk.Widget)
htmlNode = customNode.getNode ();
}
else
{
htmlNode = document.createElement (tagName);
var a = node.attributes;
for (var i = 0; i < a.length; i++)
{
var nodeName = a[i].nodeName;
var nodeValue = a[i].nodeValue;
if (/^on-\w+/.test (nodeName))
{
var method = this.getMethod (nodeValue);
htmlNode.addEventListener (
nodeName.substr (3), method.bind (this.signalData));
}
else if (nodeName === 'id')
{
this.objectMap[nodeValue] = htmlNode;
}
else
htmlNode.setAttribute (nodeName,
this.translateValue (nodeValue));
}
var childs = node.childNodes;
if (childs)
for (var i = 0; i < childs.length; i++)
{
var htmlChild = this.loadNode (childs[i]);
if (htmlChild)
htmlNode.appendChild (htmlChild);
}
}
return htmlNode;
}
,loadCustomNode: function (node, parentContext)
{
if (!node.tagName)
return null;
var tagName = node.tagName.toLowerCase ();
var klass = Vn.customTags[tagName];
if (!klass)
return null;
var customNode = new klass ();
if (!this.tags[tagName])
this.tags[tagName] = [];
this.tags[tagName].push (customNode);
var context = {
node: node
,parent: parentContext
,object: customNode
,klass: klass
};
this.contexts.push (context);
var nodeId = node.getAttribute ('id');
if (nodeId)
this.objectMap[nodeId] = customNode;
var childs = node.childNodes;
if (childs)
for (var i = 0; i < childs.length; i++)
this.loadCustomNode (childs[i], context);
return customNode;
}
,translateValue: function (value)
{
var chr = value.charAt (0);
if (chr == '_')
return _(value.substr (1));
else if (chr == '\\' && value.charAt (1) == '_')
return value.substr (1);
return value;
}
,getMethod: function (value)
{
if (this.signalData)
var methodName = 'this.signalData.'+ value;
else
var methodName = value;
var method;
try {
method = eval (methodName);
}
catch (e)
{
method = null;
}
if (method == null)
console.warn ('Vn.Builder: Function \'%s\' not found',
value);
return method;
}
,replaceFunc: function (token)
{
return token.charAt(1).toUpperCase ();
}
,resolveProperties: function ()
{
for (var i = 0; i < this.contexts.length; i++)
{
var c = this.contexts[i];
var a = c.node.attributes;
for (var j = 0; j < a.length; j++)
this.setAttribute (c, a[j].nodeName, a[j].nodeValue);
if (c.parent)
{
var parentProperty = c.node.getAttribute ('property');
if (!parentProperty)
parentProperty = c.parent.klass.Child;
if (parentProperty)
this.setProperty (c.parent, parentProperty, c.object);
if (c.klass.Parent)
this.setProperty (c, c.klass.Parent, c.parent.object);
}
c.object.loadXml (this, c.node);
}
}
,setAttribute: function (c, attribute, value)
{
if (/^on-\w+/.test (attribute))
{
var method = this.getMethod (value);
if (method)
c.object.on (attribute.substr (3), method, this.signalData);
}
else if (!/^(id|property)$/.test (attribute))
{
this.setProperty (c, attribute, value)
}
}
,setProperty: function (c, attribute, value)
{
var propName = attribute.replace (/-./g, this.replaceFunc);
var prop = c.klass.Properties[propName];
if (!prop)
{
console.warn ('Vn.Builder: Attribute \'%s\' not valid for tag \'%s\'',
attribute, c.node.tagName);
return;
}
if (!value)
return;
switch (prop.type)
{
case Boolean:
value = (/^(true|1)$/i).test (value);
break;
case Number:
value = 0 + new Number (value);
break;
case String:
value = this.translateValue (value);
break;
case Function:
{
var method = this.getMethod (value);
value = method ? method.bind (this.signalData) : null;
break;
}
default:
if (prop.type instanceof Function)
{
if (typeof value == 'string')
value = this.get (value);
if (!(value instanceof prop.type))
return;
}
else if (prop.enumType)
value = prop.enumType[value];
}
if (value !== undefined)
c.object[propName] = value;
else
console.warn ('Vn.Builder: Empty attribute \'%s\' on tag \'%s\'',
attribute, c.node.tagName);
}
,setParent: function (parentBuilder)
{
this.parentBuilder = parentBuilder;
if (parentBuilder)
this.signalData = parentBuilder.signalData;
}
,$: function (objectId)
{
return this.get (objectId);
}
,get: function (objectId)
{
var object = this.objectMap[objectId];
if (object)
return object;
if (this.parentBuilder)
return this.parentBuilder.get (objectId);
return null;
}
,getObjects: function (tagName)
{
if (this.tags[tagName])
return this.tags[tagName];
return [];
}
,_destroy: function ()
{
for (var tag in this.tags)
{
var objects = this.tags[tag];
for (var i = 0; i < objects.length; i++)
objects[i].unref ();
}
this.parent ();
}
});