Menu.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  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-boxOverflow-Menu'>/**
  19. </span> * @private
  20. */
  21. Ext.define('Ext.layout.container.boxOverflow.Menu', {
  22. /* Begin Definitions */
  23. extend: 'Ext.layout.container.boxOverflow.None',
  24. requires: ['Ext.toolbar.Separator', 'Ext.button.Button'],
  25. alternateClassName: 'Ext.layout.boxOverflow.Menu',
  26. /* End Definitions */
  27. <span id='Ext-layout-container-boxOverflow-Menu-cfg-triggerButtonCls'> /**
  28. </span> * @cfg {String} triggerButtonCls
  29. * CSS class added to the Button which shows the overflow menu.
  30. */
  31. <span id='Ext-layout-container-boxOverflow-Menu-property-noItemsMenuText'> /**
  32. </span> * @property {String} noItemsMenuText
  33. * HTML fragment to render into the toolbar overflow menu if there are no items to display
  34. */
  35. noItemsMenuText : '&lt;div class=&quot;' + Ext.baseCSSPrefix + 'toolbar-no-items&quot;&gt;(None)&lt;/div&gt;',
  36. constructor: function(layout) {
  37. var me = this;
  38. me.callParent(arguments);
  39. me.triggerButtonCls = me.triggerButtonCls || Ext.baseCSSPrefix + 'box-menu-' + layout.getNames().right;
  40. <span id='Ext-layout-container-boxOverflow-Menu-property-menuItems'> /**
  41. </span> * @property {Array} menuItems
  42. * Array of all items that are currently hidden and should go into the dropdown menu
  43. */
  44. me.menuItems = [];
  45. },
  46. beginLayout: function (ownerContext) {
  47. this.callParent(arguments);
  48. // Before layout, we need to re-show all items which we may have hidden due to a
  49. // previous overflow...
  50. this.clearOverflow(ownerContext);
  51. },
  52. beginLayoutCycle: function (ownerContext, firstCycle) {
  53. this.callParent(arguments);
  54. if (!firstCycle) {
  55. // if we are being re-run, we need to clear any overflow from the last run and
  56. // recache the childItems collection
  57. this.clearOverflow(ownerContext);
  58. this.layout.cacheChildItems(ownerContext);
  59. }
  60. },
  61. onRemove: function(comp){
  62. Ext.Array.remove(this.menuItems, comp);
  63. },
  64. // We don't define a prefix in menu overflow.
  65. getSuffixConfig: function() {
  66. var me = this,
  67. layout = me.layout,
  68. oid = layout.owner.id;
  69. <span id='Ext-layout-container-boxOverflow-Menu-property-menu'> /**
  70. </span> * @private
  71. * @property {Ext.menu.Menu} menu
  72. * The expand menu - holds items for every item that cannot be shown
  73. * because the container is currently not large enough.
  74. */
  75. me.menu = new Ext.menu.Menu({
  76. listeners: {
  77. scope: me,
  78. beforeshow: me.beforeMenuShow
  79. }
  80. });
  81. <span id='Ext-layout-container-boxOverflow-Menu-property-menuTrigger'> /**
  82. </span> * @private
  83. * @property {Ext.button.Button} menuTrigger
  84. * The expand button which triggers the overflow menu to be shown
  85. */
  86. me.menuTrigger = new Ext.button.Button({
  87. id : oid + '-menu-trigger',
  88. cls : Ext.layout.container.Box.prototype.innerCls + ' ' + me.triggerButtonCls,
  89. hidden : true,
  90. ownerCt : layout.owner, // To enable the Menu to ascertain a valid zIndexManager owner in the same tree
  91. ownerLayout: layout,
  92. iconCls : Ext.baseCSSPrefix + me.getOwnerType(layout.owner) + '-more-icon',
  93. ui : layout.owner instanceof Ext.toolbar.Toolbar ? 'default-toolbar' : 'default',
  94. menu : me.menu,
  95. getSplitCls: function() { return '';}
  96. });
  97. return me.menuTrigger.getRenderTree();
  98. },
  99. getOverflowCls: function() {
  100. return Ext.baseCSSPrefix + this.layout.direction + '-box-overflow-body';
  101. },
  102. handleOverflow: function(ownerContext) {
  103. var me = this,
  104. layout = me.layout,
  105. names = layout.getNames(),
  106. plan = ownerContext.state.boxPlan,
  107. posArgs = [null, null];
  108. me.showTrigger(ownerContext);
  109. // Center the menuTrigger button.
  110. // TODO: Should we emulate align: 'middle' like this, or should we 'stretchmax' the menuTrigger?
  111. posArgs[names.heightIndex] = (plan.maxSize - me.menuTrigger[names.getHeight]()) / 2;
  112. me.menuTrigger.setPosition.apply(me.menuTrigger, posArgs);
  113. return {
  114. reservedSpace: me.menuTrigger[names.getWidth]()
  115. };
  116. },
  117. <span id='Ext-layout-container-boxOverflow-Menu-method-captureChildElements'> /**
  118. </span> * Finishes the render operation of the trigger Button.
  119. * @private
  120. */
  121. captureChildElements: function() {
  122. var menuTrigger = this.menuTrigger;
  123. if (menuTrigger.rendering) {
  124. menuTrigger.finishRender();
  125. }
  126. },
  127. _asLayoutRoot: { isRoot: true },
  128. <span id='Ext-layout-container-boxOverflow-Menu-method-clearOverflow'> /**
  129. </span> * @private
  130. * Called by the layout, when it determines that there is no overflow.
  131. * Also called as an interceptor to the layout's onLayout method to reshow
  132. * previously hidden overflowing items.
  133. */
  134. clearOverflow: function(ownerContext) {
  135. var me = this,
  136. items = me.menuItems,
  137. item,
  138. i = 0,
  139. length = items.length,
  140. owner = me.layout.owner,
  141. asLayoutRoot = me._asLayoutRoot;
  142. owner.suspendLayouts();
  143. me.captureChildElements();
  144. me.hideTrigger();
  145. owner.resumeLayouts();
  146. for (; i &lt; length; i++) {
  147. item = items[i];
  148. // What we are doing here is preventing the layout bubble from invalidating our
  149. // owner component. We need just the button to be added to the layout run.
  150. item.suspendLayouts();
  151. item.show();
  152. item.resumeLayouts(asLayoutRoot);
  153. }
  154. items.length = 0;
  155. },
  156. <span id='Ext-layout-container-boxOverflow-Menu-method-showTrigger'> /**
  157. </span> * @private
  158. * Shows the overflow trigger when enableOverflow is set to true and the items
  159. * in the layout are too wide to fit in the space available
  160. */
  161. showTrigger: function(ownerContext) {
  162. var me = this,
  163. layout = me.layout,
  164. owner = layout.owner,
  165. names = layout.getNames(),
  166. startProp = names.x,
  167. sizeProp = names.width,
  168. plan = ownerContext.state.boxPlan,
  169. available = plan.targetSize[sizeProp],
  170. childItems = ownerContext.childItems,
  171. len = childItems.length,
  172. menuTrigger = me.menuTrigger,
  173. childContext,
  174. comp, i, props;
  175. // We don't want the menuTrigger.show to cause owner's layout to be invalidated, so
  176. // we force just the button to be invalidated and added to the current run.
  177. menuTrigger.suspendLayouts();
  178. menuTrigger.show();
  179. menuTrigger.resumeLayouts(me._asLayoutRoot);
  180. available -= me.menuTrigger.getWidth();
  181. owner.suspendLayouts();
  182. // Hide all items which are off the end, and store them to allow them to be restored
  183. // before each layout operation.
  184. me.menuItems.length = 0;
  185. for (i = 0; i &lt; len; i++) {
  186. childContext = childItems[i];
  187. props = childContext.props;
  188. if (props[startProp] + props[sizeProp] &gt; available) {
  189. comp = childContext.target;
  190. me.menuItems.push(comp);
  191. comp.hide();
  192. }
  193. }
  194. owner.resumeLayouts();
  195. },
  196. <span id='Ext-layout-container-boxOverflow-Menu-method-hideTrigger'> /**
  197. </span> * @private
  198. */
  199. hideTrigger: function() {
  200. var menuTrigger = this.menuTrigger;
  201. if (menuTrigger) {
  202. menuTrigger.hide();
  203. }
  204. },
  205. <span id='Ext-layout-container-boxOverflow-Menu-method-beforeMenuShow'> /**
  206. </span> * @private
  207. * Called before the overflow menu is shown. This constructs the menu's items, caching them for as long as it can.
  208. */
  209. beforeMenuShow: function(menu) {
  210. var me = this,
  211. items = me.menuItems,
  212. i = 0,
  213. len = items.length,
  214. item,
  215. prev,
  216. needsSep = function(group, prev){
  217. return group.isXType('buttongroup') &amp;&amp; !(prev instanceof Ext.toolbar.Separator);
  218. };
  219. menu.suspendLayouts();
  220. me.clearMenu();
  221. menu.removeAll();
  222. for (; i &lt; len; i++) {
  223. item = items[i];
  224. // Do not show a separator as a first item
  225. if (!i &amp;&amp; (item instanceof Ext.toolbar.Separator)) {
  226. continue;
  227. }
  228. if (prev &amp;&amp; (needsSep(item, prev) || needsSep(prev, item))) {
  229. menu.add('-');
  230. }
  231. me.addComponentToMenu(menu, item);
  232. prev = item;
  233. }
  234. // put something so the menu isn't empty if no compatible items found
  235. if (menu.items.length &lt; 1) {
  236. menu.add(me.noItemsMenuText);
  237. }
  238. menu.resumeLayouts();
  239. },
  240. <span id='Ext-layout-container-boxOverflow-Menu-method-createMenuConfig'> /**
  241. </span> * @private
  242. * Returns a menu config for a given component. This config is used to create a menu item
  243. * to be added to the expander menu
  244. * @param {Ext.Component} component The component to create the config for
  245. * @param {Boolean} hideOnClick Passed through to the menu item
  246. */
  247. createMenuConfig : function(component, hideOnClick) {
  248. var config = Ext.apply({}, component.initialConfig),
  249. group = component.toggleGroup;
  250. Ext.copyTo(config, component, [
  251. 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
  252. ]);
  253. Ext.apply(config, {
  254. text : component.overflowText || component.text,
  255. hideOnClick: hideOnClick,
  256. destroyMenu: false
  257. });
  258. // Clone must have same value, and must sync original's value on change
  259. if (component.isFormField) {
  260. config.value = component.getValue();
  261. // We're going to add a listener
  262. if (!config.listeners) {
  263. config.listeners = {};
  264. }
  265. // Sync the original component's value when the clone changes value.
  266. // This intentionally overwrites any developer-configured change listener on the clone.
  267. // That's because we monitor the clone's change event, and sync the
  268. // original field by calling setValue, so the original field's change
  269. // event will still fire.
  270. config.listeners.change = function(c, newVal, oldVal) {
  271. component.setValue(newVal);
  272. }
  273. }
  274. // ToggleButtons become CheckItems
  275. else if (group || component.enableToggle) {
  276. Ext.apply(config, {
  277. iconAlign: 'right',
  278. hideOnClick: false,
  279. group : group,
  280. checked: component.pressed,
  281. listeners: {
  282. checkchange: function(item, checked) {
  283. component.toggle(checked);
  284. }
  285. }
  286. });
  287. }
  288. delete config.ownerCt;
  289. delete config.xtype;
  290. delete config.id;
  291. return config;
  292. },
  293. <span id='Ext-layout-container-boxOverflow-Menu-method-addComponentToMenu'> /**
  294. </span> * @private
  295. * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
  296. * @param {Ext.menu.Menu} menu The menu to add to
  297. * @param {Ext.Component} component The component to add
  298. * TODO: Implement overrides in Ext.layout.container.boxOverflow which create overrides
  299. * for SplitButton, Button, ButtonGroup, and TextField. And a generic one for Component
  300. * which create clones suitable for use in an overflow menu.
  301. */
  302. addComponentToMenu : function(menu, component) {
  303. var me = this,
  304. i, items, iLen;
  305. if (component instanceof Ext.toolbar.Separator) {
  306. menu.add('-');
  307. } else if (component.isComponent) {
  308. if (component.isXType('splitbutton')) {
  309. menu.add(me.createMenuConfig(component, true));
  310. } else if (component.isXType('button')) {
  311. menu.add(me.createMenuConfig(component, !component.menu));
  312. } else if (component.isXType('buttongroup')) {
  313. items = component.items.items;
  314. iLen = items.length;
  315. for (i = 0; i &lt; iLen; i++) {
  316. me.addComponentToMenu(menu, items[i]);
  317. }
  318. } else {
  319. menu.add(Ext.create(Ext.getClassName(component), me.createMenuConfig(component)));
  320. }
  321. }
  322. },
  323. <span id='Ext-layout-container-boxOverflow-Menu-method-clearMenu'> /**
  324. </span> * @private
  325. * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
  326. * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
  327. */
  328. clearMenu : function() {
  329. var menu = this.menu,
  330. items, i, iLen, item;
  331. if (menu &amp;&amp; menu.items) {
  332. items = menu.items.items;
  333. iLen = items.length;
  334. for (i = 0; i &lt; iLen; i++) {
  335. item = items[i];
  336. if (item.setMenu) {
  337. item.setMenu(null);
  338. }
  339. }
  340. }
  341. },
  342. <span id='Ext-layout-container-boxOverflow-Menu-method-destroy'> /**
  343. </span> * @private
  344. */
  345. destroy: function() {
  346. var trigger = this.menuTrigger;
  347. if (trigger &amp;&amp; !this.layout.owner.items.contains(trigger)) {
  348. // Ensure we delete the ownerCt if it's not in the items
  349. // so we don't get spurious container remove warnings.
  350. delete trigger.ownerCt;
  351. }
  352. Ext.destroy(this.menu, trigger);
  353. }
  354. });
  355. </pre>
  356. </body>
  357. </html>