Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

aui-tree-data.js 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. AUI.add('aui-tree-data', function(A) {
  2. /**
  3. * The TreeData Utility
  4. *
  5. * @module aui-tree
  6. * @submodule aui-tree-data
  7. */
  8. var L = A.Lang,
  9. isArray = L.isArray,
  10. isBoolean = L.isBoolean,
  11. isObject = L.isObject,
  12. isUndefined = L.isUndefined,
  13. BOUNDING_BOX = 'boundingBox',
  14. CHILDREN = 'children',
  15. CONTAINER = 'container',
  16. DOT = '.',
  17. ID = 'id',
  18. INDEX = 'index',
  19. LAZY_LOAD = 'lazyLoad',
  20. LEAF = 'leaf',
  21. NEXT_SIBLING = 'nextSibling',
  22. NODE = 'node',
  23. OWNER_TREE = 'ownerTree',
  24. PARENT_NODE = 'parentNode',
  25. PREV_SIBLING = 'prevSibling',
  26. PREVIOUS_SIBLING = 'previousSibling',
  27. TREE = 'tree',
  28. TREE_NODE = 'tree-node',
  29. TREE_DATA = 'tree-data',
  30. isTreeNode = function(v) {
  31. return ( A.instanceOf(v, A.TreeNode) );
  32. },
  33. isTreeView = function(v) {
  34. return ( A.instanceOf(v, A.TreeView) );
  35. },
  36. getCN = A.getClassName,
  37. CSS_TREE_NODE = getCN(TREE, NODE);
  38. /**
  39. * A base class for TreeData, providing:
  40. * <ul>
  41. * <li>Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li>
  42. * <li>Handle the data of the tree</li>
  43. * <li>Basic DOM implementation (append/remove/insert)</li>
  44. * <li>Indexing management to handle the children nodes</li>
  45. * </ul>
  46. *
  47. * Check the list of <a href="TreeData.html#configattributes">Configuration Attributes</a> available for
  48. * TreeData.
  49. *
  50. * @param config {Object} Object literal specifying widget configuration properties.
  51. *
  52. * @class TreeData
  53. * @constructor
  54. * @extends Base
  55. */
  56. var TreeData = function () {};
  57. TreeData.ATTRS = {
  58. /**
  59. * Container to nest children nodes. If has cntainer it's not a leaf.
  60. *
  61. * @attribute container
  62. * @default null
  63. * @type Node | String
  64. */
  65. container: {
  66. setter: A.one
  67. },
  68. /**
  69. * Array of children (i.e. could be a JSON metadata object or a TreeNode instance).
  70. *
  71. * @attribute children
  72. * @default []
  73. * @type Array
  74. */
  75. children: {
  76. value: [],
  77. validator: isArray,
  78. setter: '_setChildren'
  79. },
  80. /**
  81. * Index the nodes.
  82. *
  83. * @attribute index
  84. * @default {}
  85. * @type Object
  86. */
  87. index: {
  88. value: {}
  89. }
  90. };
  91. A.mix(TreeData.prototype, {
  92. _indexPrimed: false,
  93. childrenLength: 0,
  94. /**
  95. * Construction logic executed during TreeData instantiation. Lifecycle.
  96. *
  97. * @method initializer
  98. * @protected
  99. */
  100. initTreeData: function() {
  101. var instance = this;
  102. // binding on initializer, needed before .render() phase
  103. instance.publish('move');
  104. instance.publish('append', { defaultFn: instance._appendChild });
  105. instance.publish('remove', { defaultFn: instance._removeChild });
  106. },
  107. /**
  108. * Descructor lifecycle implementation for the TreeData class.
  109. * Purges events attached to the node (and all child nodes).
  110. *
  111. * @method destructor
  112. * @protected
  113. */
  114. destructor: function() {
  115. var instance = this;
  116. instance.eachChildren(function(node) {
  117. node.destroy();
  118. }, true);
  119. },
  120. /**
  121. * Get a TreeNode by id.
  122. *
  123. * @method getNodeById
  124. * @param {String} uid
  125. * @return {TreeNode}
  126. */
  127. getNodeById: function(uid) {
  128. var instance = this;
  129. if (!instance._indexPrimed) {
  130. instance.refreshIndex();
  131. }
  132. return instance.get(INDEX)[uid];
  133. },
  134. /**
  135. * Whether the TreeNode is registered on this TreeData.
  136. *
  137. * @method isRegistered
  138. * @param {TreeNode} node
  139. * @return {boolean}
  140. */
  141. isRegistered: function(node) {
  142. var instance = this;
  143. return !!(instance.get(INDEX)[ node.get(ID) ]);
  144. },
  145. /**
  146. * Update the references of the passed TreeNode.
  147. *
  148. * @method updateReferences
  149. * @param {node} TreeNode
  150. * @param {parentNode} TreeNode
  151. * @param {ownerTree} TreeView
  152. */
  153. updateReferences: function(node, parentNode, ownerTree) {
  154. var instance = this;
  155. var oldParent = node.get(PARENT_NODE);
  156. var oldOwnerTree = node.get(OWNER_TREE);
  157. var moved = oldParent && (oldParent !== parentNode);
  158. if (oldParent) {
  159. if (moved) {
  160. // when moved update the oldParent children
  161. var children = oldParent.get(CHILDREN);
  162. A.Array.removeItem(children, node);
  163. oldParent.set(CHILDREN, children);
  164. }
  165. oldParent.unregisterNode(node);
  166. }
  167. if (oldOwnerTree) {
  168. oldOwnerTree.unregisterNode(node);
  169. }
  170. // update parent reference when registered
  171. node.set(PARENT_NODE, parentNode);
  172. // update the ownerTree of the node
  173. node.set(OWNER_TREE, ownerTree);
  174. if (parentNode) {
  175. // register the new node on the parentNode index
  176. parentNode.registerNode(node);
  177. }
  178. if (ownerTree) {
  179. // register the new node to the ownerTree index
  180. ownerTree.registerNode(node);
  181. }
  182. if (oldOwnerTree != ownerTree) {
  183. // when change the OWNER_TREE update the children references also
  184. node.eachChildren(function(child) {
  185. instance.updateReferences(child, child.get(PARENT_NODE), ownerTree);
  186. });
  187. }
  188. // trigger move event
  189. if (moved) {
  190. var output = instance.getEventOutputMap(node);
  191. if (!oldParent.get(CHILDREN).length) {
  192. oldParent.collapse();
  193. oldParent.hideHitArea();
  194. }
  195. output.tree.oldParent = oldParent;
  196. output.tree.oldOwnerTree = oldOwnerTree;
  197. instance.bubbleEvent('move', output);
  198. }
  199. },
  200. /**
  201. * Refresh the index (i.e. re-index all nodes).
  202. *
  203. * @method refreshIndex
  204. */
  205. refreshIndex: function() {
  206. var instance = this;
  207. // reset index
  208. instance.updateIndex({});
  209. // get all descendent children - deep
  210. instance.eachChildren(function(node) {
  211. instance.registerNode(node);
  212. }, true);
  213. },
  214. /**
  215. * Register the passed TreeNode on this TreeData.
  216. *
  217. * @method registerNode
  218. * @param {TreeNode} node
  219. */
  220. registerNode: function(node) {
  221. var instance = this;
  222. var uid = node.get(ID);
  223. var index = instance.get(INDEX);
  224. if (uid) {
  225. index[uid] = node;
  226. }
  227. if (isTreeView(instance)) {
  228. node.addTarget(instance);
  229. // when the node is appended to the TreeView set the OWNER_TREE
  230. node.set(OWNER_TREE, instance);
  231. }
  232. node._inheritOwnerTreeAttrs();
  233. instance.updateIndex(index);
  234. },
  235. /**
  236. * Update the <a href="TreeData.html#config_index">index</a> attribute value.
  237. *
  238. * @method updateIndex
  239. * @param {Object} index
  240. */
  241. updateIndex: function(index) {
  242. var instance = this;
  243. if (index) {
  244. instance._indexPrimed = true;
  245. instance.set(INDEX, index);
  246. }
  247. },
  248. /**
  249. * Unregister the passed TreeNode from this TreeData.
  250. *
  251. * @method unregisterNode
  252. * @param {TreeNode} node
  253. */
  254. unregisterNode: function(node) {
  255. var instance = this;
  256. var index = instance.get(INDEX);
  257. delete index[ node.get(ID) ];
  258. if (isTreeView(instance)) {
  259. node.removeTarget(instance);
  260. }
  261. instance.updateIndex(index);
  262. },
  263. /**
  264. * Collapse all children of the TreeData.
  265. *
  266. * @method collapseAll
  267. */
  268. collapseAll: function() {
  269. var instance = this;
  270. instance.eachChildren(function(node) {
  271. node.collapse();
  272. }, true);
  273. },
  274. /**
  275. * Expand all children of the TreeData.
  276. *
  277. * @method expandAll
  278. */
  279. expandAll: function() {
  280. var instance = this;
  281. instance.eachChildren(function(node) {
  282. node.expand();
  283. }, true);
  284. },
  285. /**
  286. * Select all children of the TreeData.
  287. *
  288. * @method selectAll
  289. */
  290. selectAll: function() {
  291. var instance = this;
  292. instance.eachChildren(function(child) {
  293. child.select();
  294. }, true);
  295. },
  296. /**
  297. * Unselect all children of the TreeData.
  298. *
  299. * @method unselectAll
  300. */
  301. unselectAll: function() {
  302. var instance = this;
  303. instance.eachChildren(function(child) {
  304. child.unselect();
  305. }, true);
  306. },
  307. /**
  308. * Loop each children and execute the <code>fn</code> callback.
  309. *
  310. * @method eachChildren
  311. * @param {function} fn callback
  312. * @param {boolean} fn recursive
  313. */
  314. eachChildren: function(fn, deep) {
  315. var instance = this;
  316. var children = instance.getChildren(deep);
  317. A.Array.each(children, function(node) {
  318. if (node) {
  319. fn.apply(instance, arguments);
  320. }
  321. });
  322. },
  323. /**
  324. * Loop each parent node and execute the <code>fn</code> callback.
  325. *
  326. * @method eachParent
  327. * @param {function} fn callback
  328. */
  329. eachParent: function(fn) {
  330. var instance = this;
  331. var parentNode = instance.get(PARENT_NODE);
  332. while (parentNode) {
  333. if (parentNode) {
  334. fn.call(instance, parentNode);
  335. }
  336. parentNode = parentNode.get(PARENT_NODE);
  337. }
  338. },
  339. /**
  340. * Bubble event to all parent nodes.
  341. *
  342. * @method bubbleEvent
  343. * @param {String} eventType
  344. * @param {Array} args
  345. * @param {boolean} cancelBubbling
  346. * @param {boolean} stopActionPropagation
  347. */
  348. bubbleEvent: function(eventType, args, cancelBubbling, stopActionPropagation) {
  349. var instance = this;
  350. // event.stopActionPropagation === undefined, invoke the event native action
  351. instance.fire(eventType, args);
  352. if (!cancelBubbling) {
  353. var parentNode = instance.get(PARENT_NODE);
  354. // Avoid execution of the native action (private methods) while propagate
  355. // for example: private _appendChild() is invoked only on the first level of the bubbling
  356. // the intention is only invoke the user callback on parent nodes.
  357. args = args || {};
  358. if (isUndefined(stopActionPropagation)) {
  359. stopActionPropagation = true;
  360. }
  361. args.stopActionPropagation = stopActionPropagation;
  362. while(parentNode) {
  363. parentNode.fire(eventType, args);
  364. parentNode = parentNode.get(PARENT_NODE);
  365. }
  366. }
  367. },
  368. /**
  369. * Create a TreeNode instance.
  370. *
  371. * @method createNode
  372. * @param {Object} options
  373. * @return {TreeNode}
  374. */
  375. createNode: function(options) {
  376. var instance = this;
  377. var classType = A.TreeNode.nodeTypes[ isObject(options) ? options.type : options ] || A.TreeNode;
  378. return new classType(
  379. isObject(options) ? options : {}
  380. );
  381. },
  382. /**
  383. * Append a child node to the TreeData.
  384. *
  385. * @method appendChild
  386. * @param {TreeNode} node
  387. * @param {boolean} cancelBubbling
  388. */
  389. appendChild: function(node, cancelBubbling) {
  390. var instance = this;
  391. var output = instance.getEventOutputMap(node);
  392. instance.bubbleEvent('append', output, cancelBubbling);
  393. },
  394. /**
  395. * Append a child node to the TreeData.
  396. *
  397. * @method _appendChild
  398. * @param {TreeNode} node
  399. * @param {boolean} cancelBubbling
  400. * @protected
  401. */
  402. _appendChild: function(event) {
  403. // stopActionPropagation while bubbling
  404. if (event.stopActionPropagation) {
  405. return false;
  406. }
  407. var instance = this;
  408. var node = event.tree.node;
  409. var ownerTree = instance.get(OWNER_TREE);
  410. var children = instance.get(CHILDREN);
  411. // updateReferences first
  412. instance.updateReferences(node, instance, ownerTree);
  413. // and then set the children, to have the appendChild propagation
  414. // the PARENT_NODE references should be updated
  415. var length = children.push(node);
  416. instance.childrenLength = children.length;
  417. // updating prev/nextSibling attributes
  418. var prevIndex = length - 2;
  419. var prevSibling = instance.item(prevIndex);
  420. node._nextSibling = null;
  421. node._prevSibling = prevSibling;
  422. // render node
  423. node.render(instance.get(CONTAINER));
  424. },
  425. /**
  426. * Get a TreeNode children by index.
  427. *
  428. * @method item
  429. * @param {Number} index
  430. * @return {TreeNode}
  431. */
  432. item: function(index) {
  433. var instance = this;
  434. return instance.get(CHILDREN)[index];
  435. },
  436. /**
  437. * Index of the passed TreeNode on the <a
  438. * href="TreeData.html#config_children">children</a> attribute.
  439. *
  440. * @method indexOf
  441. * @param {TreeNode} node
  442. * @return {Number}
  443. */
  444. indexOf: function(node) {
  445. var instance = this;
  446. return A.Array.indexOf( instance.get(CHILDREN), node );
  447. },
  448. /**
  449. * Whether the TreeData contains children or not.
  450. *
  451. * @method hasChildNodes
  452. * @return {boolean}
  453. */
  454. hasChildNodes: function() {
  455. var instance = this;
  456. return (instance.getChildrenLength() > 0);
  457. },
  458. /**
  459. * Get an Array of the children nodes of the current TreeData.
  460. *
  461. * @method getChildren
  462. * @param {boolean} deep
  463. * @return {Array}
  464. */
  465. getChildren: function(deep) {
  466. var instance = this;
  467. var cNodes = [];
  468. var children = instance.get(CHILDREN);
  469. cNodes = cNodes.concat(children);
  470. if (deep) {
  471. instance.eachChildren(function(child) {
  472. cNodes = cNodes.concat( child.getChildren(deep) );
  473. });
  474. }
  475. return cNodes;
  476. },
  477. getChildrenLength: function() {
  478. var instance = this;
  479. return (instance.childrenLength || instance.get(CHILDREN).length);
  480. },
  481. /**
  482. * Get an object containing metadata for the custom events.
  483. *
  484. * @method getEventOutputMap
  485. * @param {TreeData} node
  486. * @return {Object}
  487. */
  488. getEventOutputMap: function(node) {
  489. var instance = this;
  490. return {
  491. tree: {
  492. instance: instance,
  493. node: node || instance
  494. }
  495. };
  496. },
  497. /**
  498. * Remove the passed <code>node</code> from the current TreeData.
  499. *
  500. * @method removeChild
  501. * @param {TreeData} node
  502. */
  503. removeChild: function(node) {
  504. var instance = this;
  505. var output = instance.getEventOutputMap(node);
  506. instance.bubbleEvent('remove', output);
  507. },
  508. /**
  509. * Remove the passed <code>node</code> from the current TreeData.
  510. *
  511. * @method _removeChild
  512. * @param {TreeData} node
  513. */
  514. _removeChild: function(event) {
  515. // stopActionPropagation while bubbling
  516. if (event.stopActionPropagation) {
  517. return false;
  518. }
  519. var instance = this;
  520. var node = event.tree.node;
  521. var ownerTree = instance.get(OWNER_TREE);
  522. if (instance.isRegistered(node)) {
  523. // update parent reference when removed
  524. node.set(PARENT_NODE, null);
  525. // unregister the node
  526. instance.unregisterNode(node);
  527. // no parent, no ownerTree
  528. node.set(OWNER_TREE, null);
  529. if (ownerTree) {
  530. // unregister the removed node from the tree index
  531. ownerTree.unregisterNode(node);
  532. }
  533. // remove child from the container
  534. node.get(BOUNDING_BOX).remove();
  535. var children = instance.get(CHILDREN);
  536. A.Array.removeItem(children, node);
  537. instance.set(CHILDREN, children);
  538. }
  539. },
  540. /**
  541. * Delete all children of the current TreeData.
  542. *
  543. * @method empty
  544. */
  545. empty: function() {
  546. var instance = this;
  547. instance.eachChildren(function(node) {
  548. var parentNode = node.get(PARENT_NODE);
  549. if (parentNode) {
  550. parentNode.removeChild(node);
  551. }
  552. });
  553. },
  554. /**
  555. * Insert <code>treeNode</code> before or after the <code>refTreeNode</code>.
  556. *
  557. * @method insert
  558. * @param {TreeNode} treeNode
  559. * @param {TreeNode} refTreeNode
  560. * @param {TreeNode} where 'before' or 'after'
  561. */
  562. insert: function(treeNode, refTreeNode, where) {
  563. var instance = this;
  564. refTreeNode = refTreeNode || this;
  565. if (refTreeNode === treeNode) {
  566. return false; // NOTE: return
  567. }
  568. var refParentTreeNode = refTreeNode.get(PARENT_NODE);
  569. if (treeNode && refParentTreeNode) {
  570. var nodeBoundingBox = treeNode.get(BOUNDING_BOX);
  571. var refBoundingBox = refTreeNode.get(BOUNDING_BOX);
  572. var ownerTree = refTreeNode.get(OWNER_TREE);
  573. if (where === 'before') {
  574. refBoundingBox.placeBefore(nodeBoundingBox);
  575. }
  576. else if (where === 'after') {
  577. refBoundingBox.placeAfter(nodeBoundingBox);
  578. }
  579. var refSiblings = [];
  580. // using the YUI selector to regenerate the index based on the real dom
  581. // this avoid misscalculations on the nodes index number
  582. var DOMChildren = refParentTreeNode.get(BOUNDING_BOX).all('> ul > li');
  583. DOMChildren.each(function(child) {
  584. refSiblings.push( child.getData(TREE_NODE) );
  585. });
  586. // updating prev/nextSibling attributes
  587. var nextSiblingNode = nodeBoundingBox.get(NEXT_SIBLING);
  588. treeNode.set(NEXT_SIBLING, nextSiblingNode && nextSiblingNode.getData(TREE_NODE));
  589. var prevSiblingNode = nodeBoundingBox.get(PREVIOUS_SIBLING);
  590. treeNode.set(PREV_SIBLING, prevSiblingNode && prevSiblingNode.getData(TREE_NODE));
  591. // update all references
  592. refTreeNode.updateReferences(treeNode, refParentTreeNode, ownerTree);
  593. // updating refParentTreeNode childTreeNodes
  594. refParentTreeNode.set(CHILDREN, refSiblings);
  595. }
  596. // render treeNode after it's inserted
  597. treeNode.render();
  598. // invoking insert event
  599. var output = refTreeNode.getEventOutputMap(treeNode);
  600. output.tree.refTreeNode = refTreeNode;
  601. refTreeNode.bubbleEvent('insert', output);
  602. },
  603. /**
  604. * Insert <code>treeNode</code> after the <code>refTreeNode</code>.
  605. *
  606. * @method insertAfter
  607. * @param {TreeNode} treeNode
  608. * @param {TreeNode} refTreeNode
  609. */
  610. insertAfter: function(treeNode, refTreeNode) {
  611. var instance = this;
  612. instance.insert(treeNode, refTreeNode, 'after');
  613. },
  614. /**
  615. * Insert <code>treeNode</code> before the <code>refTreeNode</code>.
  616. *
  617. * @method insertBefore
  618. * @param {TreeNode} treeNode
  619. * @param {TreeNode} refTreeNode
  620. */
  621. insertBefore: function(treeNode, refTreeNode) {
  622. var instance = this;
  623. instance.insert(treeNode, refTreeNode, 'before');
  624. },
  625. /**
  626. * Get a TreeNode instance by a child DOM Node.
  627. *
  628. * @method getNodeByChild
  629. * @param {Node} child
  630. * @return {TreeNode}
  631. */
  632. getNodeByChild: function(child) {
  633. var instance = this;
  634. var treeNodeEl = child.ancestor(DOT+CSS_TREE_NODE);
  635. if (treeNodeEl) {
  636. return treeNodeEl.getData(TREE_NODE);
  637. }
  638. return null;
  639. },
  640. _inheritOwnerTreeAttrs: L.emptyFn,
  641. /**
  642. * Setter for <a href="TreeData.html#config_children">children</a>.
  643. *
  644. * @method _setChildren
  645. * @protected
  646. * @param {Array} v
  647. * @return {Array}
  648. */
  649. _setChildren: function(v) {
  650. var instance = this;
  651. var childNodes = [];
  652. var container = instance.get(CONTAINER);
  653. if (!container) {
  654. container = instance._createNodeContainer();
  655. }
  656. instance.childrenLength = v.length;
  657. // before render the node, make sure the PARENT_NODE and OWNER_TREE references are updated
  658. // this is required on the render phase of the TreeNode (_createNodeContainer)
  659. // to propagate the events callback (appendChild/expand)
  660. var ownerTree = instance;
  661. if (isTreeNode(instance)) {
  662. ownerTree = instance.get(OWNER_TREE);
  663. }
  664. var hasOwnerTree = isTreeView(ownerTree);
  665. var lazyLoad = true;
  666. if (hasOwnerTree) {
  667. lazyLoad = ownerTree.get(LAZY_LOAD);
  668. }
  669. instance.updateIndex({});
  670. if (instance.childrenLength > 0) {
  671. instance.set(LEAF, false);
  672. }
  673. A.Array.each(v, function(node, index) {
  674. if (node) {
  675. if (!isTreeNode(node) && isObject(node)) {
  676. // cache and remove children to lazy add them later for
  677. // performance reasons
  678. var children = node[CHILDREN];
  679. var hasChildren = children && children.length;
  680. node[OWNER_TREE] = ownerTree;
  681. node[PARENT_NODE] = instance;
  682. if (hasChildren && lazyLoad) {
  683. delete node[CHILDREN];
  684. }
  685. // creating node from json
  686. var jsonNode = node;
  687. node = instance.createNode(node);
  688. if (hasChildren && lazyLoad) {
  689. jsonNode.children = children;
  690. node.childrenLength = children.length;
  691. A.setTimeout(function() {
  692. node.set(CHILDREN, children);
  693. }, 50);
  694. }
  695. }
  696. instance.registerNode(node);
  697. if (hasOwnerTree) {
  698. ownerTree.registerNode(node);
  699. }
  700. node.render(container);
  701. // avoid duplicated children on the childNodes list
  702. if (A.Array.indexOf(childNodes, node) === -1) {
  703. childNodes.push(node);
  704. }
  705. }
  706. });
  707. return childNodes;
  708. }
  709. });
  710. A.TreeData = TreeData;
  711. }, '@VERSION@' ,{requires:['aui-base','aui-task-manager'], skinnable:false});