Container3.html 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999
  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-grid-header-Container'>/**
  19. </span> * Container which holds headers and is docked at the top or bottom of a TablePanel.
  20. * The HeaderContainer drives resizing/moving/hiding of columns within the TableView.
  21. * As headers are hidden, moved or resized the headercontainer is responsible for
  22. * triggering changes within the view.
  23. */
  24. Ext.define('Ext.grid.header.Container', {
  25. extend: 'Ext.container.Container',
  26. requires: [
  27. 'Ext.grid.ColumnLayout',
  28. 'Ext.grid.plugin.HeaderResizer',
  29. 'Ext.grid.plugin.HeaderReorderer'
  30. ],
  31. uses: [
  32. 'Ext.grid.column.Column',
  33. 'Ext.menu.Menu',
  34. 'Ext.menu.CheckItem',
  35. 'Ext.menu.Separator'
  36. ],
  37. border: true,
  38. alias: 'widget.headercontainer',
  39. baseCls: Ext.baseCSSPrefix + 'grid-header-ct',
  40. dock: 'top',
  41. <span id='Ext-grid-header-Container-cfg-weight'> /**
  42. </span> * @cfg {Number} weight
  43. * HeaderContainer overrides the default weight of 0 for all docked items to 100.
  44. * This is so that it has more priority over things like toolbars.
  45. */
  46. weight: 100,
  47. defaultType: 'gridcolumn',
  48. detachOnRemove: false,
  49. <span id='Ext-grid-header-Container-cfg-defaultWidth'> /**
  50. </span> * @cfg {Number} defaultWidth
  51. * Width of the header if no width or flex is specified.
  52. */
  53. defaultWidth: 100,
  54. <span id='Ext-grid-header-Container-cfg-sealed'> /**
  55. </span> * @cfg {Boolean} [sealed=false]
  56. * Specify as `true` to constrain column dragging so that a column cannot be dragged into or out of this column.
  57. *
  58. * **Note that this config is only valid for column headers which contain child column headers, eg:**
  59. * {
  60. * sealed: true
  61. * text: 'ExtJS',
  62. * columns: [{
  63. * text: '3.0.4',
  64. * dataIndex: 'ext304'
  65. * }, {
  66. * text: '4.1.0',
  67. * dataIndex: 'ext410'
  68. * }
  69. * }
  70. *
  71. */
  72. //&lt;locale&gt;
  73. sortAscText: 'Sort Ascending',
  74. //&lt;/locale&gt;
  75. //&lt;locale&gt;
  76. sortDescText: 'Sort Descending',
  77. //&lt;/locale&gt;
  78. //&lt;locale&gt;
  79. sortClearText: 'Clear Sort',
  80. //&lt;/locale&gt;
  81. //&lt;locale&gt;
  82. columnsText: 'Columns',
  83. //&lt;/locale&gt;
  84. headerOpenCls: Ext.baseCSSPrefix + 'column-header-open',
  85. // private; will probably be removed by 4.0
  86. triStateSort: false,
  87. ddLock: false,
  88. dragging: false,
  89. <span id='Ext-grid-header-Container-property-isGroupHeader'> /**
  90. </span> * @property {Boolean} isGroupHeader
  91. * True if this HeaderContainer is in fact a group header which contains sub headers.
  92. */
  93. <span id='Ext-grid-header-Container-cfg-sortable'> /**
  94. </span> * @cfg {Boolean} sortable
  95. * Provides the default sortable state for all Headers within this HeaderContainer.
  96. * Also turns on or off the menus in the HeaderContainer. Note that the menu is
  97. * shared across every header and therefore turning it off will remove the menu
  98. * items for every header.
  99. */
  100. sortable: true,
  101. initComponent: function() {
  102. var me = this;
  103. me.headerCounter = 0;
  104. me.plugins = me.plugins || [];
  105. // TODO: Pass in configurations to turn on/off dynamic
  106. // resizing and disable resizing all together
  107. // Only set up a Resizer and Reorderer for the topmost HeaderContainer.
  108. // Nested Group Headers are themselves HeaderContainers
  109. if (!me.isHeader) {
  110. if (me.enableColumnResize) {
  111. me.resizer = new Ext.grid.plugin.HeaderResizer();
  112. me.plugins.push(me.resizer);
  113. }
  114. if (me.enableColumnMove) {
  115. me.reorderer = new Ext.grid.plugin.HeaderReorderer();
  116. me.plugins.push(me.reorderer);
  117. }
  118. }
  119. // Base headers do not need a box layout
  120. if (me.isHeader &amp;&amp; !me.items) {
  121. me.layout = me.layout || 'auto';
  122. }
  123. // HeaderContainer and Group header needs a gridcolumn layout.
  124. else {
  125. me.layout = Ext.apply({
  126. type: 'gridcolumn',
  127. align: 'stretchmax'
  128. }, me.initialConfig.layout);
  129. }
  130. me.defaults = me.defaults || {};
  131. Ext.applyIf(me.defaults, {
  132. triStateSort: me.triStateSort,
  133. sortable: me.sortable
  134. });
  135. me.menuTask = new Ext.util.DelayedTask(me.updateMenuDisabledState, me);
  136. me.callParent();
  137. me.addEvents(
  138. <span id='Ext-grid-header-Container-event-columnresize'> /**
  139. </span> * @event columnresize
  140. * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
  141. * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
  142. * @param {Number} width
  143. */
  144. 'columnresize',
  145. <span id='Ext-grid-header-Container-event-headerclick'> /**
  146. </span> * @event headerclick
  147. * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
  148. * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
  149. * @param {Ext.EventObject} e
  150. * @param {HTMLElement} t
  151. */
  152. 'headerclick',
  153. <span id='Ext-grid-header-Container-event-headertriggerclick'> /**
  154. </span> * @event headertriggerclick
  155. * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
  156. * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
  157. * @param {Ext.EventObject} e
  158. * @param {HTMLElement} t
  159. */
  160. 'headertriggerclick',
  161. <span id='Ext-grid-header-Container-event-columnmove'> /**
  162. </span> * @event columnmove
  163. * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
  164. * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
  165. * @param {Number} fromIdx
  166. * @param {Number} toIdx
  167. */
  168. 'columnmove',
  169. <span id='Ext-grid-header-Container-event-columnhide'> /**
  170. </span> * @event columnhide
  171. * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
  172. * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
  173. */
  174. 'columnhide',
  175. <span id='Ext-grid-header-Container-event-columnshow'> /**
  176. </span> * @event columnshow
  177. * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
  178. * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
  179. */
  180. 'columnshow',
  181. <span id='Ext-grid-header-Container-event-sortchange'> /**
  182. </span> * @event sortchange
  183. * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
  184. * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
  185. * @param {String} direction
  186. */
  187. 'sortchange',
  188. <span id='Ext-grid-header-Container-event-menucreate'> /**
  189. </span> * @event menucreate
  190. * Fired immediately after the column header menu is created.
  191. * @param {Ext.grid.header.Container} ct This instance
  192. * @param {Ext.menu.Menu} menu The Menu that was created
  193. */
  194. 'menucreate'
  195. );
  196. },
  197. onDestroy: function() {
  198. var me = this;
  199. me.menuTask.cancel();
  200. Ext.destroy(me.resizer, me.reorderer);
  201. me.callParent();
  202. },
  203. applyColumnsState: function(columns) {
  204. if (!columns || !columns.length) {
  205. return;
  206. }
  207. var me = this,
  208. items = me.items.items,
  209. count = items.length,
  210. i = 0,
  211. length = columns.length,
  212. c, col, columnState, index;
  213. for (c = 0; c &lt; length; c++) {
  214. columnState = columns[c];
  215. for (index = count; index--; ) {
  216. col = items[index];
  217. if (col.getStateId &amp;&amp; col.getStateId() == columnState.id) {
  218. // If a column in the new grid matches up with a saved state...
  219. // Ensure that the column is restored to the state order.
  220. // i is incremented upon every column match, so all persistent
  221. // columns are ordered before any new columns.
  222. if (i !== index) {
  223. me.moveHeader(index, i);
  224. }
  225. if (col.applyColumnState) {
  226. col.applyColumnState(columnState);
  227. }
  228. ++i;
  229. break;
  230. }
  231. }
  232. }
  233. },
  234. getColumnsState: function () {
  235. var me = this,
  236. columns = [],
  237. state;
  238. me.items.each(function (col) {
  239. state = col.getColumnState &amp;&amp; col.getColumnState();
  240. if (state) {
  241. columns.push(state);
  242. }
  243. });
  244. return columns;
  245. },
  246. // Invalidate column cache on add
  247. // We cannot refresh the View on every add because this method is called
  248. // when the HeaderDropZone moves Headers around, that will also refresh the view
  249. onAdd: function(c) {
  250. var me = this,
  251. headerCt = me.isHeader ? me.getOwnerHeaderCt() : me;
  252. if (!c.headerId) {
  253. c.headerId = c.initialConfig.id || Ext.id(null, 'header-');
  254. }
  255. if (!c.stateId) {
  256. // This was the headerId generated in 4.0, so to preserve saved state, we now
  257. // assign a default stateId in that same manner. The stateId's of a column are
  258. // not global at the stateProvider, but are local to the grid state data. The
  259. // headerId should still follow our standard naming convention.
  260. c.stateId = c.initialConfig.id || ('h' + (++me.headerCounter));
  261. }
  262. //&lt;debug warn&gt;
  263. if (Ext.global.console &amp;&amp; Ext.global.console.warn) {
  264. if (!me._usedIDs) {
  265. me._usedIDs = {};
  266. }
  267. if (me._usedIDs[c.headerId]) {
  268. Ext.global.console.warn(this.$className, 'attempted to reuse an existing id', c.headerId);
  269. }
  270. me._usedIDs[c.headerId] = true;
  271. }
  272. //&lt;/debug&gt;
  273. me.callParent(arguments);
  274. // Upon add of any column we need to purge the *HeaderContainer's* cache of leaf view columns.
  275. if (headerCt) {
  276. headerCt.purgeCache();
  277. }
  278. },
  279. // Invalidate column cache on remove
  280. // We cannot refresh the View on every remove because this method is called
  281. // when the HeaderDropZone moves Headers around, that will also refresh the view
  282. onRemove: function(c) {
  283. var me = this,
  284. headerCt = me.isHeader ? me.getOwnerHeaderCt() : me;
  285. me.callParent(arguments);
  286. //&lt;debug warn&gt;
  287. if (!me._usedIDs) {
  288. me._usedIDs = {};
  289. }
  290. delete me._usedIDs[c.headerId];
  291. //&lt;/debug&gt;
  292. // Upon removal of any column we need to purge the *HeaderContainer's* cache of leaf view columns.
  293. if (headerCt) {
  294. me.purgeCache();
  295. }
  296. },
  297. // @private
  298. applyDefaults: function(config) {
  299. var ret;
  300. /*
  301. * Ensure header.Container defaults don't get applied to a RowNumberer
  302. * if an xtype is supplied. This isn't an ideal solution however it's
  303. * much more likely that a RowNumberer with no options will be created,
  304. * wanting to use the defaults specified on the class as opposed to
  305. * those setup on the Container.
  306. */
  307. if (config &amp;&amp; !config.isComponent &amp;&amp; config.xtype == 'rownumberer') {
  308. ret = config;
  309. } else {
  310. ret = this.callParent(arguments);
  311. // Apply default width unless it's a group header (in which case it must be left to shrinkwrap), or it's flexed
  312. if (!config.isGroupHeader &amp;&amp; !('width' in ret) &amp;&amp; !ret.flex) {
  313. ret.width = this.defaultWidth;
  314. }
  315. }
  316. return ret;
  317. },
  318. afterRender: function() {
  319. this.callParent();
  320. this.setSortState();
  321. },
  322. setSortState: function(){
  323. var store = this.up('[store]').store,
  324. // grab the first sorter, since there may also be groupers
  325. // in this collection
  326. first = store.getFirstSorter(),
  327. hd;
  328. if (first) {
  329. hd = this.down('gridcolumn[dataIndex=' + first.property +']');
  330. if (hd) {
  331. hd.setSortState(first.direction, false, true);
  332. }
  333. } else {
  334. this.clearOtherSortStates(null);
  335. }
  336. },
  337. getHeaderMenu: function(){
  338. var menu = this.getMenu(),
  339. item;
  340. if (menu) {
  341. item = menu.child('#columnItem');
  342. if (item) {
  343. return item.menu;
  344. }
  345. }
  346. return null;
  347. },
  348. onHeaderVisibilityChange: function(header, visible){
  349. var me = this,
  350. menu = me.getHeaderMenu(),
  351. item;
  352. if (menu) {
  353. // If the header was hidden programmatically, sync the Menu state
  354. item = me.getMenuItemForHeader(menu, header);
  355. if (item) {
  356. item.setChecked(visible, true);
  357. }
  358. // delay this since the headers may fire a number of times if we're hiding/showing groups
  359. me.menuTask.delay(50);
  360. }
  361. },
  362. <span id='Ext-grid-header-Container-method-getLeafMenuItems'> /**
  363. </span> * @private
  364. * Gets all &quot;leaf&quot; menu nodes and returns the checked count for those leaves.
  365. * Only includes columns that are hideable via the menu
  366. */
  367. getLeafMenuItems: function() {
  368. var me = this,
  369. columns = me.getGridColumns(),
  370. items = [],
  371. i = 0,
  372. count = 0,
  373. len = columns.length,
  374. menu = me.getMenu(),
  375. item;
  376. for (; i &lt; len; ++i) {
  377. item = columns[i];
  378. if (item.hideable) {
  379. item = me.getMenuItemForHeader(menu, item);
  380. if (item) {
  381. items.push(item);
  382. if (item.checked) {
  383. ++count;
  384. }
  385. }
  386. } else if (!item.hidden &amp;&amp; !item.menuDisabled) {
  387. ++count;
  388. }
  389. }
  390. return {
  391. items: items,
  392. checkedCount: count
  393. };
  394. },
  395. updateMenuDisabledState: function(){
  396. var me = this,
  397. result = me.getLeafMenuItems(),
  398. total = result.checkedCount,
  399. items = result.items,
  400. len = items.length,
  401. i = 0,
  402. rootItem = me.getMenu().child('#columnItem');
  403. if (total &lt;= 1) {
  404. // only one column visible, prevent hiding of the remaining item
  405. me.disableMenuItems(rootItem, Ext.ComponentQuery.query('[checked=true]', items)[0]);
  406. } else {
  407. // at least 2 visible, set the state appropriately
  408. for (; i &lt; len; ++i) {
  409. me.setMenuItemState(total, rootItem, items[i]);
  410. }
  411. }
  412. },
  413. disableMenuItems: function(rootItem, item){
  414. while (item &amp;&amp; item != rootItem) {
  415. item.disableCheckChange();
  416. item = item.parentMenu.ownerItem;
  417. }
  418. },
  419. setMenuItemState: function(total, rootItem, item){
  420. var parentMenu,
  421. checkedChildren;
  422. while (item &amp;&amp; item != rootItem) {
  423. parentMenu = item.parentMenu;
  424. checkedChildren = item.parentMenu.query('[checked=true]:not([menu])').length;
  425. item.enableCheckChange();
  426. item = parentMenu.ownerItem;
  427. if (checkedChildren === total) {
  428. // contains all the checked children, jump out the item and all parents
  429. break;
  430. }
  431. }
  432. // while we're not at the top, disable from the current item up
  433. this.disableMenuItems(rootItem, item);
  434. },
  435. getMenuItemForHeader: function(menu, header){
  436. return header ? menu.down('menucheckitem[headerId=' + header.id + ']') : null;
  437. },
  438. onHeaderShow: function(header) {
  439. // Pass up to the GridSection
  440. var me = this,
  441. gridSection = me.ownerCt;
  442. me.onHeaderVisibilityChange(header, true);
  443. // Only update the grid UI when we are notified about base level Header shows;
  444. // Group header shows just cause a layout of the HeaderContainer
  445. if (!header.isGroupHeader) {
  446. if (gridSection) {
  447. gridSection.onHeaderShow(me, header);
  448. }
  449. }
  450. me.fireEvent('columnshow', me, header);
  451. },
  452. onHeaderHide: function(header) {
  453. // Pass up to the GridSection
  454. var me = this,
  455. gridSection = me.ownerCt;
  456. me.onHeaderVisibilityChange(header, false);
  457. // Only update the UI when we are notified about base level Header hides;
  458. if (!header.isGroupHeader) {
  459. if (gridSection) {
  460. gridSection.onHeaderHide(me, header);
  461. }
  462. }
  463. me.fireEvent('columnhide', me, header);
  464. },
  465. <span id='Ext-grid-header-Container-method-tempLock'> /**
  466. </span> * Temporarily lock the headerCt. This makes it so that clicking on headers
  467. * don't trigger actions like sorting or opening of the header menu. This is
  468. * done because extraneous events may be fired on the headers after interacting
  469. * with a drag drop operation.
  470. * @private
  471. */
  472. tempLock: function() {
  473. this.ddLock = true;
  474. Ext.Function.defer(function() {
  475. this.ddLock = false;
  476. }, 200, this);
  477. },
  478. onHeaderResize: function(header, w, suppressFocus) {
  479. var me = this,
  480. view = me.view,
  481. gridSection = me.ownerCt;
  482. // Do not react to header sizing during initial Panel layout when there is no view content to size.
  483. if (view &amp;&amp; view.table.dom) {
  484. me.tempLock();
  485. if (gridSection) {
  486. gridSection.onHeaderResize(me, header, w);
  487. }
  488. }
  489. me.fireEvent('columnresize', this, header, w);
  490. },
  491. onHeaderClick: function(header, e, t) {
  492. header.fireEvent('headerclick', this, header, e, t);
  493. this.fireEvent(&quot;headerclick&quot;, this, header, e, t);
  494. },
  495. onHeaderTriggerClick: function(header, e, t) {
  496. // generate and cache menu, provide ability to cancel/etc
  497. var me = this;
  498. if (header.fireEvent('headertriggerclick', me, header, e, t) !== false &amp;&amp; me.fireEvent(&quot;headertriggerclick&quot;, me, header, e, t) !== false) {
  499. me.showMenuBy(t, header);
  500. }
  501. },
  502. showMenuBy: function(t, header) {
  503. var menu = this.getMenu(),
  504. ascItem = menu.down('#ascItem'),
  505. descItem = menu.down('#descItem'),
  506. sortableMth;
  507. menu.activeHeader = menu.ownerCt = header;
  508. menu.setFloatParent(header);
  509. // TODO: remove coupling to Header's titleContainer el
  510. header.titleEl.addCls(this.headerOpenCls);
  511. // enable or disable asc &amp; desc menu items based on header being sortable
  512. sortableMth = header.sortable ? 'enable' : 'disable';
  513. if (ascItem) {
  514. ascItem[sortableMth]();
  515. }
  516. if (descItem) {
  517. descItem[sortableMth]();
  518. }
  519. menu.showBy(t);
  520. },
  521. // remove the trigger open class when the menu is hidden
  522. onMenuDeactivate: function() {
  523. var menu = this.getMenu();
  524. // TODO: remove coupling to Header's titleContainer el
  525. menu.activeHeader.titleEl.removeCls(this.headerOpenCls);
  526. },
  527. moveHeader: function(fromIdx, toIdx) {
  528. // An automatically expiring lock
  529. this.tempLock();
  530. this.onHeaderMoved(this.move(fromIdx, toIdx), 1, fromIdx, toIdx);
  531. },
  532. purgeCache: function() {
  533. var me = this;
  534. // Delete column cache - column order has changed.
  535. delete me.gridDataColumns;
  536. delete me.hideableColumns;
  537. // Menu changes when columns are moved. It will be recreated.
  538. if (me.menu) {
  539. // Must hide before destroy so that trigger el is deactivated
  540. me.menu.hide();
  541. me.menu.destroy();
  542. delete me.menu;
  543. }
  544. },
  545. onHeaderMoved: function(header, colsToMove, fromIdx, toIdx) {
  546. var me = this,
  547. gridSection = me.ownerCt;
  548. if (gridSection &amp;&amp; gridSection.onHeaderMove) {
  549. gridSection.onHeaderMove(me, header, colsToMove, fromIdx, toIdx);
  550. }
  551. me.fireEvent(&quot;columnmove&quot;, me, header, fromIdx, toIdx);
  552. },
  553. <span id='Ext-grid-header-Container-method-getMenu'> /**
  554. </span> * Gets the menu (and will create it if it doesn't already exist)
  555. * @private
  556. */
  557. getMenu: function() {
  558. var me = this;
  559. if (!me.menu) {
  560. me.menu = new Ext.menu.Menu({
  561. hideOnParentHide: false, // Persists when owning ColumnHeader is hidden
  562. items: me.getMenuItems(),
  563. listeners: {
  564. deactivate: me.onMenuDeactivate,
  565. scope: me
  566. }
  567. });
  568. me.updateMenuDisabledState();
  569. me.fireEvent('menucreate', me, me.menu);
  570. }
  571. return me.menu;
  572. },
  573. <span id='Ext-grid-header-Container-method-getMenuItems'> /**
  574. </span> * Returns an array of menu items to be placed into the shared menu
  575. * across all headers in this header container.
  576. * @returns {Array} menuItems
  577. */
  578. getMenuItems: function() {
  579. var me = this,
  580. menuItems = [],
  581. hideableColumns = me.enableColumnHide ? me.getColumnMenu(me) : null;
  582. if (me.sortable) {
  583. menuItems = [{
  584. itemId: 'ascItem',
  585. text: me.sortAscText,
  586. cls: Ext.baseCSSPrefix + 'hmenu-sort-asc',
  587. handler: me.onSortAscClick,
  588. scope: me
  589. },{
  590. itemId: 'descItem',
  591. text: me.sortDescText,
  592. cls: Ext.baseCSSPrefix + 'hmenu-sort-desc',
  593. handler: me.onSortDescClick,
  594. scope: me
  595. }];
  596. }
  597. if (hideableColumns &amp;&amp; hideableColumns.length) {
  598. menuItems.push('-', {
  599. itemId: 'columnItem',
  600. text: me.columnsText,
  601. cls: Ext.baseCSSPrefix + 'cols-icon',
  602. menu: hideableColumns
  603. });
  604. }
  605. return menuItems;
  606. },
  607. // sort asc when clicking on item in menu
  608. onSortAscClick: function() {
  609. var menu = this.getMenu(),
  610. activeHeader = menu.activeHeader;
  611. activeHeader.setSortState('ASC');
  612. },
  613. // sort desc when clicking on item in menu
  614. onSortDescClick: function() {
  615. var menu = this.getMenu(),
  616. activeHeader = menu.activeHeader;
  617. activeHeader.setSortState('DESC');
  618. },
  619. <span id='Ext-grid-header-Container-method-getColumnMenu'> /**
  620. </span> * Returns an array of menu CheckItems corresponding to all immediate children
  621. * of the passed Container which have been configured as hideable.
  622. */
  623. getColumnMenu: function(headerContainer) {
  624. var menuItems = [],
  625. i = 0,
  626. item,
  627. items = headerContainer.query('&gt;gridcolumn[hideable]'),
  628. itemsLn = items.length,
  629. menuItem;
  630. for (; i &lt; itemsLn; i++) {
  631. item = items[i];
  632. menuItem = new Ext.menu.CheckItem({
  633. text: item.menuText || item.text,
  634. checked: !item.hidden,
  635. hideOnClick: false,
  636. headerId: item.id,
  637. menu: item.isGroupHeader ? this.getColumnMenu(item) : undefined,
  638. checkHandler: this.onColumnCheckChange,
  639. scope: this
  640. });
  641. menuItems.push(menuItem);
  642. // If the header is ever destroyed - for instance by dragging out the last remaining sub header,
  643. // then the associated menu item must also be destroyed.
  644. item.on({
  645. destroy: Ext.Function.bind(menuItem.destroy, menuItem)
  646. });
  647. }
  648. return menuItems;
  649. },
  650. onColumnCheckChange: function(checkItem, checked) {
  651. var header = Ext.getCmp(checkItem.headerId);
  652. header[checked ? 'show' : 'hide']();
  653. },
  654. <span id='Ext-grid-header-Container-method-getColumnsForTpl'> /**
  655. </span> * Get the columns used for generating a template via TableChunker.
  656. * Returns an array of all columns and their
  657. *
  658. * - dataIndex
  659. * - align
  660. * - width
  661. * - id
  662. * - columnId - used to create an identifying CSS class
  663. * - cls The tdCls configuration from the Column object
  664. *
  665. * @private
  666. */
  667. getColumnsForTpl: function(flushCache) {
  668. var cols = [],
  669. headers = this.getGridColumns(flushCache),
  670. headersLn = headers.length,
  671. i = 0,
  672. header,
  673. width;
  674. for (; i &lt; headersLn; i++) {
  675. header = headers[i];
  676. if (header.hidden || header.up('headercontainer[hidden=true]')) {
  677. width = 0;
  678. } else {
  679. width = header.getDesiredWidth();
  680. }
  681. cols.push({
  682. dataIndex: header.dataIndex,
  683. align: header.align,
  684. width: width,
  685. id: header.id,
  686. cls: header.tdCls,
  687. columnId: header.getItemId()
  688. });
  689. }
  690. return cols;
  691. },
  692. <span id='Ext-grid-header-Container-method-getColumnCount'> /**
  693. </span> * Returns the number of &lt;b&gt;grid columns&lt;/b&gt; descended from this HeaderContainer.
  694. * Group Columns are HeaderContainers. All grid columns are returned, including hidden ones.
  695. */
  696. getColumnCount: function() {
  697. return this.getGridColumns().length;
  698. },
  699. <span id='Ext-grid-header-Container-method-getFullWidth'> /**
  700. </span> * Gets the full width of all columns that are visible.
  701. */
  702. getFullWidth: function(flushCache) {
  703. var fullWidth = 0,
  704. headers = this.getVisibleGridColumns(flushCache),
  705. headersLn = headers.length,
  706. i = 0,
  707. header;
  708. for (; i &lt; headersLn; i++) {
  709. header = headers[i];
  710. // use headers getDesiredWidth if its there
  711. if (header.getDesiredWidth) {
  712. fullWidth += header.getDesiredWidth() || 0;
  713. // if injected a diff cmp use getWidth
  714. } else {
  715. fullWidth += header.getWidth();
  716. }
  717. }
  718. return fullWidth;
  719. },
  720. // invoked internally by a header when not using triStateSorting
  721. clearOtherSortStates: function(activeHeader) {
  722. var headers = this.getGridColumns(),
  723. headersLn = headers.length,
  724. i = 0;
  725. for (; i &lt; headersLn; i++) {
  726. if (headers[i] !== activeHeader) {
  727. // unset the sortstate and dont recurse
  728. headers[i].setSortState(null, true);
  729. }
  730. }
  731. },
  732. <span id='Ext-grid-header-Container-method-getVisibleGridColumns'> /**
  733. </span> * Returns an array of the **visible** columns in the grid. This goes down to the lowest column header
  734. * level, and does not return **grouped** headers which contain sub headers.
  735. * @param {Boolean} refreshCache If omitted, the cached set of columns will be returned. Pass true to refresh the cache.
  736. * @returns {Array}
  737. */
  738. getVisibleGridColumns: function(refreshCache) {
  739. return Ext.ComponentQuery.query(':not([hidden])', this.getGridColumns(refreshCache));
  740. },
  741. <span id='Ext-grid-header-Container-method-getGridColumns'> /**
  742. </span> * Returns an array of all columns which map to Store fields. This goes down to the lowest column header
  743. * level, and does not return **grouped** headers which contain sub headers.
  744. * @param {Boolean} refreshCache If omitted, the cached set of columns will be returned. Pass true to refresh the cache.
  745. * @returns {Array}
  746. */
  747. getGridColumns: function(refreshCache) {
  748. var me = this,
  749. result = refreshCache ? null : me.gridDataColumns;
  750. // Not already got the column cache, so collect the base columns
  751. if (!result) {
  752. me.gridDataColumns = result = [];
  753. me.cascade(function(c) {
  754. if ((c !== me) &amp;&amp; !c.isGroupHeader) {
  755. result.push(c);
  756. }
  757. });
  758. }
  759. return result;
  760. },
  761. <span id='Ext-grid-header-Container-method-getHideableColumns'> /**
  762. </span> * @private
  763. * For use by column headers in determining whether there are any hideable columns when deciding whether or not
  764. * the header menu should be disabled.
  765. */
  766. getHideableColumns: function(refreshCache) {
  767. var me = this,
  768. result = refreshCache ? null : me.hideableColumns;
  769. if (!result) {
  770. result = me.hideableColumns = me.query('[hideable]');
  771. }
  772. return result;
  773. },
  774. <span id='Ext-grid-header-Container-method-getHeaderIndex'> /**
  775. </span> * Returns the index of a leaf level header regardless of what the nesting
  776. * structure is.
  777. *
  778. * If a group header is passed, the index of the first leaf level heder within it is returned.
  779. *
  780. * @param {Ext.grid.column.Column} header The header to find the index of
  781. * @return {Number} The index of the specified column header
  782. */
  783. getHeaderIndex: function(header) {
  784. // If we are being asked the index of a group header, find the first leaf header node, and return the index of that
  785. if (header.isGroupHeader) {
  786. header = header.down(':not([isgroupHeader])');
  787. }
  788. return Ext.Array.indexOf(this.getGridColumns(), header);
  789. },
  790. <span id='Ext-grid-header-Container-method-getHeaderAtIndex'> /**
  791. </span> * Get a leaf level header by index regardless of what the nesting
  792. * structure is.
  793. * @param {Number} The column index for which to retrieve the column.
  794. */
  795. getHeaderAtIndex: function(index) {
  796. var columns = this.getGridColumns();
  797. return columns.length ? columns[index] : null;
  798. },
  799. <span id='Ext-grid-header-Container-method-getVisibleHeaderClosestToIndex'> /**
  800. </span> * When passed a column index, returns the closet *visible* column to that. If the column at the passed index is visible,
  801. * that is returned. If it is hidden, either the next visible, or the previous visible column is returned.
  802. * @param {Number} index Position at which to find the closest visible column.
  803. */
  804. getVisibleHeaderClosestToIndex: function(index) {
  805. var result = this.getHeaderAtIndex(index);
  806. if (result &amp;&amp; result.hidden) {
  807. result = result.next(':not([hidden])') || result.prev(':not([hidden])');
  808. }
  809. return result;
  810. },
  811. <span id='Ext-grid-header-Container-method-prepareData'> /**
  812. </span> * Maps the record data to base it on the header id's.
  813. * This correlates to the markup/template generated by
  814. * TableChunker.
  815. */
  816. prepareData: function(data, rowIdx, record, view, panel) {
  817. var me = this,
  818. obj = {},
  819. headers = me.gridDataColumns || me.getGridColumns(),
  820. headersLn = headers.length,
  821. colIdx = 0,
  822. header,
  823. headerId,
  824. renderer,
  825. value,
  826. metaData,
  827. store = panel.store;
  828. for (; colIdx &lt; headersLn; colIdx++) {
  829. metaData = {
  830. tdCls: '',
  831. style: ''
  832. };
  833. header = headers[colIdx];
  834. headerId = header.id;
  835. renderer = header.renderer;
  836. value = data[header.dataIndex];
  837. if (typeof renderer == &quot;function&quot;) {
  838. value = renderer.call(
  839. header.scope || me.ownerCt,
  840. value,
  841. // metadata per cell passing an obj by reference so that
  842. // it can be manipulated inside the renderer
  843. metaData,
  844. record,
  845. rowIdx,
  846. colIdx,
  847. store,
  848. view
  849. );
  850. }
  851. // &lt;debug&gt;
  852. if (metaData.css) {
  853. // This warning attribute is used by the compat layer
  854. obj.cssWarning = true;
  855. metaData.tdCls = metaData.css;
  856. delete metaData.css;
  857. }
  858. // &lt;/debug&gt;
  859. if (me.markDirty) {
  860. obj[headerId + '-modified'] = record.isModified(header.dataIndex) ? Ext.baseCSSPrefix + 'grid-dirty-cell' : '';
  861. }
  862. obj[headerId+'-tdCls'] = metaData.tdCls;
  863. obj[headerId+'-tdAttr'] = metaData.tdAttr;
  864. obj[headerId+'-style'] = metaData.style;
  865. if (typeof value === 'undefined' || value === null || value === '') {
  866. value = header.emptyCellText;
  867. }
  868. obj[headerId] = value;
  869. }
  870. return obj;
  871. },
  872. expandToFit: function(header) {
  873. var view = this.view;
  874. if (view) {
  875. view.expandToFit(header);
  876. }
  877. }
  878. });
  879. </pre>
  880. </body>
  881. </html>