[76] | 1 | /*! |
---|
| 2 | * Ext JS Library 3.4.0 |
---|
| 3 | * Copyright(c) 2006-2011 Sencha Inc. |
---|
| 4 | * licensing@sencha.com |
---|
| 5 | * http://www.sencha.com/license |
---|
| 6 | */ |
---|
| 7 | /** |
---|
| 8 | * @class Ext.layout.boxOverflow.Menu |
---|
| 9 | * @extends Ext.layout.boxOverflow.None |
---|
| 10 | * Description |
---|
| 11 | */ |
---|
| 12 | Ext.layout.boxOverflow.Menu = Ext.extend(Ext.layout.boxOverflow.None, { |
---|
| 13 | /** |
---|
| 14 | * @cfg afterCls |
---|
| 15 | * @type String |
---|
| 16 | * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers, |
---|
| 17 | * which must always be present at the rightmost edge of the Container |
---|
| 18 | */ |
---|
| 19 | afterCls: 'x-strip-right', |
---|
| 20 | |
---|
| 21 | /** |
---|
| 22 | * @property noItemsMenuText |
---|
| 23 | * @type String |
---|
| 24 | * HTML fragment to render into the toolbar overflow menu if there are no items to display |
---|
| 25 | */ |
---|
| 26 | noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>', |
---|
| 27 | |
---|
| 28 | constructor: function(layout) { |
---|
| 29 | Ext.layout.boxOverflow.Menu.superclass.constructor.apply(this, arguments); |
---|
| 30 | |
---|
| 31 | /** |
---|
| 32 | * @property menuItems |
---|
| 33 | * @type Array |
---|
| 34 | * Array of all items that are currently hidden and should go into the dropdown menu |
---|
| 35 | */ |
---|
| 36 | this.menuItems = []; |
---|
| 37 | }, |
---|
| 38 | |
---|
| 39 | /** |
---|
| 40 | * @private |
---|
| 41 | * Creates the beforeCt, innerCt and afterCt elements if they have not already been created |
---|
| 42 | * @param {Ext.Container} container The Container attached to this Layout instance |
---|
| 43 | * @param {Ext.Element} target The target Element |
---|
| 44 | */ |
---|
| 45 | createInnerElements: function() { |
---|
| 46 | if (!this.afterCt) { |
---|
| 47 | this.afterCt = this.layout.innerCt.insertSibling({cls: this.afterCls}, 'before'); |
---|
| 48 | } |
---|
| 49 | }, |
---|
| 50 | |
---|
| 51 | /** |
---|
| 52 | * @private |
---|
| 53 | */ |
---|
| 54 | clearOverflow: function(calculations, targetSize) { |
---|
| 55 | var newWidth = targetSize.width + (this.afterCt ? this.afterCt.getWidth() : 0), |
---|
| 56 | items = this.menuItems; |
---|
| 57 | |
---|
| 58 | this.hideTrigger(); |
---|
| 59 | |
---|
| 60 | for (var index = 0, length = items.length; index < length; index++) { |
---|
| 61 | items.pop().component.show(); |
---|
| 62 | } |
---|
| 63 | |
---|
| 64 | return { |
---|
| 65 | targetSize: { |
---|
| 66 | height: targetSize.height, |
---|
| 67 | width : newWidth |
---|
| 68 | } |
---|
| 69 | }; |
---|
| 70 | }, |
---|
| 71 | |
---|
| 72 | /** |
---|
| 73 | * @private |
---|
| 74 | */ |
---|
| 75 | showTrigger: function() { |
---|
| 76 | this.createMenu(); |
---|
| 77 | this.menuTrigger.show(); |
---|
| 78 | }, |
---|
| 79 | |
---|
| 80 | /** |
---|
| 81 | * @private |
---|
| 82 | */ |
---|
| 83 | hideTrigger: function() { |
---|
| 84 | if (this.menuTrigger != undefined) { |
---|
| 85 | this.menuTrigger.hide(); |
---|
| 86 | } |
---|
| 87 | }, |
---|
| 88 | |
---|
| 89 | /** |
---|
| 90 | * @private |
---|
| 91 | * Called before the overflow menu is shown. This constructs the menu's items, caching them for as long as it can. |
---|
| 92 | */ |
---|
| 93 | beforeMenuShow: function(menu) { |
---|
| 94 | var items = this.menuItems, |
---|
| 95 | len = items.length, |
---|
| 96 | item, |
---|
| 97 | prev; |
---|
| 98 | |
---|
| 99 | var needsSep = function(group, item){ |
---|
| 100 | return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator); |
---|
| 101 | }; |
---|
| 102 | |
---|
| 103 | this.clearMenu(); |
---|
| 104 | menu.removeAll(); |
---|
| 105 | |
---|
| 106 | for (var i = 0; i < len; i++) { |
---|
| 107 | item = items[i].component; |
---|
| 108 | |
---|
| 109 | if (prev && (needsSep(item, prev) || needsSep(prev, item))) { |
---|
| 110 | menu.add('-'); |
---|
| 111 | } |
---|
| 112 | |
---|
| 113 | this.addComponentToMenu(menu, item); |
---|
| 114 | prev = item; |
---|
| 115 | } |
---|
| 116 | |
---|
| 117 | // put something so the menu isn't empty if no compatible items found |
---|
| 118 | if (menu.items.length < 1) { |
---|
| 119 | menu.add(this.noItemsMenuText); |
---|
| 120 | } |
---|
| 121 | }, |
---|
| 122 | |
---|
| 123 | /** |
---|
| 124 | * @private |
---|
| 125 | * Returns a menu config for a given component. This config is used to create a menu item |
---|
| 126 | * to be added to the expander menu |
---|
| 127 | * @param {Ext.Component} component The component to create the config for |
---|
| 128 | * @param {Boolean} hideOnClick Passed through to the menu item |
---|
| 129 | */ |
---|
| 130 | createMenuConfig : function(component, hideOnClick){ |
---|
| 131 | var config = Ext.apply({}, component.initialConfig), |
---|
| 132 | group = component.toggleGroup; |
---|
| 133 | |
---|
| 134 | Ext.copyTo(config, component, [ |
---|
| 135 | 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu' |
---|
| 136 | ]); |
---|
| 137 | |
---|
| 138 | Ext.apply(config, { |
---|
| 139 | text : component.overflowText || component.text, |
---|
| 140 | hideOnClick: hideOnClick |
---|
| 141 | }); |
---|
| 142 | |
---|
| 143 | if (group || component.enableToggle) { |
---|
| 144 | Ext.apply(config, { |
---|
| 145 | group : group, |
---|
| 146 | checked: component.pressed, |
---|
| 147 | listeners: { |
---|
| 148 | checkchange: function(item, checked){ |
---|
| 149 | component.toggle(checked); |
---|
| 150 | } |
---|
| 151 | } |
---|
| 152 | }); |
---|
| 153 | } |
---|
| 154 | |
---|
| 155 | delete config.ownerCt; |
---|
| 156 | delete config.xtype; |
---|
| 157 | delete config.id; |
---|
| 158 | |
---|
| 159 | return config; |
---|
| 160 | }, |
---|
| 161 | |
---|
| 162 | /** |
---|
| 163 | * @private |
---|
| 164 | * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually. |
---|
| 165 | * @param {Ext.menu.Menu} menu The menu to add to |
---|
| 166 | * @param {Ext.Component} component The component to add |
---|
| 167 | */ |
---|
| 168 | addComponentToMenu : function(menu, component) { |
---|
| 169 | if (component instanceof Ext.Toolbar.Separator) { |
---|
| 170 | menu.add('-'); |
---|
| 171 | |
---|
| 172 | } else if (Ext.isFunction(component.isXType)) { |
---|
| 173 | if (component.isXType('splitbutton')) { |
---|
| 174 | menu.add(this.createMenuConfig(component, true)); |
---|
| 175 | |
---|
| 176 | } else if (component.isXType('button')) { |
---|
| 177 | menu.add(this.createMenuConfig(component, !component.menu)); |
---|
| 178 | |
---|
| 179 | } else if (component.isXType('buttongroup')) { |
---|
| 180 | component.items.each(function(item){ |
---|
| 181 | this.addComponentToMenu(menu, item); |
---|
| 182 | }, this); |
---|
| 183 | } |
---|
| 184 | } |
---|
| 185 | }, |
---|
| 186 | |
---|
| 187 | /** |
---|
| 188 | * @private |
---|
| 189 | * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as |
---|
| 190 | * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item |
---|
| 191 | */ |
---|
| 192 | clearMenu : function(){ |
---|
| 193 | var menu = this.moreMenu; |
---|
| 194 | if (menu && menu.items) { |
---|
| 195 | menu.items.each(function(item){ |
---|
| 196 | delete item.menu; |
---|
| 197 | }); |
---|
| 198 | } |
---|
| 199 | }, |
---|
| 200 | |
---|
| 201 | /** |
---|
| 202 | * @private |
---|
| 203 | * Creates the overflow trigger and menu used when enableOverflow is set to true and the items |
---|
| 204 | * in the layout are too wide to fit in the space available |
---|
| 205 | */ |
---|
| 206 | createMenu: function() { |
---|
| 207 | if (!this.menuTrigger) { |
---|
| 208 | this.createInnerElements(); |
---|
| 209 | |
---|
| 210 | /** |
---|
| 211 | * @private |
---|
| 212 | * @property menu |
---|
| 213 | * @type Ext.menu.Menu |
---|
| 214 | * The expand menu - holds items for every item that cannot be shown |
---|
| 215 | * because the container is currently not large enough. |
---|
| 216 | */ |
---|
| 217 | this.menu = new Ext.menu.Menu({ |
---|
| 218 | ownerCt : this.layout.container, |
---|
| 219 | listeners: { |
---|
| 220 | scope: this, |
---|
| 221 | beforeshow: this.beforeMenuShow |
---|
| 222 | } |
---|
| 223 | }); |
---|
| 224 | |
---|
| 225 | /** |
---|
| 226 | * @private |
---|
| 227 | * @property menuTrigger |
---|
| 228 | * @type Ext.Button |
---|
| 229 | * The expand button which triggers the overflow menu to be shown |
---|
| 230 | */ |
---|
| 231 | this.menuTrigger = new Ext.Button({ |
---|
| 232 | iconCls : 'x-toolbar-more-icon', |
---|
| 233 | cls : 'x-toolbar-more', |
---|
| 234 | menu : this.menu, |
---|
| 235 | renderTo: this.afterCt |
---|
| 236 | }); |
---|
| 237 | } |
---|
| 238 | }, |
---|
| 239 | |
---|
| 240 | /** |
---|
| 241 | * @private |
---|
| 242 | */ |
---|
| 243 | destroy: function() { |
---|
| 244 | Ext.destroy(this.menu, this.menuTrigger); |
---|
| 245 | } |
---|
| 246 | }); |
---|
| 247 | |
---|
| 248 | Ext.layout.boxOverflow.menu = Ext.layout.boxOverflow.Menu; |
---|
| 249 | |
---|
| 250 | |
---|
| 251 | /** |
---|
| 252 | * @class Ext.layout.boxOverflow.HorizontalMenu |
---|
| 253 | * @extends Ext.layout.boxOverflow.Menu |
---|
| 254 | * Description |
---|
| 255 | */ |
---|
| 256 | Ext.layout.boxOverflow.HorizontalMenu = Ext.extend(Ext.layout.boxOverflow.Menu, { |
---|
| 257 | |
---|
| 258 | constructor: function() { |
---|
| 259 | Ext.layout.boxOverflow.HorizontalMenu.superclass.constructor.apply(this, arguments); |
---|
| 260 | |
---|
| 261 | var me = this, |
---|
| 262 | layout = me.layout, |
---|
| 263 | origFunction = layout.calculateChildBoxes; |
---|
| 264 | |
---|
| 265 | layout.calculateChildBoxes = function(visibleItems, targetSize) { |
---|
| 266 | var calcs = origFunction.apply(layout, arguments), |
---|
| 267 | meta = calcs.meta, |
---|
| 268 | items = me.menuItems; |
---|
| 269 | |
---|
| 270 | //calculate the width of the items currently hidden solely because there is not enough space |
---|
| 271 | //to display them |
---|
| 272 | var hiddenWidth = 0; |
---|
| 273 | for (var index = 0, length = items.length; index < length; index++) { |
---|
| 274 | hiddenWidth += items[index].width; |
---|
| 275 | } |
---|
| 276 | |
---|
| 277 | meta.minimumWidth += hiddenWidth; |
---|
| 278 | meta.tooNarrow = meta.minimumWidth > targetSize.width; |
---|
| 279 | |
---|
| 280 | return calcs; |
---|
| 281 | }; |
---|
| 282 | }, |
---|
| 283 | |
---|
| 284 | handleOverflow: function(calculations, targetSize) { |
---|
| 285 | this.showTrigger(); |
---|
| 286 | |
---|
| 287 | var newWidth = targetSize.width - this.afterCt.getWidth(), |
---|
| 288 | boxes = calculations.boxes, |
---|
| 289 | usedWidth = 0, |
---|
| 290 | recalculate = false; |
---|
| 291 | |
---|
| 292 | //calculate the width of all visible items and any spare width |
---|
| 293 | for (var index = 0, length = boxes.length; index < length; index++) { |
---|
| 294 | usedWidth += boxes[index].width; |
---|
| 295 | } |
---|
| 296 | |
---|
| 297 | var spareWidth = newWidth - usedWidth, |
---|
| 298 | showCount = 0; |
---|
| 299 | |
---|
| 300 | //see if we can re-show any of the hidden components |
---|
| 301 | for (var index = 0, length = this.menuItems.length; index < length; index++) { |
---|
| 302 | var hidden = this.menuItems[index], |
---|
| 303 | comp = hidden.component, |
---|
| 304 | width = hidden.width; |
---|
| 305 | |
---|
| 306 | if (width < spareWidth) { |
---|
| 307 | comp.show(); |
---|
| 308 | |
---|
| 309 | spareWidth -= width; |
---|
| 310 | showCount ++; |
---|
| 311 | recalculate = true; |
---|
| 312 | } else { |
---|
| 313 | break; |
---|
| 314 | } |
---|
| 315 | } |
---|
| 316 | |
---|
| 317 | if (recalculate) { |
---|
| 318 | this.menuItems = this.menuItems.slice(showCount); |
---|
| 319 | } else { |
---|
| 320 | for (var i = boxes.length - 1; i >= 0; i--) { |
---|
| 321 | var item = boxes[i].component, |
---|
| 322 | right = boxes[i].left + boxes[i].width; |
---|
| 323 | |
---|
| 324 | if (right >= newWidth) { |
---|
| 325 | this.menuItems.unshift({ |
---|
| 326 | component: item, |
---|
| 327 | width : boxes[i].width |
---|
| 328 | }); |
---|
| 329 | |
---|
| 330 | item.hide(); |
---|
| 331 | } else { |
---|
| 332 | break; |
---|
| 333 | } |
---|
| 334 | } |
---|
| 335 | } |
---|
| 336 | |
---|
| 337 | if (this.menuItems.length == 0) { |
---|
| 338 | this.hideTrigger(); |
---|
| 339 | } |
---|
| 340 | |
---|
| 341 | return { |
---|
| 342 | targetSize: { |
---|
| 343 | height: targetSize.height, |
---|
| 344 | width : newWidth |
---|
| 345 | }, |
---|
| 346 | recalculate: recalculate |
---|
| 347 | }; |
---|
| 348 | } |
---|
| 349 | }); |
---|
| 350 | |
---|
| 351 | Ext.layout.boxOverflow.menu.hbox = Ext.layout.boxOverflow.HorizontalMenu; |
---|