From 0cf90bb53ee6d029e7aaa4f6e1067a1236077c01 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Mon, 9 Nov 2015 18:11:51 +0100 Subject: [PATCH] =?UTF-8?q?Ahora=20Vn.Builder=20preprocesa=20los=20XML=20h?= =?UTF-8?q?aciendo=20que=20la=20carga=20repetida=20(Ej:=20Htk.Repeater)=20?= =?UTF-8?q?sea=20m=C3=A1s=20eficiente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/forms/ecomerce/catalog/catalog.js | 14 +- web/forms/ecomerce/catalog/ui.xml | 200 ++++---- web/js/htk/repeater.js | 97 ++-- web/js/vn/builder-new.js | 575 ---------------------- web/js/vn/builder.js | 656 +++++++++++++++++--------- web/js/vn/main.js | 1 - 6 files changed, 614 insertions(+), 929 deletions(-) delete mode 100755 web/js/vn/builder-new.js diff --git a/web/forms/ecomerce/catalog/catalog.js b/web/forms/ecomerce/catalog/catalog.js index 6c3517c9..e013f3ec 100755 --- a/web/forms/ecomerce/catalog/catalog.js +++ b/web/forms/ecomerce/catalog/catalog.js @@ -114,6 +114,7 @@ Vn.Catalog = new Class this.hideMenu (); var realms = this.$('realms-model'); + return; if (!realms.ready) return; @@ -350,7 +351,7 @@ Vn.Catalog = new Class Vn.Filter = new Class ({ - Extends: Htk.Widget + Extends: Htk.Field ,Tag: 'vn-filter' ,Child: 'model' ,Properties: @@ -403,8 +404,8 @@ Vn.Filter = new Class this.node.className = 'vn-filter'; this._select = new Htk.Select (); - this._select.on ('mousedown', this._onClick.bind (this)); - this._select.on ('changed', this._onChange.bind (this)); + this._select.on ('mousedown', this._onClick, this); + this._select.on ('changed', this._onChange, this); this.node.appendChild (this._select.getNode ()); this._ul = document.createElement ('ul'); @@ -422,10 +423,11 @@ Vn.Filter = new Class ,_onCloseClick: function (li) { Vn.Node.remove (li); + this.value = undefined; } ,_onChange: function () - { + { if (this._select.value === null || this._select.value === undefined) return; @@ -446,7 +448,9 @@ Vn.Filter = new Class var text = document.createTextNode (label); li.appendChild (text); - setTimeout (this._onTimeout.bind (this)); + setTimeout (this._onTimeout.bind (this)); + + this.value = this._select.value; } ,_onTimeout: function () diff --git a/web/forms/ecomerce/catalog/ui.xml b/web/forms/ecomerce/catalog/ui.xml index 28de2a31..17d17f0e 100755 --- a/web/forms/ecomerce/catalog/ui.xml +++ b/web/forms/ecomerce/catalog/ui.xml @@ -1,53 +1,61 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + - SELECT item_id, warehouse_id, SUM(amount) amount - FROM basket_item - GROUP BY warehouse_id + + SELECT item_id, warehouse_id, SUM(amount) amount + FROM basket_item + GROUP BY warehouse_id + @@ -57,11 +65,11 @@ SELECT Id_Article item_id FROM vn2008.Articles WHERE #filter; CALL bionic_calc (); - SELECT a.Id_Article item_id, t.available, t.price, p.producer, + SELECT a.Id_Article item_id, t.available, t.price, p.name producer, a.Foto, a.Article, a.Categoria, a.Medida, a.Tallos, a.Color, o.Abreviatura FROM tmp.bionic_item t JOIN vn2008.Articles a ON a.Id_Article = t.item_id - LEFT JOIN vn2008.Articles_producer p ON p.Id_Article = a.Id_Article + LEFT JOIN vn2008.producer p ON p.producer_id = a.producer_id LEFT JOIN vn2008.Origen o ON a.id_origen = o.id WHERE t.available > 0 ORDER BY a.Article, a.Medida @@ -177,8 +185,8 @@

- - from + + from @@ -226,59 +234,83 @@ - - CALL item_available (); - SELECT DISTINCT r.id, r.reino - FROM vn2008.reinos r - JOIN vn2008.Tipos t ON t.reino_id = r.id - JOIN vn2008.Articles a ON a.tipo_id = t.tipo_id - JOIN tmp.item_available i ON i.item_id = a.Id_Article - WHERE /*#filter - AND*/ r.display - ORDER BY r.reino + + + SELECT id, reino, color FROM vn2008.reinos + WHERE display != FALSE ORDER BY reino + - - - CALL item_available (); - SELECT DISTINCT t.tipo_id, LEFT(t.Tipo, 18) type - FROM vn2008.Tipos t - JOIN vn2008.Articles a ON a.tipo_id = t.tipo_id - JOIN tmp.item_available i ON i.item_id = a.Id_Article - /*WHERE #filter*/ - ORDER BY t.Tipo + + + + CALL item_available (); + SELECT DISTINCT t.tipo_id, LEFT(t.Tipo, 18) type + FROM vn2008.Tipos t + JOIN vn2008.Articles a ON a.tipo_id = t.tipo_id + JOIN tmp.item_available i ON i.item_id = a.Id_Article + /*WHERE #filter*/ + ORDER BY t.Tipo + - + - CALL item_available (); - SELECT DISTINCT c.Id_Tinta, c.name - FROM vn2008.Tintas c - JOIN vn2008.Articles a ON a.Color = c.Id_Tinta - JOIN tmp.item_available i ON i.item_id = a.Id_Article - /*WHERE #filter*/ - ORDER BY c.name + + CALL item_available (); + SELECT DISTINCT c.Id_Tinta, c.name + FROM vn2008.Tintas c + JOIN vn2008.Articles a ON a.Color = c.Id_Tinta + JOIN tmp.item_available i ON i.item_id = a.Id_Article + /*WHERE #filter*/ + ORDER BY c.name + - + - CALL item_available (); - SELECT DISTINCT o.id, o.Origen, o.Abreviatura - FROM vn2008.Origen o - JOIN vn2008.Articles a ON a.id_origen = o.id - JOIN tmp.item_available i ON i.item_id = a.Id_Article - /*WHERE #filter*/ - ORDER BY o.Origen + + CALL item_available (); + SELECT DISTINCT o.id, o.Origen, o.Abreviatura + FROM vn2008.Origen o + JOIN vn2008.Articles a ON a.id_origen = o.id + JOIN tmp.item_available i ON i.item_id = a.Id_Article + /*WHERE #filter*/ + ORDER BY o.Origen + - + - CALL item_available (); - SELECT DISTINCT a.Categoria, a.Categoria category - FROM vn2008.Articles a - JOIN tmp.item_available i ON i.item_id = a.Id_Article - /*WHERE #filter*/ - ORDER BY a.Categoria + + CALL item_available (); + SELECT DISTINCT a.Categoria, a.Categoria category + FROM vn2008.Articles a + JOIN tmp.item_available i ON i.item_id = a.Id_Article + /*WHERE #filter*/ + ORDER BY a.Categoria + + + + + + + CALL item_available (); + SELECT DISTINCT p.producer_id, p.name + FROM vn2008.producer p + JOIN vn2008.Articles a ON a.producer_id = p.producer_id + JOIN tmp.item_available i ON i.item_id = a.Id_Article + /*WHERE #filter*/ + ORDER BY p.name +
diff --git a/web/js/htk/repeater.js b/web/js/htk/repeater.js index 4da6b1fd..e6e697ee 100755 --- a/web/js/htk/repeater.js +++ b/web/js/htk/repeater.js @@ -12,13 +12,13 @@ Htk.Repeater = new Class { this.link ({_model: x}, { - 'status-changed': this.onModelChange - ,'row-deleted': this.onRowDelete - ,'row-updated': this.onRowUpdate - ,'row-inserted': this.onRowInsert + 'status-changed': this._onModelChange + ,'row-deleted': this._onRowDelete + ,'row-updated': this._onRowUpdate + ,'row-inserted': this._onRowInsert }); - this.onModelChange (); + this._onModelChange (); } ,get: function () { @@ -62,7 +62,10 @@ Htk.Repeater = new Class ,initialize: function (props) { var div = this.createElement ('div'); - div.className = 'htk-repeater'; + + this._container = document.createElement ('div'); + this._container.className = 'htk-repeater'; + div.appendChild (this._container); this.parent (props); } @@ -75,25 +78,25 @@ Htk.Repeater = new Class builder.setParent (builderResult); builder.loadXmlFromNode (node.firstElementChild); - this.onModelChange (); + this._onModelChange (); } ,getChild: function (index) { - return this.node.childNodes[index]; + return this._container.childNodes[index]; } ,getBuilder: function (index) { - return this.childsData[index].builder; + return this._childsData[index].builder; } ,getForm: function (index) { - return this.childsData[index].form; + return this._childsData[index].form; } - ,buildBox: function (index) + ,_buildBox: function (index) { var form = new Db.Form ({ model: this._model, @@ -103,61 +106,64 @@ Htk.Repeater = new Class this._builder.add (this._formId, form); var res = this._builder.load (); - this.childsData.push ({ + this._childsData.push ({ builder: res, form: form }); if (this._renderer) this._renderer (res, form); - - this.node.appendChild (res.getMain ()); + + return res.getMain (); } - ,onModelChange: function () + ,_onModelChange: function () { if (!this._model || !this._builder) return; - - Vn.Node.removeChilds (this.node); - this.freeChildsData (); - this.childsData = []; + + this.node.removeChild (this._container); + Vn.Node.removeChilds (this._container); + + this._freeChildsData (); + this._childsData = []; switch (this._model.status) { case Db.Model.Status.READY: { for (var i = 0; i < this._model.numRows; i++) - this.buildBox (i); + this._container.appendChild (this._buildBox (i)); - this.showNoRecordsFound (); + this._showNoRecordsFound (); break; } case Db.Model.Status.LOADING: - this.showMessage (_('Loading'), 'loader-black.gif'); + this._showMessage (_('Loading'), 'loader-black.gif'); break; case Db.Model.Status.CLEAN: - this.showMessage (this.emptyMessage, 'refresh.svg'); + this._showMessage (this.emptyMessage, 'refresh.svg'); break; case Db.Model.Status.ERROR: - this.showMessage (_('ErrorLoadingData'), 'error.svg'); + this._showMessage (_('ErrorLoadingData'), 'error.svg'); break; } + this.node.appendChild (this._container); this.signalEmit ('change'); } - ,showNoRecordsFound: function (count) + ,_showNoRecordsFound: function (count) { - if (this._model.numRows == 0) + if (this._model.numRows === 0) this.showMessage (_('EmptyList'), 'clean.svg'); } - ,showMessage: function (message, src) + ,_showMessage: function (message, src) { var div = document.createElement ('div'); div.className = 'message'; - this.node.appendChild (div); + this._container.appendChild (div); var img = document.createElement ('img'); img.alt = ''; @@ -167,35 +173,42 @@ Htk.Repeater = new Class div.appendChild (document.createTextNode (message)); } - ,onRowDelete: function (model, row) + ,_onRowDelete: function (model, row) { - Vn.Node.remove (this.node.childNodes[row]); - this.showNoRecordsFound (); + Vn.Node.remove (this._container.childNodes[row]); + this._unrefChildData (row); + this._showNoRecordsFound (); } - ,onRowUpdate: function (model, row, columns) + ,_onRowUpdate: function (model, row, columns) { // this.form[row].signalEmit ('iter-changed'); } - ,onRowInsert: function (model, row) + ,_onRowInsert: function (model, row) { - this.buildBox (row); + var box = this._buildBox (row); + this._container.appendChild (box); } - ,freeChildsData: function () + ,_freeChildsData: function () { - if (this.childsData) - for (var i = 0; i < this.childsData.length; i++) - { - this.childsData[i].form.unref (); - this.childsData[i].builder.unref (); - } + if (this._childsData) + for (var i = 0; i < this._childsData.length; i++) + this._unrefChildData (i); + } + + ,_unrefChildData: function (index) + { + var childData = this._childsData[index]; + childData.form.unref (); + childData.builder.unref (); } ,destroy: function () { - this.freeChildsData (); + this._freeChildsData (); this.parent (); } }); + diff --git a/web/js/vn/builder-new.js b/web/js/vn/builder-new.js deleted file mode 100755 index 0ec64301..00000000 --- a/web/js/vn/builder-new.js +++ /dev/null @@ -1,575 +0,0 @@ -/** - * Creates a object from a XML specification. - **/ -Vn.Builder = new Class -({ - Extends: Vn.Object - ,addedMap: {} - - ,add: function (id, object) - { - this.addedMap[id] = object; - } - - ,setParent: function (parentBuilder) - { - this.parentBuilder = parentBuilder; - - if (parentBuilder && !this.signalData) - this.signalData = parentBuilder.builder.signalData; - } - - ,getMain: function (result) - { - return result.objects[this.mainContext.id]; - } - - ,getById: function (objectId, result) - { - var index = this.contextMap[objectId]; - - if (index !== undefined) - return result.objects[index]; - else if (this.addedMap[objectId]) - return this.addedMap[objectId]; - else if (this.parentBuilder) - this.parentBuilder.getById (objectId); - - return null; - } - - ,getByTagName: function (tagName, result) - { - var tags = this.tags[tagName]; - - if (tags) - { - var arr = new Array (tags.length); - - for (var i = 0; i < tags.length; i++) - arr[i] = result.objects[tags[i]]; - - return arr; - } - - return []; - } - - ,loadXml: function (path, dstDocument) - { - var xmlDoc = Vn.getXml (path); - - if (!xmlDoc) - return false; - - var docElement = xmlDoc.documentElement; - - if (docElement.tagName !== 'vn') - return false; - - this._compileInit (dstDocument); - - var childs = docElement.childNodes; - - if (childs) - for (var i = 0; i < childs.length; i++) - this._compileNode (childs[i]); - - this._compileEnd (); - return true; - } - - ,loadXmlFromNode: function (node, dstDocument) - { - this._compileInit (dstDocument); - this.mainContext = this._compileNode (node); - this._compileEnd (); - } - - ,load: function () - { - var contexts = this.contexts; - var len = contexts.length; - var objects = new Array (len); - - for (var i = 0; i < len; i++) - { - var context = contexts[i]; - objects[i] = - this.textInstantiate (context) - || this.objectInstantiate (context) - || this.elementInstantiate (context); - } - - var res = new BuilderResult (this, objects); - - var addedObject; - - for (var i = this.propLinks.length - 1; i >= 0; i--) - { - var l = this.propLinks[i]; - if (addedObject = this.addedMap[l.value]) - objects[l.context.id][l.prop] = addedObject; - } - - for (var i = this.childLinks.length - 1; i >= 0; i--) - { - var l = this.childLinks[i]; - if (addedObject = this.addedMap[l.value]) - objects[l.context.id].appendChild (addedObject); - } - - for (var i = 0; i < len; i++) - { - var context = contexts[i]; - var object = objects[i]; - - this.objectLink (context, object, objects, res) || - this.elementLink (context, object, objects, res); - } - - return res; - } - - ,_compileInit: function (dstDocument) - { - this.tags = {}; - this.contexts = []; - this.contextMap = {}; - this.propLinks = []; - this.childLinks = []; - this.mainContext = null; - this.document = dstDocument ? dstDocument : document; - } - - ,_compileEnd: function (node) - { - var contextId; - - for (var i = this.propLinks.length - 1; i >= 0; i--) - { - var l = this.propLinks[i]; - - if (contextId = this.contextMap[l.value]) - { - l.context.objectProps[l.prop] = contextId; - this.propLinks.splice (i, 1); - } - else if (this.parentBuilder) - { - var object = this.parentBuilder.getById (l.value); - - if (object) - pl.context.props[pl.prop] = object; - } - } - - for (var i = this.childLinks.length - 1; i >= 0; i--) - { - var l = this.childLinks[i]; - - if (contextId = this.contextMap[l.value]) - { - l.context.childs.push (contextId); - this.childLinks.splice (i, 1); - } - } - } - - ,_compileNode: function (node) - { - var context = null; - var tagName = null; - - if (node.nodeType === Node.ELEMENT_NODE) - tagName = node.tagName.toLowerCase (); - else if (node.nodeType !== Node.TEXT_NODE - || /^\s*$/.test (node.textContent)) - return null; - - var context = - this.textCompile (node, tagName) - || this.objectCompile (node, tagName) - || this.elementCompile (node, tagName); - - context.id = this.contexts.length; - - if (tagName) - { - var nodeId = node.getAttribute ('id'); - - if (nodeId) - this.contextMap[nodeId] = context.id; - - var tags = this.tags[tagName]; - - if (!tags) - this.tags[tagName] = tags = []; - - tags.push (context.id); - } - - this.contexts.push (context); - return context; - } - - /** - * Creates a text node context. - **/ - ,textCompile: function (node, tagName) - { - if (!tagName) - var text = node.textContent; - else if (tagName === 't') - var text = _(node.firstChild.textContent); - else - return null; - - return {text: text}; - } - - ,textInstantiate: function (context) - { - if (!context.text) - return null; - - return this.document.createTextNode (context.text); - } - - /** - * Creates a object context. - **/ - ,objectCompile: function (node, tagName) - { - var handler; - var props = {}; - var objectProps = {}; - var childs = []; - var events = {}; - var klass = Vn.customTags[tagName]; - - if (!klass) - return null; - - var context = { - klass: klass, - props: props, - events: events, - objectProps: objectProps, - childs: childs - }; - - var a = node.attributes; - - for (var i = 0; i < a.length; i++) - { - var attribute = a[i].nodeName; - var value = a[i].nodeValue; - - if ((handler = this._getEventHandler (attribute, value))) - { - events[attribute.substr (3)] = handler; - } - else if (!/^(id|property)$/.test (attribute)) - { - this.propCompile (context, klass, props, - node, attribute, value); - } - } - - var childNodes = node.childNodes; - - if (childNodes) - for (var i = 0; i < childNodes.length; i++) - { - var child = childNodes[i]; - var childTagName = null; - - if (child.tagName) - childTagName = child.tagName.toLowerCase (); - - if (childTagName === 'pointer') - { - this.childLinks.push ({ - context: context, - objectId: child.getAttribute ('object') - }); - } - else if (childTagName === 'custom') - { - context.custom = child; - } - else - { - var childContext = this._compileNode (child); - - if (!childContext) - continue; - - var prop = null; - - if (child.getAttribute) - prop = child.getAttribute ('property'); - - if (prop) - objectProps[prop] = childContext.id; - else - childs.push (childContext.id); - } - } - - return context; - } - - ,propCompile: function (context, klass, props, node, attribute, value) - { - var newValue = null; - var propName = attribute.replace (/-./g, this._replaceFunc); - var propInfo = klass.Properties[propName]; - - if (!propInfo) - { - console.warn ('Vn.Builder: Attribute \'%s\' not valid for tag \'%s\'', - attribute, node.tagName); - return; - } - if (!value) - { - console.warn ('Vn.Builder: Attribute \'%s\' empty on tag \'%s\'', - attribute, node.tagName); - return; - } - - switch (propInfo.type) - { - 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: - newValue = this._getMethod (value); - break; - default: - if (propInfo.enumType) - newValue = propInfo.enumType[value]; - break; - } - - if (newValue !== null && newValue !== undefined) - { - props[propName] = newValue; - } - else if (propInfo.type instanceof Function) - { - this.propLinks.push ({ - context: context, - prop: attribute, - value: value - }); - } - else - console.warn ('Vn.Builder: Attribute \'%s\' invalid for tag \'%s\'', - attribute, node.tagName); - } - - ,objectInstantiate: function (context) - { - if (!context.klass) - return null; - - return new context.klass (context.props); - } - - ,objectLink: function (context, object, objects, res) - { - if (!context.klass) - return null; - - 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]]); - - var events = context.events; - for (var event in events) - object.on (event, - events[event].bind (this.signalData)); - - if (context.custom) - object.loadXml (res, context.custom); - } - - /** - * Creates a HTML node context. - **/ - ,elementCompile: function (node, tagName) - { - var handler; - var events = {}; - var childs = []; - var htmlNode = this.document.createElement (tagName); - - var a = node.attributes; - - for (var i = 0; i < a.length; i++) - { - var attribute = a[i].nodeName; - var value = a[i].nodeValue; - - if ((handler = this._getEventHandler (attribute, value))) - { - events[attribute.substr (3)] = handler; - } - else if (attribute !== 'id') - htmlNode.setAttribute (attribute, - this._translateValue (value)); - } - - var childNodes = node.childNodes; - - if (childNodes) - for (var i = 0; i < childNodes.length; i++) - { - var childContext = this._compileNode (childNodes[i]); - - if (childContext) - childs.push (childContext.id); - } - - return { - node: htmlNode, - events: events, - childs: childs - }; - } - - ,elementInstantiate: function (context) - { - if (!context.node) - return null; - - return context.node.cloneNode (false); - } - - ,elementLink: function (context, object, objects) - { - if (!context.node) - return null; - - var childs = context.childs; - for (var i = 0; i < childs.length; i++) - { - var child = objects[childs[i]]; - - if (child instanceof Htk.Widget) - object.appendChild (child.getNode ()); - else if (child instanceof Node) - object.appendChild (child); - } - - var events = context.events; - for (var event in events) - object.addEventListener (event, - events[event].bind (this.signalData)); - } - - ,_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; - } - - ,_getEventHandler: function (attribute, value) - { - if (!(/^on-\w+/.test (attribute))) - return null; - - return this._getMethod (value); - } - - ,_replaceFunc: function (token) - { - return token.charAt(1).toUpperCase (); - } -}); - -var BuilderResult = new Class -({ - Extends: Vn.Object - - ,initialize: function (builder, objects) - { - this.builder = builder; - this.objects = objects; - } - - ,getMain: function () - { - return this.builder.getMain (this); - } - - ,$: function (objectId) - { - return this.builder.getById (objectId, this); - } - - ,getById: function (objectId) - { - return this.builder.getById (objectId, this); - } - - ,getByTagName: function (tagName) - { - return this.builder.getByTagName (tagName, this); - } - - ,_destroy: function () - { - var objects = this.objects; - - for (var i = 0; i < objects.length; i++) - if (objects[i].unref) - objects[i].unref (); - - this.parent (); - } -}); - diff --git a/web/js/vn/builder.js b/web/js/vn/builder.js index 95a9f227..162240cd 100755 --- a/web/js/vn/builder.js +++ b/web/js/vn/builder.js @@ -1,274 +1,491 @@ /** * Creates a object from a XML specification. **/ -Vn.BuilderOld = new Class +Vn.Builder = new Class ({ Extends: Vn.Object - ,objectMap: {} - ,tags: {} + ,_addedMap: {} + ,_contexts: null - ,load: function () + ,add: function (id, object) { - return this; + this._addedMap[id] = object; + } + + ,setParent: function (parentResult) + { + this._parentResult = parentResult; + + if (parentResult && !this.signalData) + this.signalData = parentResult.builder.signalData; + } + + ,getMain: function (result) + { + return result.objects[this._mainContext]; + } + + ,getById: function (objectId, result) + { + var index = this._contextMap[objectId]; + + if (index !== undefined) + return result.objects[index]; + else if (this._parentResult) + return this._parentResult.getById (objectId); + + return null; + } + + ,getByTagName: function (tagName, result) + { + var tags = this._tags[tagName]; + + if (tags) + { + var arr = new Array (tags.length); + + for (var i = 0; i < tags.length; i++) + arr[i] = result.objects[tags[i]]; + + return arr; + } + + return []; } - ,loadXml: function (xmlDoc) + ,loadXml: function (path, dstDocument) { + var xmlDoc = Vn.getXml (path); + if (!xmlDoc) return false; + this._compileInit (dstDocument); + this._path = path; + var docElement = xmlDoc.documentElement; if (docElement.tagName !== 'vn') + { + this._showError ('Malformed XML'); + this._contexts = null; return false; + } - this.contexts = []; var childs = docElement.childNodes; if (childs) for (var i = 0; i < childs.length; i++) - this.loadNode (childs[i], null); + this._compileNode (childs[i]); - this.resolveProperties (); - delete this.contexts; + this._compileEnd (); return true; } - ,loadXmlFromNode: function (node) + ,loadXmlFromNode: function (node, dstDocument) { - this.contexts = []; - var mainNode = this.loadNode (node); - this.resolveProperties (); - delete this.contexts; - return mainNode; + this._compileInit (dstDocument); + this._mainContext = this._compileNode (node).id; + this._compileEnd (); } - ,add: function (id, object) + ,load: function () { - this.objectMap[id] = object; + if (this._contexts === null) + return null; + + var contexts = this._contexts; + var len = contexts.length; + var objects = new Array (len); + + for (var i = 0; i < len; i++) + { + var context = contexts[i]; + + if (context.tagName) + objects[i] = this.elementInstantiate (context); + else if (context.klass) + objects[i] = this.objectInstantiate (context); + else + objects[i] = this.textInstantiate (context); + } + + var res = new BuilderResult (this, objects); + + for (var i = this._links.length - 1; i >= 0; i--) + { + var l = this._links[i]; + var addedObject = this._addedMap[l.objectId]; + + if (addedObject) + if (l.prop) + objects[l.context.id][l.prop] = addedObject; + else + objects[l.context.id].appendChild (addedObject); + else + this._showError ('Referenced unexistent object with id \'%s\'', + l.objectId); + } + + for (var i = 0; i < len; i++) + { + var context = contexts[i]; + var object = objects[i]; + + if (context.tagName) + this.elementLink (context, object, objects, res); + else if (context.klass) + this.objectLink (context, object, objects, res); + } + + return res; + } + + ,_compileInit: function (dstDocument) + { + this._path = null; + this._tags = {}; + this._contexts = []; + this._contextMap = {}; + this._links = []; + this._mainContext = null; + this._document = dstDocument ? dstDocument : document; + } + + ,_compileEnd: function (node) + { + for (var i = this._links.length - 1; i >= 0; i--) + { + var l = this._links[i]; + var contextId = this._contextMap[l.objectId] + + if (contextId) + { + if (l.prop) + l.context.objectProps[l.prop] = contextId; + else + l.context.childs.push (contextId); + + this._links.splice (i, 1); + } + else if (this._parentResult) + { + var object = this._parentResult.getById (l.objectId); + + if (object) + pl.context.props[pl.prop] = object; + } + } } - ,loadNode: function (node) + ,_compileNode: function (node) { - var customNode; - var htmlNode = null; + var context = null; var tagName = null; - if (node.tagName) + if (node.nodeType === Node.ELEMENT_NODE) tagName = node.tagName.toLowerCase (); + else if (node.nodeType !== Node.TEXT_NODE + || /^[\n\r\t]*$/.test (node.textContent)) + return null; + + var context = + this.textCompile (node, tagName) + || this.objectCompile (node, tagName) + || this.elementCompile (node, tagName); + + context.id = this._contexts.length; + + if (tagName) + { + var nodeId = node.getAttribute ('id'); + + if (nodeId) + this._contextMap[nodeId] = context.id; + + var tags = this._tags[tagName]; - if (tagName === 't') - { - htmlNode = document.createTextNode (_(node.firstChild.textContent)); - } - else if (!tagName) - { - htmlNode = document.importNode (node, false); - } - else if ((customNode = this.loadCustomNode (node, tagName, 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); - } + if (!tags) + this._tags[tagName] = tags = []; + + tags.push (context.id); } - return htmlNode; + this._contexts.push (context); + return context; } - - ,loadCustomNode: function (node, tagName, parentContext) + + /** + * Creates a text node context. + **/ + ,textCompile: function (node, tagName) { if (!tagName) + var text = node.textContent; + else if (tagName === 't') + var text = _(node.firstChild.textContent); + else return null; + return {text: text}; + } + + ,textInstantiate: function (context) + { + return this._document.createTextNode (context.text); + } + + /** + * Creates a object context. + **/ + ,objectCompile: function (node, tagName) + { 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 props = {}; + var objectProps = {}; + var childs = []; + var events = {}; + var handler; + var context = { - node: node - ,parent: parentContext - ,object: customNode - ,klass: klass - ,custom: null + klass: klass, + props: props, + objectProps: objectProps, + childs: childs, + events: events, + custom: null }; - 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++) + + var a = node.attributes; + + for (var i = 0; i < a.length; i++) { - var childTagName = childs[i].tagName; - - if (!childTagName) - continue; + var attribute = a[i].nodeName; + var value = a[i].nodeValue; - childTagName = childTagName.toLowerCase (); - - var customChild = this.loadCustomNode ( - childs[i], childTagName, context); - - if (!customChild && childTagName === 'custom') - context.custom = childs[i]; - } - - return customNode; - } - - ,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.custom) - c.object.loadXml (this, c.custom); - - if (c.parent) + if (handler = this._getEventHandler (attribute, value)) { - var parentProperty = c.node.getAttribute ('property'); - - if (parentProperty) - this.setProperty (c.parent, parentProperty, c.object); - else - c.parent.object.appendChild (c.object); + events[attribute.substr (3)] = handler; + } + else if (!/^(id|property)$/.test (attribute)) + { + this.propCompile (context, klass, props, + node, attribute, value); } } - } - - ,setAttribute: function (c, attribute, value) - { - if (/^on-\w+/.test (attribute)) + + var childNodes = node.childNodes; + + if (childNodes) + for (var i = 0; i < childNodes.length; i++) { - var method = this.getMethod (value); + var child = childNodes[i]; - if (method) - c.object.on (attribute.substr (3), method, this.signalData); - } - else if (!/^(id|property)$/.test (attribute)) - { - this.setProperty (c, attribute, value) + if (child.nodeType !== Node.ELEMENT_NODE) + continue; + + var childContext; + var childTagName = child.tagName.toLowerCase (); + + if (childTagName === 'pointer') + { + this._addLink (context, null, child.getAttribute ('object')); + } + else if (childTagName === 'custom') + { + context.custom = child; + } + else if (childContext = this._compileNode (child)) + { + var prop = child.getAttribute ('property'); + + if (prop) + objectProps[prop] = childContext.id; + else + childs.push (childContext.id); + } } + + return context; } - ,setProperty: function (c, attribute, value) + ,propCompile: function (context, klass, props, node, attribute, value) { - var propName = attribute.replace (/-./g, this.replaceFunc); - var prop = c.klass.Properties[propName]; + var newValue = null; + var propName = attribute.replace (/-./g, this._replaceFunc); + var propInfo = klass.Properties[propName]; - if (!prop) + if (!propInfo) { - console.warn ('Vn.Builder: Attribute \'%s\' not valid for tag \'%s\'', - attribute, c.node.tagName); + this._showError ('Attribute \'%s\' not valid for tag \'%s\'', + attribute, 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]; + this._showError ('Attribute \'%s\' empty on tag \'%s\'', + attribute, node.tagName); + return; } - if (value !== undefined) - c.object[propName] = value; + switch (propInfo.type) + { + 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: + newValue = this._getMethod (value); + break; + default: + if (propInfo.enumType) + newValue = propInfo.enumType[value]; + break; + } + + if (newValue !== null && newValue !== undefined) + props[propName] = newValue; + else if (propInfo.type instanceof Function) + this._addLink (context, attribute, value); else - console.warn ('Vn.Builder: Empty attribute \'%s\' on tag \'%s\'', - attribute, c.node.tagName); + this._showError ('Attribute \'%s\' invalid for tag \'%s\'', + attribute, node.tagName); + } + + ,objectInstantiate: function (context) + { + return new context.klass (context.props); + } + + ,objectLink: function (context, object, objects, res) + { + 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]]); + + var events = context.events; + for (var event in events) + object.on (event, + events[event].bind (this.signalData)); + + if (context.custom) + object.loadXml (res, context.custom); + } + + /** + * Creates a HTML node context. + **/ + ,elementCompile: function (node, tagName) + { + var attributes = {}; + var childs = []; + var events = {}; + var handler; + + var a = node.attributes; + + for (var i = 0; i < a.length; i++) + { + var attribute = a[i].nodeName; + var value = a[i].nodeValue; + + if (handler = this._getEventHandler (attribute, value)) + events[attribute.substr (3)] = handler; + else if (attribute !== 'id') + attributes[attribute] = this._translateValue (value); + } + + var childContext; + var childNodes = node.childNodes; + + if (childNodes) + for (var i = 0; i < childNodes.length; i++) + if (childContext = this._compileNode (childNodes[i])) + childs.push (childContext.id); + + return { + tagName: tagName, + attributes: attributes, + childs: childs, + events: events + }; + } + + ,elementInstantiate: function (context) + { + return this._document.createElement (context.tagName); + } + + ,elementLink: function (context, object, objects) + { + var attributes = context.attributes; + for (var attribute in attributes) + object.setAttribute (attribute, attributes[attribute]); + + var childs = context.childs; + for (var i = 0; i < childs.length; i++) + { + var child = objects[childs[i]]; + + if (child instanceof Htk.Widget) + object.appendChild (child.getNode ()); + else if (child instanceof Node) + object.appendChild (child); + } + + var events = context.events; + for (var event in events) + object.addEventListener (event, + events[event].bind (this.signalData)); + } + + ,_showError: function (error) + { + var path = this._path ? this._path : 'Node'; + var logArgs = ['Vn.Builder: %s: '+ error, path]; + + for (var i = 1; i < arguments.length; i++) + logArgs.push (arguments[i]); + + console.warn.apply (null, logArgs); + } + + ,_addLink: function (context, prop, objectId) + { + this._links.push ({ + context: context + ,prop: prop + ,objectId: objectId + }); } -//+++++++++++++++++++++++++++++++++++++++++++ Utilities - - ,translateValue: function (value) + ,_translateValue: function (value) { var chr = value.charAt (0); - if (chr == '_') + if (chr === '_') return _(value.substr (1)); - else if (chr == '\\' && value.charAt (1) == '_') + else if (chr === '\\' && value.charAt (1) === '_') return value.substr (1); return value; } - ,getMethod: function (value) + ,_getMethod: function (value) { if (this.signalData) var methodName = 'this.signalData.'+ value; @@ -285,69 +502,64 @@ Vn.BuilderOld = new Class method = null; } - if (method == null) - console.warn ('Vn.Builder: Function \'%s\' not found', - value); + if (method === null) + this._showError ('Function \'%s\' not found', value); return method; } - ,getEventHandler: function (attribute, value) + ,_getEventHandler: function (attribute, value) { if (!(/^on-\w+/.test (attribute))) return null; - return this.getMethod (value); + return this._getMethod (value); } - ,replaceFunc: function (token) + ,_replaceFunc: function (token) { return token.charAt(1).toUpperCase (); } - - ,setParent: function (parentBuilder) +}); + +var BuilderResult = new Class +({ + Extends: Vn.Object + + ,initialize: function (builder, objects) { - this.parentBuilder = parentBuilder; - - if (parentBuilder) - this.signalData = parentBuilder.signalData; + this.builder = builder; + this.objects = objects; + } + + ,getMain: function () + { + return this.builder.getMain (this); } ,$: function (objectId) { - return this.getById (objectId); + return this.builder.getById (objectId, this); } - + ,getById: function (objectId) { - var object = this.objectMap[objectId]; - - if (object) - return object; - if (this.parentBuilder) - return this.parentBuilder.get (objectId); - - return null; + return this.builder.getById (objectId, this); } ,getByTagName: function (tagName) { - if (this.tags[tagName]) - return this.tags[tagName]; - - return []; + return this.builder.getByTagName (tagName, this); } ,_destroy: function () { - for (var tag in this.tags) - { - var objects = this.tags[tag]; + var objects = this.objects; + + for (var i = 0; i < objects.length; i++) + if (objects[i] instanceof Vn.Object) + objects[i].unref (); - for (var i = 0; i < objects.length; i++) - objects[i].unref (); - } - this.parent (); } }); diff --git a/web/js/vn/main.js b/web/js/vn/main.js index 9dcac47e..0a650f28 100644 --- a/web/js/vn/main.js +++ b/web/js/vn/main.js @@ -16,7 +16,6 @@ Vn.includeLib ('vn', ,'hash-param' ,'node' ,'builder' - ,'builder-new' ,'http-request' ]);