javascript - Recursive builder nesting issues -


i trying parse json / javascript object html... of it's working, can't figure out recursive build method (app.layout.form.documentdirector)...

it keeps on nesting (appending) elements when shouldn't. see example , code @ http://jsfiddle.net/blogshop/dsxft/6/

can me figure out? build method on line 408 (in fiddle -- scroll down documentdirector bit see here). thanks!


build method

build: function (obj, level) {         var = this,             builder = this.getbuilder(),             iterator = object.create(app.utilities.recursiveiterator(obj)),             level = level || 0,             prev = this._prevlevel || 0,             next = level,             key,             current,             attributes,             pair,             children,             hastype = false,             maxnesting = false;          {             // current node , build             key = iterator.key();             current = iterator.current();              console.log(iterator.key() + ": " + iterator.current().tosource());              if (current.hasownproperty('type') && current.type !== '') {                  if (current.hasownproperty('type') && current.type !== '') {                     //console.log(iterator.current().type);                      attributes = {};                      $.each(current, function(key, value) {                         if (that._validattributes.indexof(key) !== -1) {                             attributes[key] = value;                         }                     });                     //console.log(attributes);                 }                  //console.log("prev: " + prev);                 console.log("level: " + level);                  if (level == prev && level == 0) {                     builder.append(current.type, attributes);                 } else if (level == prev && level > 0) {                     builder.add(current.type, attributes);                                           } else if (level < prev && level > 0) {                     builder.parent().append(current.type, attributes);                 } else if (level > prev && level > 0) {                     builder.append(current.type, attributes);                 } else {                     // nothing                 }                  if (current.hasownproperty('label')) {                     var label = builder.addbefore(builder.getcurrent(), 'label');                     builder.text(current.label, label);                 }             }              // there child nodes? if so, recurse...             if (iterator.haschildren()) {                 children = iterator.getchildren();                  if (this.iscollection(key, current)) {                     //console.log("i container");                 }                   //console.log("i have children");                 console.log("-----------------------------");                  hastype = (current.hasownproperty('type') && current.type !== '') ? current.type : false;                  if (hastype) {                     maxnesting = (this.isvoid(current.type)) ? true : false;                 }                  if (maxnesting === false) {                     next = level;                      if (hastype) {                         this._prevlevel = level;                         next = level + 1;                     }                      this.build(children, next);                 }              } else {                 if (current.hasownproperty('type') && current.type !== '') {                     //console.log("i childless");                     console.log("-----------------------------");                 }             }             iterator.next();         } while (iterator.hasnext());          if (current && current.hasownproperty('type') && current.type !== '') {              if (iterator.hasnext() === false) {                 //console.log("<----- moving " + parseint(level - prev) + " levels ----->");                 //console.log("diff: " + parseint(level - prev));                 //console.log("level: " + level);                 //console.log("prev: " + prev);                  builder.parent();                 this._prevlevel = level - prev;             }         }     }, 

additional info

documentdirector: function (builder) {     var director = object.create({         _builder: {},         _validcollection: ['sections', 'forms', 'fieldsets', 'rows', 'fields'],         _validattributes: ['id', 'name'],         _voidelements: ['base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'img', 'input', 'link', 'meta', 'param', 'source'],         _inputelements: ['text', 'select', 'radio', 'checkbox', 'textarea', 'datepicker', 'yesno'],         _prevlevel: 0,          init: function (builder) {             builder = builder || '';             if (builder) this.setbuilder(builder);              return this;         },         setbuilder: function (builder) {             this._builder = builder;              return this;         },         getbuilder: function () {             return this._builder;         },         iscollection: function (key, node) {             // collections must have key, don't have type             key = key || '';             if (key === '') return false;              return (node.constructor === array && this._validcollection.indexof(key) !== -1) ? true : false;         },         isvoid: function (type) {             var isvoidelement = false;              if (this._voidelements.indexof(type.tostring()) !== -1) {                 isvoidelement = true;             }              if (this._inputelements.indexof(type.tostring()) !== -1) {                 isvoidelement = true;             }              return isvoidelement;         },         build: function (obj, level) {             var = this,                 builder = this.getbuilder(),                 iterator = object.create(app.utilities.recursiveiterator(obj)),                 level = level || 0,                 prev = this._prevlevel || 0,                 next = level,                 key,                 current,                 attributes,                 pair,                 children,                 hastype = false,                 maxnesting = false;              {                 // current node , build                 key = iterator.key();                 current = iterator.current();                  console.log(iterator.key() + ": " + iterator.current().tosource());                  if (current.hasownproperty('type') && current.type !== '') {                      if (current.hasownproperty('type') && current.type !== '') {                         //console.log(iterator.current().type);                          attributes = {};                          $.each(current, function(key, value) {                             if (that._validattributes.indexof(key) !== -1) {                                 attributes[key] = value;                             }                         });                         //console.log(attributes);                     }                      //console.log("prev: " + prev);                     console.log("level: " + level);                      if (level == prev && level == 0) {                         builder.append(current.type, attributes);                     } else if (level == prev && level > 0) {                         builder.add(current.type, attributes);                                               } else if (level < prev && level > 0) {                         builder.parent().append(current.type, attributes);                     } else if (level > prev && level > 0) {                         builder.append(current.type, attributes);                     } else {                         // nothing                     }                      if (current.hasownproperty('label')) {                         var label = builder.addbefore(builder.getcurrent(), 'label');                         builder.text(current.label, label);                     }                 }                  // there child nodes? if so, recurse...                 if (iterator.haschildren()) {                     children = iterator.getchildren();                      if (this.iscollection(key, current)) {                         //console.log("i container");                     }                       //console.log("i have children");                     console.log("-----------------------------");                      hastype = (current.hasownproperty('type') && current.type !== '') ? current.type : false;                      if (hastype) {                         maxnesting = (this.isvoid(current.type)) ? true : false;                     }                      if (maxnesting === false) {                         next = level;                          if (hastype) {                             this._prevlevel = level;                             next = level + 1;                         }                          this.build(children, next);                     }                  } else {                     if (current.hasownproperty('type') && current.type !== '') {                         //console.log("i childless");                         console.log("-----------------------------");                     }                 }                 iterator.next();             } while (iterator.hasnext());              if (current && current.hasownproperty('type') && current.type !== '') {                  if (iterator.hasnext() === false) {                     //console.log("<----- moving " + parseint(level - prev) + " levels ----->");                     //console.log("diff: " + parseint(level - prev));                     //console.log("level: " + level);                     //console.log("prev: " + prev);                      builder.parent();                     this._prevlevel = level - prev;                 }             }         },         getdocument: function () {             return this.getbuilder().getdocument();         }     });      return director.init(builder); } 

dombuilder (injected documentdirector -- handles dom manipulation):

dombuilder: function () {     var dombuilder = object.create({         _document: {},         _rootnode: {},         _currentnode: {},          init: function (viewmodel, dombuilder) {             var doc, rootnode;              this._document = doc = document.createdocumentfragment();             this._rootnode = rootnode = this.appendnode(doc, 'section');             this._currentnode = rootnode;              return this;         },          /* generic methods         ------------------ */          /**          *  returns document          *          *  @return dom node: dom document fragment          */         getdocument: function () {             return this._document;         },         /**          *  returns root node          *          *  @return dom node: root node          */         getroot: function () {             return this._rootnode;         },         /**          *  returns current node          *          *  @return dom node: current node          */         getcurrent: function () {             return this._currentnode;         },         /**          *  sets current node          *          *  @return dom node: current node          */         setcurrent: function (node) {             this._currentnode = node;              return this;         },         /**          *  returns parent of current node          *          *  @return dom node: parent node          */         getparent: function () {             return this._currentnode.parentnode;         },         /**          *  creates , appends node inside specified parent          *            *  @ref dom node: insertion target new node          *  @type string: valid html5 element type          *  @attributes object: , object containing key-value pairs of attributes , values          *          *  @return dom node: newly created node          */         appendnode: function (ref, type, attributes) {             var node = document.createelement(type);             ref.appendchild(node);             //this._currentnode = node;              return node;         },         /**          *  creates node , inserts before specified element          *            *  @ref dom node: reference node inserting new node          *  @type string: valid html5 element type          *  @attributes object: , object containing key-value pairs of attributes , values          *          *  @return dom node: newly created node          */         addbefore: function (ref, type, attributes) {             var node = document.createelement(type);             ref.parentnode.insertbefore(node, ref);             //this._currentnode = node;              return node;         },         /**          *  creates node , inserts after specified element          *            *  @parent dom node: reference node inserting new node          *  @type string: valid html5 element type          *  @attributes object: , object containing key-value pairs of attributes , values          *          *  @return dom node: newly created node          */         addafter: function (ref, type, attributes) {             var node = document.createelement(type);             ref.parentnode.insertbefore(node, ref.nextsibling);             //this._currentnode = node;              return node;         },          /* chainable methods         ---------------------- */          /**          *  creates , appends node inside specified parent          *            *  @type string: valid html5 element type          *  @attributes object: , object containing key-value pairs of attributes , values          *  @ref dom node: (optional) insertion target new node          *          *  @return dombuilder:          */         append: function (type, attributes, ref) {             var parent, node;              ref = ref || this._currentnode;             node = document.createelement(type);             ref.appendchild(node);             this._currentnode = node;              if (attributes) {                 // todo: use map instead                 $.each(attributes, function (key, value) {                     node.setattribute(key, value);                 });             }              return this;         },         /**          *  creates node , inserts after specified element          *            *  @type string: valid html5 element type          *  @attributes object: , object containing key-value pairs of attributes , values          *  @ref dom node: reference node inserting new node          *          *  @return dombuilder:          */         add: function (type, attributes, ref) {             var ref, node;              ref = ref || this._currentnode;             node = document.createelement(type);             //console.log(ref);             ref.parentnode.insertbefore(node, ref.nextsibling);             this._currentnode = node;              if (attributes) {                 // todo: use map instead                 $.each(attributes, function (key, value) {                     node.setattribute(key, value);                 });             }              return this;         },         /**          *  creates node , inserts before specified element          *            *  @type string: valid html5 element type          *  @attributes object: , object containing key-value pairs of attributes , values          *  @ref dom node: reference node inserting new node          *          *  @return dombuilder:          */         before: function (type, attributes, ref) {             var ref, node;              ref = ref || this._currentnode;             node = document.createelement(type);             ref.parentnode.insertbefore(node, ref);             this._currentnode = node;              if (attributes) {                 // todo: use map instead                 $.each(attributes, function (key, value) {                     node.setattribute(key, value);                 });             }              return this;         },         /**          *  sets internal current node reference parent of current node          *          *  @return dombuilder:          */         parent: function () {             var ref, node;              ref = ref || this._currentnode;             this._currentnode = this._currentnode.parentnode;              return this;         },         /**          *  sets text specified node          *          *  @return dombuilder:          */         text: function (value, ref) {             var node = document.createtextnode(value);             ref.appendchild(node);              return this;         }     });      return dombuilder.init(); } 

bootstrap:

var formlayout = [         {             type: 'section',             id: 'header',         },         {             type: 'div',             id: 'center-pane',             forms: [                 {                     type: 'section',                     id: 'claim-history',                     label: 'add claim history',                     templates: [                         {                             fieldsets: [                                 {                                     type: 'fieldset',                                     id: 'claim-history-details',                                     label: 'details',                                     rows: [                                         {                                             type: 'div',                                             fields: [                                                 {                                                     // standard html5 attributes can defined                                                     id: 'maincontent_detailscontent_lossdate',                                                     name: 'lossdate',                                                     label: 'date of loss',                                                     type: 'datepicker', // types: standard html5 form element or kendo ui widget                                                     classname: 'small',                                                     data: {                                                         role: 'datepicker', // redundant proxy type parameter                                                         bind: {                                                             value: 'datepickervalue' // bind kendo ui datepicker                                                         }                                                     }                                                 }                                             ]                                         },                                         {                                             type: 'div',                                             fields: [                                                 {                                                     // standard html5 attributes can defined                                                     id: 'maincontent_detailscontent_typeofloss',                                                     name: 'typeofloss',                                                     label: 'type of loss',                                                     type: 'select', // combobox,                                                     classname: ''                                                 }                                             ]                                         },                                         {                                             type: 'div',                                             fields: [                                                 {                                                     // standard html5 attributes can defined                                                     id: 'maincontent_detailscontent_atfaultpercentage',                                                     name: 'atfaultpercentage',                                                     label: 'at fault %',                                                     type: 'text',                                                     classname: 'tiny'                                                 },                                                 {                                                     // standard html5 attributes can defined                                                     id: 'maincontent_detailscontent_causeofloss',                                                     name: 'causeofloss',                                                     label: 'cause of loss',                                                     type: 'select',                                                     classname: ''                                                 }                                             ]                                         },                                         {                                             type: 'div',                                             fields: [                                                 {                                                     // standard html5 attributes can defined                                                     id: '',                                                     name: '',                                                     label: 'charges laid',                                                     type: 'yesno',                                                     classname: '',                                                     data: {                                                         bind: {                                                             source: 'yesno',                                                             value: 'datepickervalue' // bind kendo ui datepicker                                                         }                                                     }                                                 },                                                 {                                                     // standard html5 attributes can defined                                                     id: 'maincontent_detailscontent_chargeslaid',                                                     name: 'chargeslaid',                                                     label: 'details',                                                     type: 'textarea',                                                     classname: 'tiny'                                                 }                                             ]                                         }                                     ],                                 },                                 {                                     type: 'fieldset',                                     id: 'claim-history-amounts',                                     label: 'amounts',                                     rows: [                                         {                                             type: 'div',                                             fields: [                                                 {                                                     // standard html5 attributes can defined                                                     id: 'maincontent_detailscontent_seca',                                                     name: 'seca',                                                     label: 'sec a',                                                     type: 'yesno',                                                     classname: 'tiny'                                                 },                                                 {                                                     // standard html5 attributes can defined                                                     id: 'maincontent_detailscontent_secatotal',                                                     name: 'secatotal',                                                     label: 'sec total',                                                     type: 'text',                                                     classname: 'small'                                                 }                                             ]                                         },                                         {                                             type: 'div',                                             fields: [                                                 {                                                     // standard html5 attributes can defined                                                     id: 'maincontent_detailscontent_secc',                                                     name: 'secc',                                                     label: 'sec c',                                                     type: 'text',                                                     classname: 'tiny'                                                 },                                             ]                                         },                                         {                                             type: 'div',                                             fields: [                                                 {                                                     // standard html5 attributes can defined                                                     id: 'maincontent_detailscontent_ignorereason',                                                     name: 'ignorereason',                                                     label: 'ignore reason',                                                     type: 'select',                                                     classname: ''                                                 }                                             ]                                         }                                     ],                                 },                                 {                                     type: 'fieldset',                                     id: 'claim-history-vehicle-driver',                                     label: 'vehicle , driver',                                     rows: [                                         {                                             type: 'div',                                             fields: [                                                 {                                                     // standard html5 attributes can defined                                                     id: 'maincontent_detailscontent_claimvehicle',                                                     name: 'claimvehicle',                                                     label: 'claim vehicle',                                                     type: 'select',                                                     classname: ''                                                 }                                             ]                                         }                                     ],                                 } // end fieldset                             ] // end fieldsets                           } // end template                     ] // end templates                 } // end form             ] // end forms         },         {             type: 'div',             id: 'left-pane'         },         {             type: 'div',             id: 'right-pane'         }     ]; // end sections var formbuilder = object.create(app.layout.form.dombuilder()); var formdirector = object.create(app.layout.form.documentdirector(formbuilder)); formdirector.build(formlayout); document.getelementbyid("test").appendchild(formdirector.getdocument()); 

solved -- each successive recurse, should have been appending first child node (of object passed in), , adding remaining nodes. added isfirst variable keep track.

working fiddle if anyone's interested... http://jsfiddle.net/blogshop/dsxft/

build: function (obj, level) {             var = this,                 builder = this.getbuilder(),                 iterator = object.create(app.utilities.recursiveiterator(obj)),                 level,                 key,                 current,                 attributes,                 pair,                 children,                 isfirst = true,                 hastype = false,                 maxnesting = false;              {                 // current node , build                 key = iterator.key();                 current = iterator.current();                  hastype = (current.hasownproperty('type') && current.type !== '') ? current.type : false;                  if (hastype) {                     maxnesting = (this.isvoid(current.type)) ? true : false;                      attributes = {};                      $.each(current, function(key, value) {                         if (that._validattributes.indexof(key) !== -1) {                             attributes[key] = value;                         }                     });                      if (isfirst == true) {                         builder.append(current.type, attributes);                         isfirst = false;                     } else {                         builder.add(current.type, attributes)                     }                      // prepend label field                     if (current.hasownproperty('label')) {                         var label = builder.addbefore(builder.getcurrent(), 'label');                         builder.text(current.label, label);                     }                 }                  // there child nodes? if so, recurse...                 if (iterator.haschildren()) {                     children = iterator.getchildren();                      if (maxnesting === false) {                                              // recurse                         level = (hastype) ? level + 1 : level;                         this.build(children, level);                     }                 }                  // move next node                 iterator.next();             } while (iterator.hasnext());              if (current && current.hasownproperty('type') && current.type !== '') {                 if (iterator.hasnext() === false) builder.parent();             }         }, 

Comments

Popular posts from this blog

python - How to create a legend for 3D bar in matplotlib? -

java - Multi-Label Document Classification -

php - Dynamic url re-writing using htaccess -