GroupTabPanel.js 10 KB

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