Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / examples / ux / GroupTabPanel.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  * @author Nicolas Ferrero
17  * @class Ext.ux.GroupTabPanel
18  * @extends Ext.Container
19  * A TabPanel with grouping support.
20  */
21 Ext.define('Ext.ux.GroupTabPanel', {
22     extend: 'Ext.Container',
23
24     alias: 'widget.grouptabpanel',
25
26     requires:[
27         'Ext.data.*',
28         'Ext.tree.*',
29         'Ext.layout.*'
30     ],
31
32     baseCls : Ext.baseCSSPrefix + 'grouptabpanel',
33
34     initComponent: function(config) {
35         var me = this,
36             items = [];
37
38         Ext.apply(me, config);
39
40         me.store = me.createItemsStore();
41         me.layout = {
42             type: 'hbox',
43             pack: 'start',
44             align: 'stretch'
45         };
46         me.defaults = {
47             border: false
48         };
49
50         me.items = Ext.each(me.items, function(item) {
51             items.push(item.items);
52         });
53
54         me.items = [{
55             xtype: 'treepanel',
56             cls: 'x-tree-panel x-grouptabbar',
57             width: 150,
58             rootVisible: false,
59             height: 400,
60             store: me.store,
61             hideHeaders: true,
62             useArrows: true,
63             animate: false,
64             viewConfig: {
65                 overItemCls: ''
66             },
67             columns: [{
68                 xtype: 'treecolumn',
69                 sortable: false,
70                 dataIndex: 'text',
71                 flex: 1,
72                 renderer: function (value, cell, node, idx1, idx2, store, tree) {
73                     var cls = '';
74
75                     if (!node.data.activeGroup) {
76                         cls += ' x-inactive-group';
77                     } else if (node.parentNode && node.parentNode.parentNode === null) {
78                         cls += ' x-grouptab-first';
79                         if (node.previousSibling) {
80                             cls += ' x-grouptab-prev';
81                         }
82                     } else if (node.nextSibling === null) {
83                         cls += ' x-grouptab-last';
84                     } else {
85                         cls += ' x-grouptab-center';
86                     }
87                     if (node.data.activeTab) {
88                             cls += ' x-active-tab';
89                     }
90                     cell.tdCls= 'x-grouptab'+ cls;
91
92                     return value;
93                 }
94              }]
95         },{
96             xtype: 'container',
97             flex: 1,
98             layout: 'card',
99             activeItem: me.mainItem,
100             baseCls: Ext.baseCSSPrefix + 'grouptabcontainer',
101             items: items
102         }];
103
104         me.addEvents(
105             /**
106              * @event beforetabchange
107              * Fires before a tab change (activated by {@link #setActiveTab}). Return false in any listener to cancel
108              * the tabchange
109              * @param {Ext.ux.GroupTabPanel} grouptabPanel The GroupTabPanel
110              * @param {Ext.Component} newCard The card that is about to be activated
111              * @param {Ext.Component} oldCard The card that is currently active
112              */
113             'beforetabchange',
114
115             /**
116              * @event tabchange
117              * Fires when a new tab has been activated (activated by {@link #setActiveTab}).
118              * @param {Ext.ux.GroupTabPanel} grouptabPanel The GroupTabPanel
119              * @param {Ext.Component} newCard The newly activated item
120              * @param {Ext.Component} oldCard The previously active item
121              */
122             'tabchange',
123
124             /**
125              * @event beforegroupchange
126              * Fires before a group change (activated by {@link #setActiveGroup}). Return false in any listener to cancel
127              * the groupchange
128              * @param {Ext.ux.GroupTabPanel} grouptabPanel The GroupTabPanel
129              * @param {Ext.Component} newGroup The root group card that is about to be activated
130              * @param {Ext.Component} oldGroup The root group card that is currently active
131              */
132             'beforegroupchange',
133
134             /**
135              * @event groupchange
136              * Fires when a new group has been activated (activated by {@link #setActiveGroup}).
137              * @param {Ext.ux.GroupTabPanel} grouptabPanel The GroupTabPanel
138              * @param {Ext.Component} newGroup The newly activated root group item
139              * @param {Ext.Component} oldGroup The previously active root group item
140              */
141             'groupchange'
142         );
143
144         me.callParent(arguments);
145         me.setActiveTab(me.activeTab);
146         me.setActiveGroup(me.activeGroup);
147         me.mon(me.down('treepanel').getSelectionModel(), 'select', me.onNodeSelect, me);
148     },
149
150     /**
151      * @private
152      * Node selection listener.
153      */
154     onNodeSelect: function (selModel, node) {
155         var me = this,
156             currentNode = me.store.getRootNode(),
157             parent;
158
159         if (node.parentNode && node.parentNode.parentNode === null) {
160             parent = node;
161         } else {
162             parent = node.parentNode;
163         }
164
165         if (me.setActiveGroup(parent.get('id')) === false || me.setActiveTab(node.get('id')) === false) {
166             return false;
167         }
168
169         while(currentNode) {
170             currentNode.set('activeTab', false);
171             currentNode.set('activeGroup', false);
172             currentNode = currentNode.firstChild || currentNode.nextSibling || currentNode.parentNode.nextSibling;
173         }
174
175         parent.set('activeGroup', true);
176
177         parent.eachChild(function(child) {
178
179             child.set('activeGroup', true);
180         });
181         node.set('activeTab', true);
182         selModel.view.refresh();
183     },
184
185     /**
186      * Makes the given component active (makes it the visible card in the GroupTabPanel's CardLayout)
187      * @param {Ext.Component} cmp The component to make active
188      */
189     setActiveTab: function(cmp) {
190         var me = this,
191             newTab = cmp,
192             oldTab;
193
194         if(Ext.isString(cmp)) {
195             newTab = Ext.getCmp(newTab);
196         }
197
198         if (newTab === me.activeTab) {
199             return false;
200         }
201
202         oldTab = me.activeTab;
203         if (me.fireEvent('beforetabchange', me, newTab, oldTab) !== false) {
204              me.activeTab = newTab;
205              if (me.rendered) {
206                  me.down('container[baseCls=' + Ext.baseCSSPrefix + 'grouptabcontainer' + ']').getLayout().setActiveItem(newTab);
207              }
208              me.fireEvent('tabchange', me, newTab, oldTab);
209          }
210          return true;
211     },
212
213     /**
214      * Makes the given group active
215      * @param {Ext.Component} cmp The root component to make active.
216      */
217     setActiveGroup: function(cmp) {
218         var me = this,
219             newGroup = cmp,
220             oldGroup;
221
222         if(Ext.isString(cmp)) {
223             newGroup = Ext.getCmp(newGroup);
224         }
225
226         if (newGroup === me.activeGroup) {
227             return true;
228         }
229
230         oldGroup = me.activeGroup;
231         if (me.fireEvent('beforegroupchange', me, newGroup, oldGroup) !== false) {
232              me.activeGroup = newGroup;
233              me.fireEvent('groupchange', me, newGroup, oldGroup);
234          } else {
235              return false;
236          }
237          return true;
238     },
239
240     /**
241      * @private
242      * Creates the TreeStore used by the GroupTabBar.
243      */
244     createItemsStore: function() {
245         var me = this,
246             data = {
247             text:'.',
248             children: []
249         };
250         me.activeGroup = me.activeGroup || 0;
251
252         Ext.each(me.items, function(item, idx){
253             var items = item.items,
254                 rootItem = (items[item.mainItem] || items[0]),
255                 root = {
256                     children: []
257                 };
258
259             if (!rootItem.id) {
260                 rootItem.id = Ext.id();
261             }
262
263             root.id = rootItem.id;
264             root.text = rootItem.title;
265             root.iconCls = rootItem.iconCls;
266             delete rootItem.iconCls;
267             delete rootItem.title;
268             root.expanded = true;
269             root.activeGroup = (me.activeGroup === idx);
270             root.activeTab = root.activeGroup ? true : false;
271             if (root.activeTab) {
272                 me.activeTab = root.id;
273             }
274
275             if (root.activeGroup) {
276                 me.mainItem = item.mainItem || 0;
277                 me.activeGroup = root.id;
278             }
279
280             Ext.each(item.items, function(childItem) {
281                 if (!childItem.id) {
282                     childItem.id = Ext.id();
283                 }
284                 if(childItem.id !== root.id) {
285                     var child = {
286                         id: childItem.id,
287                         leaf: true,
288                         text: childItem.title,
289                         iconCls: childItem.iconCls,
290                         activeTab: false
291                     };
292                     delete childItem.title;
293                     delete childItem.iconCls;
294
295                     child.activeGroup = root.activeGroup;
296                     root.children.push(child);
297                 }
298             }, me);
299
300             data.children.push(root);
301
302       }, me);
303
304        return Ext.create('Ext.data.TreeStore', {
305             fields: ['id', 'text', 'activeGroup', 'activeTab'],
306             root: {expanded: true},
307             proxy: {
308                 type: 'memory',
309                 data: data
310             }
311         });
312     },
313
314     /**
315      * Returns the item that is currently active inside this GroupTabPanel.
316      * @return {Ext.Component/Integer} The currently active item
317      */
318     getActiveTab: function() {
319         return this.activeTab;
320     },
321
322     /**
323      * Returns the root group item that is currently active inside this GroupTabPanel.
324      * @return {Ext.Component/Integer} The currently active root group item
325      */
326     getActiveGroup: function() {
327         return this.activeGroup;
328     }
329 });
330