Card.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-layout-container-Card'>/**
  19. </span> * This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be
  20. * visible at any given time. This layout style is most commonly used for wizards, tab implementations, etc.
  21. * This class is intended to be extended or created via the layout:'card' {@link Ext.container.Container#layout} config,
  22. * and should generally not need to be created directly via the new keyword.
  23. *
  24. * The CardLayout's focal method is {@link #setActiveItem}. Since only one panel is displayed at a time,
  25. * the only way to move from one Component to the next is by calling setActiveItem, passing the next panel to display
  26. * (or its id or index). The layout itself does not provide a user interface for handling this navigation,
  27. * so that functionality must be provided by the developer.
  28. *
  29. * To change the active card of a container, call the setActiveItem method of its layout:
  30. *
  31. * @example
  32. * var p = Ext.create('Ext.panel.Panel', {
  33. * layout: 'card',
  34. * items: [
  35. * { html: 'Card 1' },
  36. * { html: 'Card 2' }
  37. * ],
  38. * renderTo: Ext.getBody()
  39. * });
  40. *
  41. * p.getLayout().setActiveItem(1);
  42. *
  43. * In the following example, a simplistic wizard setup is demonstrated. A button bar is added
  44. * to the footer of the containing panel to provide navigation buttons. The buttons will be handled by a
  45. * common navigation routine. Note that other uses of a CardLayout (like a tab control) would require a
  46. * completely different implementation. For serious implementations, a better approach would be to extend
  47. * CardLayout to provide the custom functionality needed.
  48. *
  49. * @example
  50. * var navigate = function(panel, direction){
  51. * // This routine could contain business logic required to manage the navigation steps.
  52. * // It would call setActiveItem as needed, manage navigation button state, handle any
  53. * // branching logic that might be required, handle alternate actions like cancellation
  54. * // or finalization, etc. A complete wizard implementation could get pretty
  55. * // sophisticated depending on the complexity required, and should probably be
  56. * // done as a subclass of CardLayout in a real-world implementation.
  57. * var layout = panel.getLayout();
  58. * layout[direction]();
  59. * Ext.getCmp('move-prev').setDisabled(!layout.getPrev());
  60. * Ext.getCmp('move-next').setDisabled(!layout.getNext());
  61. * };
  62. *
  63. * Ext.create('Ext.panel.Panel', {
  64. * title: 'Example Wizard',
  65. * width: 300,
  66. * height: 200,
  67. * layout: 'card',
  68. * bodyStyle: 'padding:15px',
  69. * defaults: {
  70. * // applied to each contained panel
  71. * border: false
  72. * },
  73. * // just an example of one possible navigation scheme, using buttons
  74. * bbar: [
  75. * {
  76. * id: 'move-prev',
  77. * text: 'Back',
  78. * handler: function(btn) {
  79. * navigate(btn.up(&quot;panel&quot;), &quot;prev&quot;);
  80. * },
  81. * disabled: true
  82. * },
  83. * '-&gt;', // greedy spacer so that the buttons are aligned to each side
  84. * {
  85. * id: 'move-next',
  86. * text: 'Next',
  87. * handler: function(btn) {
  88. * navigate(btn.up(&quot;panel&quot;), &quot;next&quot;);
  89. * }
  90. * }
  91. * ],
  92. * // the panels (or &quot;cards&quot;) within the layout
  93. * items: [{
  94. * id: 'card-0',
  95. * html: '&lt;h1&gt;Welcome to the Wizard!&lt;/h1&gt;&lt;p&gt;Step 1 of 3&lt;/p&gt;'
  96. * },{
  97. * id: 'card-1',
  98. * html: '&lt;p&gt;Step 2 of 3&lt;/p&gt;'
  99. * },{
  100. * id: 'card-2',
  101. * html: '&lt;h1&gt;Congratulations!&lt;/h1&gt;&lt;p&gt;Step 3 of 3 - Complete&lt;/p&gt;'
  102. * }],
  103. * renderTo: Ext.getBody()
  104. * });
  105. */
  106. Ext.define('Ext.layout.container.Card', {
  107. /* Begin Definitions */
  108. extend: 'Ext.layout.container.Fit',
  109. alternateClassName: 'Ext.layout.CardLayout',
  110. alias: 'layout.card',
  111. /* End Definitions */
  112. type: 'card',
  113. hideInactive: true,
  114. <span id='Ext-layout-container-Card-cfg-deferredRender'> /**
  115. </span> * @cfg {Boolean} deferredRender
  116. * True to render each contained item at the time it becomes active, false to render all contained items
  117. * as soon as the layout is rendered (defaults to false). If there is a significant amount of content or
  118. * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to
  119. * true might improve performance.
  120. */
  121. deferredRender : false,
  122. getRenderTree: function () {
  123. var me = this,
  124. activeItem = me.getActiveItem();
  125. if (activeItem) {
  126. // If they veto the activate, we have no active item
  127. if (activeItem.hasListeners.beforeactivate &amp;&amp; activeItem.fireEvent('beforeactivate', activeItem) === false) {
  128. // We must null our activeItem reference, AND the one in our owning Container.
  129. // Because upon layout invalidation, renderChildren will use this.getActiveItem which
  130. // uses this.activeItem || this.owner.activeItem
  131. activeItem = me.activeItem = me.owner.activeItem = null;
  132. }
  133. // Item is to be the active one. Fire event after it is first layed out
  134. else if (activeItem.hasListeners.activate) {
  135. activeItem.on({
  136. boxready: function() {
  137. activeItem.fireEvent('activate', activeItem);
  138. },
  139. single: true
  140. });
  141. }
  142. if (me.deferredRender) {
  143. if (activeItem) {
  144. return me.getItemsRenderTree([activeItem]);
  145. }
  146. } else {
  147. return me.callParent(arguments);
  148. }
  149. }
  150. },
  151. renderChildren: function () {
  152. var me = this,
  153. active = me.getActiveItem();
  154. if (!me.deferredRender) {
  155. me.callParent();
  156. } else if (active) {
  157. // ensure the active item is configured for the layout
  158. me.renderItems([active], me.getRenderTarget());
  159. }
  160. },
  161. isValidParent : function(item, target, position) {
  162. // Note: Card layout does not care about order within the target because only one is ever visible.
  163. // We only care whether the item is a direct child of the target.
  164. var itemEl = item.el ? item.el.dom : Ext.getDom(item);
  165. return (itemEl &amp;&amp; itemEl.parentNode === (target.dom || target)) || false;
  166. },
  167. <span id='Ext-layout-container-Card-method-getActiveItem'> /**
  168. </span> * Return the active (visible) component in the layout.
  169. * @returns {Ext.Component}
  170. */
  171. getActiveItem: function() {
  172. var me = this,
  173. // Ensure the calculated result references a Component
  174. result = me.parseActiveItem(me.activeItem || (me.owner &amp;&amp; me.owner.activeItem));
  175. // Sanitize the result in case the active item is no longer there.
  176. if (result &amp;&amp; me.owner.items.indexOf(result) != -1) {
  177. me.activeItem = result;
  178. } else {
  179. me.activeItem = null;
  180. }
  181. return me.activeItem;
  182. },
  183. // @private
  184. parseActiveItem: function(item) {
  185. if (item &amp;&amp; item.isComponent) {
  186. return item;
  187. } else if (typeof item == 'number' || item === undefined) {
  188. return this.getLayoutItems()[item || 0];
  189. } else {
  190. return this.owner.getComponent(item);
  191. }
  192. },
  193. // @private. Called before both dynamic render, and bulk render.
  194. // Ensure that the active item starts visible, and inactive ones start invisible
  195. configureItem: function(item) {
  196. if (item === this.getActiveItem()) {
  197. item.hidden = false;
  198. } else {
  199. item.hidden = true;
  200. }
  201. this.callParent(arguments);
  202. },
  203. onRemove: function(component) {
  204. var me = this;
  205. if (component === me.activeItem) {
  206. me.activeItem = null;
  207. }
  208. },
  209. // @private
  210. getAnimation: function(newCard, owner) {
  211. var newAnim = (newCard || {}).cardSwitchAnimation;
  212. if (newAnim === false) {
  213. return false;
  214. }
  215. return newAnim || owner.cardSwitchAnimation;
  216. },
  217. <span id='Ext-layout-container-Card-method-getNext'> /**
  218. </span> * Return the active (visible) component in the layout to the next card
  219. * @returns {Ext.Component} The next component or false.
  220. */
  221. getNext: function() {
  222. //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This
  223. //should come back in 4.1
  224. var wrap = arguments[0],
  225. items = this.getLayoutItems(),
  226. index = Ext.Array.indexOf(items, this.activeItem);
  227. return items[index + 1] || (wrap ? items[0] : false);
  228. },
  229. <span id='Ext-layout-container-Card-method-next'> /**
  230. </span> * Sets the active (visible) component in the layout to the next card
  231. * @return {Ext.Component} the activated component or false when nothing activated.
  232. */
  233. next: function() {
  234. //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This
  235. //should come back in 4.1
  236. var anim = arguments[0],
  237. wrap = arguments[1];
  238. return this.setActiveItem(this.getNext(wrap), anim);
  239. },
  240. <span id='Ext-layout-container-Card-method-getPrev'> /**
  241. </span> * Return the active (visible) component in the layout to the previous card
  242. * @returns {Ext.Component} The previous component or false.
  243. */
  244. getPrev: function() {
  245. //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This
  246. //should come back in 4.1
  247. var wrap = arguments[0],
  248. items = this.getLayoutItems(),
  249. index = Ext.Array.indexOf(items, this.activeItem);
  250. return items[index - 1] || (wrap ? items[items.length - 1] : false);
  251. },
  252. <span id='Ext-layout-container-Card-method-prev'> /**
  253. </span> * Sets the active (visible) component in the layout to the previous card
  254. * @return {Ext.Component} the activated component or false when nothing activated.
  255. */
  256. prev: function() {
  257. //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This
  258. //should come back in 4.1
  259. var anim = arguments[0],
  260. wrap = arguments[1];
  261. return this.setActiveItem(this.getPrev(wrap), anim);
  262. },
  263. <span id='Ext-layout-container-Card-method-setActiveItem'> /**
  264. </span> * Makes the given card active.
  265. *
  266. * var card1 = Ext.create('Ext.panel.Panel', {itemId: 'card-1'});
  267. * var card2 = Ext.create('Ext.panel.Panel', {itemId: 'card-2'});
  268. * var panel = Ext.create('Ext.panel.Panel', {
  269. * layout: 'card',
  270. * activeItem: 0,
  271. * items: [card1, card2]
  272. * });
  273. * // These are all equivalent
  274. * panel.getLayout().setActiveItem(card2);
  275. * panel.getLayout().setActiveItem('card-2');
  276. * panel.getLayout().setActiveItem(1);
  277. *
  278. * @param {Ext.Component/Number/String} newCard The component, component {@link Ext.Component#id id},
  279. * {@link Ext.Component#itemId itemId}, or index of component.
  280. * @return {Ext.Component} the activated component or false when nothing activated.
  281. * False is returned also when trying to activate an already active card.
  282. */
  283. setActiveItem: function(newCard) {
  284. var me = this,
  285. owner = me.owner,
  286. oldCard = me.activeItem,
  287. rendered = owner.rendered,
  288. newIndex;
  289. newCard = me.parseActiveItem(newCard);
  290. newIndex = owner.items.indexOf(newCard);
  291. // If the card is not a child of the owner, then add it.
  292. // Without doing a layout!
  293. if (newIndex == -1) {
  294. newIndex = owner.items.items.length;
  295. Ext.suspendLayouts();
  296. newCard = owner.add(newCard);
  297. Ext.resumeLayouts();
  298. }
  299. // Is this a valid, different card?
  300. if (newCard &amp;&amp; oldCard != newCard) {
  301. // Fire the beforeactivate and beforedeactivate events on the cards
  302. if (newCard.fireEvent('beforeactivate', newCard, oldCard) === false) {
  303. return false;
  304. }
  305. if (oldCard &amp;&amp; oldCard.fireEvent('beforedeactivate', oldCard, newCard) === false) {
  306. return false;
  307. }
  308. if (rendered) {
  309. Ext.suspendLayouts();
  310. // If the card has not been rendered yet, now is the time to do so.
  311. if (!newCard.rendered) {
  312. me.renderItem(newCard, me.getRenderTarget(), owner.items.length);
  313. }
  314. if (oldCard) {
  315. if (me.hideInactive) {
  316. oldCard.hide();
  317. oldCard.hiddenByLayout = true;
  318. }
  319. oldCard.fireEvent('deactivate', oldCard, newCard);
  320. }
  321. // Make sure the new card is shown
  322. if (newCard.hidden) {
  323. newCard.show();
  324. }
  325. // Layout needs activeItem to be correct, so set it if the show has not been vetoed
  326. if (!newCard.hidden) {
  327. me.activeItem = newCard;
  328. }
  329. Ext.resumeLayouts(true);
  330. } else {
  331. me.activeItem = newCard;
  332. }
  333. newCard.fireEvent('activate', newCard, oldCard);
  334. return me.activeItem;
  335. }
  336. return false;
  337. }
  338. });
  339. </pre>
  340. </body>
  341. </html>