Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / layout / container / Card.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.layout.container.Card
17  * @extends Ext.layout.container.AbstractCard
18  *
19  * 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 id or index of
26  * the next panel to display.  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  * In the following example, a simplistic wizard setup is demonstrated.  A button bar is added
30  * to the footer of the containing panel to provide navigation buttons.  The buttons will be handled by a
31  * common navigation routine.  Note that other uses of a CardLayout (like a tab control) would require a
32  * completely different implementation.  For serious implementations, a better approach would be to extend
33  * CardLayout to provide the custom functionality needed.
34  *
35  * {@img Ext.layout.container.Card/Ext.layout.container.Card.png Ext.layout.container.Card container layout}
36  *
37  * Example usage:
38  * 
39  *     var navigate = function(panel, direction){
40  *         // This routine could contain business logic required to manage the navigation steps.
41  *         // It would call setActiveItem as needed, manage navigation button state, handle any
42  *         // branching logic that might be required, handle alternate actions like cancellation
43  *         // or finalization, etc.  A complete wizard implementation could get pretty
44  *         // sophisticated depending on the complexity required, and should probably be
45  *         // done as a subclass of CardLayout in a real-world implementation.
46  *         var layout = panel.getLayout();
47  *         layout[direction]();
48  *         Ext.getCmp('move-prev').setDisabled(!layout.getPrev());
49  *         Ext.getCmp('move-next').setDisabled(!layout.getNext());
50  *     };
51  *  
52  *     Ext.create('Ext.panel.Panel', {
53  *         title: 'Example Wizard',
54  *         width: 300,
55  *         height: 200,
56  *         layout: 'card',
57  *         activeItem: 0, // make sure the active item is set on the container config!
58  *         bodyStyle: 'padding:15px',
59  *         defaults: {
60  *             // applied to each contained panel
61  *             border: false
62  *         },
63  *         // just an example of one possible navigation scheme, using buttons
64  *         bbar: [
65  *             {
66  *                 id: 'move-prev',
67  *                 text: 'Back',
68  *                 handler: function(btn) {
69  *                     navigate(btn.up("panel"), "prev");
70  *                 },
71  *                 disabled: true
72  *             },
73  *             '->', // greedy spacer so that the buttons are aligned to each side
74  *             {
75  *                 id: 'move-next',
76  *                 text: 'Next',
77  *                 handler: function(btn) {
78  *                     navigate(btn.up("panel"), "next");
79  *                 }
80  *             }
81  *         ],
82  *         // the panels (or "cards") within the layout
83  *         items: [{
84  *             id: 'card-0',
85  *             html: '<h1>Welcome to the Wizard!</h1><p>Step 1 of 3</p>'
86  *         },{
87  *             id: 'card-1',
88  *             html: '<p>Step 2 of 3</p>'
89  *         },{
90  *             id: 'card-2',
91  *             html: '<h1>Congratulations!</h1><p>Step 3 of 3 - Complete</p>'
92  *         }],
93  *         renderTo: Ext.getBody()
94  *     });  
95  */
96 Ext.define('Ext.layout.container.Card', {
97
98     /* Begin Definitions */
99
100     alias: ['layout.card'],
101     alternateClassName: 'Ext.layout.CardLayout',
102
103     extend: 'Ext.layout.container.AbstractCard',
104
105     /* End Definitions */
106
107     /**
108      * Makes the given card active.
109      * 
110      *     var card1 = Ext.create('Ext.panel.Panel', {itemId: 'card-1'});
111      *     var card2 = Ext.create('Ext.panel.Panel', {itemId: 'card-2'});
112      *     var panel = Ext.create('Ext.panel.Panel', {
113      *         layout: 'card',
114      *         activeItem: 0,
115      *         items: [card1, card2]
116      *     });
117      *     // These are all equivalent
118      *     panel.getLayout().setActiveItem(card2);
119      *     panel.getLayout().setActiveItem('card-2');
120      *     panel.getLayout().setActiveItem(1);
121      * 
122      * @param {Ext.Component/Number/String} newCard  The component, component {@link Ext.Component#id id},
123      * {@link Ext.Component#itemId itemId}, or index of component.
124      * @return {Ext.Component} the activated component or false when nothing activated.
125      * False is returned also when trying to activate an already active card.
126      */
127     setActiveItem: function(newCard) {
128         var me = this,
129             owner = me.owner,
130             oldCard = me.activeItem,
131             newIndex;
132
133         newCard = me.parseActiveItem(newCard);
134         newIndex = owner.items.indexOf(newCard);
135
136         // If the card is not a child of the owner, then add it
137         if (newIndex == -1) {
138             newIndex = owner.items.items.length;
139             owner.add(newCard);
140         }
141
142         // Is this a valid, different card?
143         if (newCard && oldCard != newCard) {
144             // If the card has not been rendered yet, now is the time to do so.
145             if (!newCard.rendered) {
146                 me.renderItem(newCard, me.getRenderTarget(), owner.items.length);
147                 me.configureItem(newCard, 0);
148             }
149
150             me.activeItem = newCard;
151
152             // Fire the beforeactivate and beforedeactivate events on the cards
153             if (newCard.fireEvent('beforeactivate', newCard, oldCard) === false) {
154                 return false;
155             }
156             if (oldCard && oldCard.fireEvent('beforedeactivate', oldCard, newCard) === false) {
157                 return false;
158             }
159
160             // If the card hasnt been sized yet, do it now
161             if (me.sizeAllCards) {
162                 // onLayout calls setItemBox
163                 me.onLayout();
164             }
165             else {
166                 me.setItemBox(newCard, me.getTargetBox());
167             }
168
169             me.owner.suspendLayout = true;
170
171             if (oldCard) {
172                 if (me.hideInactive) {
173                     oldCard.hide();
174                 }
175                 oldCard.fireEvent('deactivate', oldCard, newCard);
176             }
177
178             // Make sure the new card is shown
179             me.owner.suspendLayout = false;
180             if (newCard.hidden) {
181                 newCard.show();
182             } else {
183                 me.onLayout();
184             }
185
186             newCard.fireEvent('activate', newCard, oldCard);
187
188             return newCard;
189         }
190         return false;
191     },
192
193     configureItem: function(item) {
194
195         // Card layout only controls dimensions which IT has controlled.
196         // That calculation has to be determined at run time by examining the ownerCt's isFixedWidth()/isFixedHeight() methods
197         item.layoutManagedHeight = 0;
198         item.layoutManagedWidth = 0;
199
200         this.callParent(arguments);
201     }});