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.

widget-parent.js 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. /*
  2. Copyright (c) 2010, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.com/yui/license.html
  5. version: 3.4.0
  6. build: nightly
  7. */
  8. YUI.add('widget-parent', function(Y) {
  9. /**
  10. * Extension enabling a Widget to be a parent of another Widget.
  11. *
  12. * @module widget-parent
  13. */
  14. var Lang = Y.Lang,
  15. RENDERED = "rendered",
  16. BOUNDING_BOX = "boundingBox";
  17. /**
  18. * Widget extension providing functionality enabling a Widget to be a
  19. * parent of another Widget.
  20. *
  21. * <p>In addition to the set of attributes supported by WidgetParent, the constructor
  22. * configuration object can also contain a <code>children</code> which can be used
  23. * to add child widgets to the parent during construction. The <code>children</code>
  24. * property is an array of either child widget instances or child widget configuration
  25. * objects, and is sugar for the <a href="#method_add">add</a> method. See the
  26. * <a href="#method_add">add</a> for details on the structure of the child widget
  27. * configuration object.
  28. * @class WidgetParent
  29. * @constructor
  30. * @uses ArrayList
  31. * @param {Object} config User configuration object.
  32. */
  33. function Parent(config) {
  34. /**
  35. * Fires when a Widget is add as a child. The event object will have a
  36. * 'child' property that returns a reference to the child Widget, as well
  37. * as an 'index' property that returns a reference to the index specified
  38. * when the add() method was called.
  39. * <p>
  40. * Subscribers to the "on" moment of this event, will be notified
  41. * before a child is added.
  42. * </p>
  43. * <p>
  44. * Subscribers to the "after" moment of this event, will be notified
  45. * after a child is added.
  46. * </p>
  47. *
  48. * @event addChild
  49. * @preventable _defAddChildFn
  50. * @param {EventFacade} e The Event Facade
  51. */
  52. this.publish("addChild", {
  53. defaultTargetOnly: true,
  54. defaultFn: this._defAddChildFn
  55. });
  56. /**
  57. * Fires when a child Widget is removed. The event object will have a
  58. * 'child' property that returns a reference to the child Widget, as well
  59. * as an 'index' property that returns a reference child's ordinal position.
  60. * <p>
  61. * Subscribers to the "on" moment of this event, will be notified
  62. * before a child is removed.
  63. * </p>
  64. * <p>
  65. * Subscribers to the "after" moment of this event, will be notified
  66. * after a child is removed.
  67. * </p>
  68. *
  69. * @event removeChild
  70. * @preventable _defRemoveChildFn
  71. * @param {EventFacade} e The Event Facade
  72. */
  73. this.publish("removeChild", {
  74. defaultTargetOnly: true,
  75. defaultFn: this._defRemoveChildFn
  76. });
  77. this._items = [];
  78. var children,
  79. handle;
  80. if (config && config.children) {
  81. children = config.children;
  82. handle = this.after("initializedChange", function (e) {
  83. this._add(children);
  84. handle.detach();
  85. });
  86. }
  87. // Widget method overlap
  88. Y.after(this._renderChildren, this, "renderUI");
  89. Y.after(this._bindUIParent, this, "bindUI");
  90. this.after("selectionChange", this._afterSelectionChange);
  91. this.after("selectedChange", this._afterParentSelectedChange);
  92. this.after("activeDescendantChange", this._afterActiveDescendantChange);
  93. this._hDestroyChild = this.after("*:destroy", this._afterDestroyChild);
  94. this.after("*:focusedChange", this._updateActiveDescendant);
  95. }
  96. Parent.ATTRS = {
  97. /**
  98. * @attribute defaultChildType
  99. * @type {String|Object}
  100. *
  101. * @description String representing the default type of the children
  102. * managed by this Widget. Can also supply default type as a constructor
  103. * reference.
  104. */
  105. defaultChildType: {
  106. setter: function (val) {
  107. var returnVal = Y.Attribute.INVALID_VALUE,
  108. FnConstructor = Lang.isString(val) ? Y[val] : val;
  109. if (Lang.isFunction(FnConstructor)) {
  110. returnVal = FnConstructor;
  111. }
  112. return returnVal;
  113. }
  114. },
  115. /**
  116. * @attribute activeDescendant
  117. * @type Widget
  118. * @readOnly
  119. *
  120. * @description Returns the Widget's currently focused descendant Widget.
  121. */
  122. activeDescendant: {
  123. readOnly: true
  124. },
  125. /**
  126. * @attribute multiple
  127. * @type Boolean
  128. * @default false
  129. * @writeOnce
  130. *
  131. * @description Boolean indicating if multiple children can be selected at
  132. * once. Whether or not multiple selection is enabled is always delegated
  133. * to the value of the <code>multiple</code> attribute of the root widget
  134. * in the object hierarchy.
  135. */
  136. multiple: {
  137. value: false,
  138. validator: Lang.isBoolean,
  139. writeOnce: true,
  140. getter: function (value) {
  141. var root = this.get("root");
  142. return (root && root != this) ? root.get("multiple") : value;
  143. }
  144. },
  145. /**
  146. * @attribute selection
  147. * @type {ArrayList|Widget}
  148. * @readOnly
  149. *
  150. * @description Returns the currently selected child Widget. If the
  151. * <code>mulitple</code> attribte is set to <code>true</code> will
  152. * return an Y.ArrayList instance containing the currently selected
  153. * children. If no children are selected, will return null.
  154. */
  155. selection: {
  156. readOnly: true,
  157. setter: "_setSelection",
  158. getter: function (value) {
  159. var selection = Lang.isArray(value) ?
  160. (new Y.ArrayList(value)) : value;
  161. return selection;
  162. }
  163. },
  164. selected: {
  165. setter: function (value) {
  166. // Enforces selection behavior on for parent Widgets. Parent's
  167. // selected attribute can be set to the following:
  168. // 0 - Not selected
  169. // 1 - Fully selected (all children are selected). In order for
  170. // all children to be selected, multiple selection must be
  171. // enabled. Therefore, you cannot set the "selected" attribute
  172. // on a parent Widget to 1 unless multiple selection is enabled.
  173. // 2 - Partially selected, meaning one ore more (but not all)
  174. // children are selected.
  175. var returnVal = value;
  176. if (value === 1 && !this.get("multiple")) {
  177. returnVal = Y.Attribute.INVALID_VALUE;
  178. }
  179. return returnVal;
  180. }
  181. }
  182. };
  183. Parent.prototype = {
  184. /**
  185. * The destructor implementation for Parent widgets. Destroys all children.
  186. * @method destructor
  187. */
  188. destructor: function() {
  189. this._destroyChildren();
  190. },
  191. /**
  192. * Destroy event listener for each child Widget, responsible for removing
  193. * the destroyed child Widget from the parent's internal array of children
  194. * (_items property).
  195. *
  196. * @method _afterDestroyChild
  197. * @protected
  198. * @param {EventFacade} event The event facade for the attribute change.
  199. */
  200. _afterDestroyChild: function (event) {
  201. var child = event.target;
  202. if (child.get("parent") == this) {
  203. child.remove();
  204. }
  205. },
  206. /**
  207. * Attribute change listener for the <code>selection</code>
  208. * attribute, responsible for setting the value of the
  209. * parent's <code>selected</code> attribute.
  210. *
  211. * @method _afterSelectionChange
  212. * @protected
  213. * @param {EventFacade} event The event facade for the attribute change.
  214. */
  215. _afterSelectionChange: function (event) {
  216. if (event.target == this && event.src != this) {
  217. var selection = event.newVal,
  218. selectedVal = 0; // Not selected
  219. if (selection) {
  220. selectedVal = 2; // Assume partially selected, confirm otherwise
  221. if (Y.instanceOf(selection, Y.ArrayList) &&
  222. (selection.size() === this.size())) {
  223. selectedVal = 1; // Fully selected
  224. }
  225. }
  226. this.set("selected", selectedVal, { src: this });
  227. }
  228. },
  229. /**
  230. * Attribute change listener for the <code>activeDescendant</code>
  231. * attribute, responsible for setting the value of the
  232. * parent's <code>activeDescendant</code> attribute.
  233. *
  234. * @method _afterActiveDescendantChange
  235. * @protected
  236. * @param {EventFacade} event The event facade for the attribute change.
  237. */
  238. _afterActiveDescendantChange: function (event) {
  239. var parent = this.get("parent");
  240. if (parent) {
  241. parent._set("activeDescendant", event.newVal);
  242. }
  243. },
  244. /**
  245. * Attribute change listener for the <code>selected</code>
  246. * attribute, responsible for syncing the selected state of all children to
  247. * match that of their parent Widget.
  248. *
  249. *
  250. * @method _afterParentSelectedChange
  251. * @protected
  252. * @param {EventFacade} event The event facade for the attribute change.
  253. */
  254. _afterParentSelectedChange: function (event) {
  255. var value = event.newVal;
  256. if (this == event.target && event.src != this &&
  257. (value === 0 || value === 1)) {
  258. this.each(function (child) {
  259. // Specify the source of this change as the parent so that
  260. // value of the parent's "selection" attribute isn't
  261. // recalculated
  262. child.set("selected", value, { src: this });
  263. }, this);
  264. }
  265. },
  266. /**
  267. * Default setter for <code>selection</code> attribute changes.
  268. *
  269. * @method _setSelection
  270. * @protected
  271. * @param child {Widget|Array} Widget or Array of Widget instances.
  272. * @return {Widget|Array} Widget or Array of Widget instances.
  273. */
  274. _setSelection: function (child) {
  275. var selection = null,
  276. selected;
  277. if (this.get("multiple") && !this.isEmpty()) {
  278. selected = [];
  279. this.each(function (v) {
  280. if (v.get("selected") > 0) {
  281. selected.push(v);
  282. }
  283. });
  284. if (selected.length > 0) {
  285. selection = selected;
  286. }
  287. }
  288. else {
  289. if (child.get("selected") > 0) {
  290. selection = child;
  291. }
  292. }
  293. return selection;
  294. },
  295. /**
  296. * Attribute change listener for the <code>selected</code>
  297. * attribute of child Widgets, responsible for setting the value of the
  298. * parent's <code>selection</code> attribute.
  299. *
  300. * @method _updateSelection
  301. * @protected
  302. * @param {EventFacade} event The event facade for the attribute change.
  303. */
  304. _updateSelection: function (event) {
  305. var child = event.target,
  306. selection;
  307. if (child.get("parent") == this) {
  308. if (event.src != "_updateSelection") {
  309. selection = this.get("selection");
  310. if (!this.get("multiple") && selection && event.newVal > 0) {
  311. // Deselect the previously selected child.
  312. // Set src equal to the current context to prevent
  313. // unnecessary re-calculation of the selection.
  314. selection.set("selected", 0, { src: "_updateSelection" });
  315. }
  316. this._set("selection", child);
  317. }
  318. if (event.src == this) {
  319. this._set("selection", child, { src: this });
  320. }
  321. }
  322. },
  323. /**
  324. * Attribute change listener for the <code>focused</code>
  325. * attribute of child Widgets, responsible for setting the value of the
  326. * parent's <code>activeDescendant</code> attribute.
  327. *
  328. * @method _updateActiveDescendant
  329. * @protected
  330. * @param {EventFacade} event The event facade for the attribute change.
  331. */
  332. _updateActiveDescendant: function (event) {
  333. var activeDescendant = (event.newVal === true) ? event.target : null;
  334. this._set("activeDescendant", activeDescendant);
  335. },
  336. /**
  337. * Creates an instance of a child Widget using the specified configuration.
  338. * By default Widget instances will be created of the type specified
  339. * by the <code>defaultChildType</code> attribute. Types can be explicitly
  340. * defined via the <code>childType</code> property of the configuration object
  341. * literal. The use of the <code>type</code> property has been deprecated, but
  342. * will still be used as a fallback, if <code>childType</code> is not defined,
  343. * for backwards compatibility.
  344. *
  345. * @method _createChild
  346. * @protected
  347. * @param config {Object} Object literal representing the configuration
  348. * used to create an instance of a Widget.
  349. */
  350. _createChild: function (config) {
  351. var defaultType = this.get("defaultChildType"),
  352. altType = config.childType || config.type,
  353. child,
  354. Fn,
  355. FnConstructor;
  356. if (altType) {
  357. Fn = Lang.isString(altType) ? Y[altType] : altType;
  358. }
  359. if (Lang.isFunction(Fn)) {
  360. FnConstructor = Fn;
  361. } else if (defaultType) {
  362. // defaultType is normalized to a function in it's setter
  363. FnConstructor = defaultType;
  364. }
  365. if (FnConstructor) {
  366. child = new FnConstructor(config);
  367. } else {
  368. Y.error("Could not create a child instance because its constructor is either undefined or invalid.");
  369. }
  370. return child;
  371. },
  372. /**
  373. * Default addChild handler
  374. *
  375. * @method _defAddChildFn
  376. * @protected
  377. * @param event {EventFacade} The Event object
  378. * @param child {Widget} The Widget instance, or configuration
  379. * object for the Widget to be added as a child.
  380. * @param index {Number} Number representing the position at
  381. * which the child will be inserted.
  382. */
  383. _defAddChildFn: function (event) {
  384. var child = event.child,
  385. index = event.index,
  386. children = this._items;
  387. if (child.get("parent")) {
  388. child.remove();
  389. }
  390. if (Lang.isNumber(index)) {
  391. children.splice(index, 0, child);
  392. }
  393. else {
  394. children.push(child);
  395. }
  396. child._set("parent", this);
  397. child.addTarget(this);
  398. // Update index in case it got normalized after addition
  399. // (e.g. user passed in 10, and there are only 3 items, the actual index would be 3. We don't want to pass 10 around in the event facade).
  400. event.index = child.get("index");
  401. // To Do: Remove in favor of using event bubbling
  402. child.after("selectedChange", Y.bind(this._updateSelection, this));
  403. },
  404. /**
  405. * Default removeChild handler
  406. *
  407. * @method _defRemoveChildFn
  408. * @protected
  409. * @param event {EventFacade} The Event object
  410. * @param child {Widget} The Widget instance to be removed.
  411. * @param index {Number} Number representing the index of the Widget to
  412. * be removed.
  413. */
  414. _defRemoveChildFn: function (event) {
  415. var child = event.child,
  416. index = event.index,
  417. children = this._items;
  418. if (child.get("focused")) {
  419. child.set("focused", false);
  420. }
  421. if (child.get("selected")) {
  422. child.set("selected", 0);
  423. }
  424. children.splice(index, 1);
  425. child.removeTarget(this);
  426. child._oldParent = child.get("parent");
  427. child._set("parent", null);
  428. },
  429. /**
  430. * @method _add
  431. * @protected
  432. * @param child {Widget|Object} The Widget instance, or configuration
  433. * object for the Widget to be added as a child.
  434. * @param child {Array} Array of Widget instances, or configuration
  435. * objects for the Widgets to be added as a children.
  436. * @param index {Number} (Optional.) Number representing the position at
  437. * which the child should be inserted.
  438. * @description Adds a Widget as a child. If the specified Widget already
  439. * has a parent it will be removed from its current parent before
  440. * being added as a child.
  441. * @return {Widget|Array} Successfully added Widget or Array containing the
  442. * successfully added Widget instance(s). If no children where added, will
  443. * will return undefined.
  444. */
  445. _add: function (child, index) {
  446. var children,
  447. oChild,
  448. returnVal;
  449. if (Lang.isArray(child)) {
  450. children = [];
  451. Y.each(child, function (v, k) {
  452. oChild = this._add(v, (index + k));
  453. if (oChild) {
  454. children.push(oChild);
  455. }
  456. }, this);
  457. if (children.length > 0) {
  458. returnVal = children;
  459. }
  460. }
  461. else {
  462. if (Y.instanceOf(child, Y.Widget)) {
  463. oChild = child;
  464. }
  465. else {
  466. oChild = this._createChild(child);
  467. }
  468. if (oChild && this.fire("addChild", { child: oChild, index: index })) {
  469. returnVal = oChild;
  470. }
  471. }
  472. return returnVal;
  473. },
  474. /**
  475. * @method add
  476. * @param child {Widget|Object} The Widget instance, or configuration
  477. * object for the Widget to be added as a child. The configuration object
  478. * for the child can include a <code>childType</code> property, which is either
  479. * a constructor function or a string which names a constructor function on the
  480. * Y instance (e.g. "Tab" would refer to Y.Tab) (<code>childType</code> used to be
  481. * named <code>type</code>, support for which has been deprecated, but is still
  482. * maintained for backward compatibility. <code>childType</code> takes precedence
  483. * over <code>type</code> if both are defined.
  484. * @param child {Array} Array of Widget instances, or configuration
  485. * objects for the Widgets to be added as a children.
  486. * @param index {Number} (Optional.) Number representing the position at
  487. * which the child should be inserted.
  488. * @description Adds a Widget as a child. If the specified Widget already
  489. * has a parent it will be removed from its current parent before
  490. * being added as a child.
  491. * @return {ArrayList} Y.ArrayList containing the successfully added
  492. * Widget instance(s). If no children where added, will return an empty
  493. * Y.ArrayList instance.
  494. */
  495. add: function () {
  496. var added = this._add.apply(this, arguments),
  497. children = added ? (Lang.isArray(added) ? added : [added]) : [];
  498. return (new Y.ArrayList(children));
  499. },
  500. /**
  501. * @method remove
  502. * @param index {Number} (Optional.) Number representing the index of the
  503. * child to be removed.
  504. * @description Removes the Widget from its parent. Optionally, can remove
  505. * a child by specifying its index.
  506. * @return {Widget} Widget instance that was successfully removed, otherwise
  507. * undefined.
  508. */
  509. remove: function (index) {
  510. var child = this._items[index],
  511. returnVal;
  512. if (child && this.fire("removeChild", { child: child, index: index })) {
  513. returnVal = child;
  514. }
  515. return returnVal;
  516. },
  517. /**
  518. * @method removeAll
  519. * @description Removes all of the children from the Widget.
  520. * @return {ArrayList} Y.ArrayList instance containing Widgets that were
  521. * successfully removed. If no children where removed, will return an empty
  522. * Y.ArrayList instance.
  523. */
  524. removeAll: function () {
  525. var removed = [],
  526. child;
  527. Y.each(this._items.concat(), function () {
  528. child = this.remove(0);
  529. if (child) {
  530. removed.push(child);
  531. }
  532. }, this);
  533. return (new Y.ArrayList(removed));
  534. },
  535. /**
  536. * Selects the child at the given index (zero-based).
  537. *
  538. * @method selectChild
  539. * @param {Number} i the index of the child to be selected
  540. */
  541. selectChild: function(i) {
  542. this.item(i).set('selected', 1);
  543. },
  544. /**
  545. * Selects all children.
  546. *
  547. * @method selectAll
  548. */
  549. selectAll: function () {
  550. this.set("selected", 1);
  551. },
  552. /**
  553. * Deselects all children.
  554. *
  555. * @method deselectAll
  556. */
  557. deselectAll: function () {
  558. this.set("selected", 0);
  559. },
  560. /**
  561. * Updates the UI in response to a child being added.
  562. *
  563. * @method _uiAddChild
  564. * @protected
  565. * @param child {Widget} The child Widget instance to render.
  566. * @param parentNode {Object} The Node under which the
  567. * child Widget is to be rendered.
  568. */
  569. _uiAddChild: function (child, parentNode) {
  570. child.render(parentNode);
  571. // TODO: Ideally this should be in Child's render UI.
  572. var childBB = child.get("boundingBox"),
  573. siblingBB,
  574. nextSibling = child.next(false),
  575. prevSibling;
  576. // Insert or Append to last child.
  577. // Avoiding index, and using the current sibling
  578. // state (which should be accurate), means we don't have
  579. // to worry about decorator elements which may be added
  580. // to the _childContainer node.
  581. if (nextSibling && nextSibling.get(RENDERED)) {
  582. siblingBB = nextSibling.get(BOUNDING_BOX);
  583. siblingBB.insert(childBB, "before");
  584. } else {
  585. prevSibling = child.previous(false);
  586. if (prevSibling && prevSibling.get(RENDERED)) {
  587. siblingBB = prevSibling.get(BOUNDING_BOX);
  588. siblingBB.insert(childBB, "after");
  589. } else if (!parentNode.contains(childBB)) {
  590. // Based on pull request from andreas-karlsson
  591. // https://github.com/yui/yui3/pull/25#issuecomment-2103536
  592. // Account for case where a child was rendered independently of the
  593. // parent-child framework, to a node outside of the parentNode,
  594. // and there are no siblings.
  595. parentNode.appendChild(childBB);
  596. }
  597. }
  598. },
  599. /**
  600. * Updates the UI in response to a child being removed.
  601. *
  602. * @method _uiRemoveChild
  603. * @protected
  604. * @param child {Widget} The child Widget instance to render.
  605. */
  606. _uiRemoveChild: function (child) {
  607. child.get("boundingBox").remove();
  608. },
  609. _afterAddChild: function (event) {
  610. var child = event.child;
  611. if (child.get("parent") == this) {
  612. this._uiAddChild(child, this._childrenContainer);
  613. }
  614. },
  615. _afterRemoveChild: function (event) {
  616. var child = event.child;
  617. if (child._oldParent == this) {
  618. this._uiRemoveChild(child);
  619. }
  620. },
  621. /**
  622. * Sets up DOM and CustomEvent listeners for the parent widget.
  623. * <p>
  624. * This method in invoked after bindUI is invoked for the Widget class
  625. * using YUI's aop infrastructure.
  626. * </p>
  627. *
  628. * @method _bindUIParent
  629. * @protected
  630. */
  631. _bindUIParent: function () {
  632. this.after("addChild", this._afterAddChild);
  633. this.after("removeChild", this._afterRemoveChild);
  634. },
  635. /**
  636. * Renders all child Widgets for the parent.
  637. * <p>
  638. * This method in invoked after renderUI is invoked for the Widget class
  639. * using YUI's aop infrastructure.
  640. * </p>
  641. * @method _renderChildren
  642. * @protected
  643. */
  644. _renderChildren: function () {
  645. /**
  646. * <p>By default WidgetParent will render it's children to the parent's content box.</p>
  647. *
  648. * <p>If the children need to be rendered somewhere else, the _childrenContainer property
  649. * can be set to the Node which the children should be rendered to. This property should be
  650. * set before the _renderChildren method is invoked, ideally in your renderUI method,
  651. * as soon as you create the element to be rendered to.</p>
  652. *
  653. * @protected
  654. * @property _childrenContainer
  655. * @value The content box
  656. * @type Node
  657. */
  658. var renderTo = this._childrenContainer || this.get("contentBox");
  659. this._childrenContainer = renderTo;
  660. this.each(function (child) {
  661. child.render(renderTo);
  662. });
  663. },
  664. /**
  665. * Destroys all child Widgets for the parent.
  666. * <p>
  667. * This method is invoked before the destructor is invoked for the Widget
  668. * class using YUI's aop infrastructure.
  669. * </p>
  670. * @method _destroyChildren
  671. * @protected
  672. */
  673. _destroyChildren: function () {
  674. // Detach the handler responsible for removing children in
  675. // response to destroying them since:
  676. // 1) It is unnecessary/inefficient at this point since we are doing
  677. // a batch destroy of all children.
  678. // 2) Removing each child will affect our ability to iterate the
  679. // children since the size of _items will be changing as we
  680. // iterate.
  681. this._hDestroyChild.detach();
  682. // Need to clone the _items array since
  683. this.each(function (child) {
  684. child.destroy();
  685. });
  686. }
  687. };
  688. Y.augment(Parent, Y.ArrayList);
  689. Y.WidgetParent = Parent;
  690. }, '3.4.0' ,{requires:['base-build', 'arraylist', 'widget']});