-<html>\r
-<head>\r
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> \r
- <title>The source code</title>\r
- <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
- <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
-</head>\r
-<body onload="prettyPrint();">\r
- <pre class="prettyprint lang-js"><div id="cls-Ext.layout.ToolbarLayout"></div>/**
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>The source code</title>
+ <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
+</head>
+<body onload="prettyPrint();">
+ <pre class="prettyprint lang-js">/*!
+ * Ext JS Library 3.2.1
+ * Copyright(c) 2006-2010 Ext JS, Inc.
+ * licensing@extjs.com
+ * http://www.extjs.com/license
+ */
+<div id="cls-Ext.layout.ToolbarLayout"></div>/**
* @class Ext.layout.ToolbarLayout
* @extends Ext.layout.ContainerLayout
- * Layout manager implicitly used by Ext.Toolbar.
+ * Layout manager used by Ext.Toolbar. This is highly specialised for use by Toolbars and would not
+ * usually be used by any other class.
*/
Ext.layout.ToolbarLayout = Ext.extend(Ext.layout.ContainerLayout, {
monitorResize : true,
- triggerWidth : 18,
- lastOverflow : false,
+ type: 'toolbar',
+
+ <div id="prop-Ext.layout.ToolbarLayout-triggerWidth"></div>/**
+ * @property triggerWidth
+ * @type Number
+ * The width allocated for the menu trigger at the extreme right end of the Toolbar
+ */
+ triggerWidth: 18,
+
+ <div id="prop-Ext.layout.ToolbarLayout-noItemsMenuText"></div>/**
+ * @property noItemsMenuText
+ * @type String
+ * HTML fragment to render into the toolbar overflow menu if there are no items to display
+ */
noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
- // private
- onLayout : function(ct, target){
- if(!this.leftTr){
+ /**
+ * @private
+ * @property lastOverflow
+ * @type Boolean
+ * Used internally to record whether the last layout caused an overflow or not
+ */
+ lastOverflow: false,
+
+ /**
+ * @private
+ * @property tableHTML
+ * @type String
+ * String used to build the HTML injected to support the Toolbar's layout. The align property is
+ * injected into this string inside the td.x-toolbar-left element during onLayout.
+ */
+ tableHTML: [
+ '<table cellspacing="0" class="x-toolbar-ct">',
+ '<tbody>',
+ '<tr>',
+ '<td class="x-toolbar-left" align="{0}">',
+ '<table cellspacing="0">',
+ '<tbody>',
+ '<tr class="x-toolbar-left-row"></tr>',
+ '</tbody>',
+ '</table>',
+ '</td>',
+ '<td class="x-toolbar-right" align="right">',
+ '<table cellspacing="0" class="x-toolbar-right-ct">',
+ '<tbody>',
+ '<tr>',
+ '<td>',
+ '<table cellspacing="0">',
+ '<tbody>',
+ '<tr class="x-toolbar-right-row"></tr>',
+ '</tbody>',
+ '</table>',
+ '</td>',
+ '<td>',
+ '<table cellspacing="0">',
+ '<tbody>',
+ '<tr class="x-toolbar-extras-row"></tr>',
+ '</tbody>',
+ '</table>',
+ '</td>',
+ '</tr>',
+ '</tbody>',
+ '</table>',
+ '</td>',
+ '</tr>',
+ '</tbody>',
+ '</table>'
+ ].join(""),
+
+ /**
+ * @private
+ * Create the wrapping Toolbar HTML and render/move all the items into the correct places
+ */
+ onLayout : function(ct, target) {
+ //render the Toolbar <table> HTML if it's not already present
+ if (!this.leftTr) {
var align = ct.buttonAlign == 'center' ? 'center' : 'left';
+
target.addClass('x-toolbar-layout-ct');
- target.insertHtml('beforeEnd',
- '<table cellspacing="0" class="x-toolbar-ct"><tbody><tr><td class="x-toolbar-left" align="' + align + '"><table cellspacing="0"><tbody><tr class="x-toolbar-left-row"></tr></tbody></table></td><td class="x-toolbar-right" align="right"><table cellspacing="0" class="x-toolbar-right-ct"><tbody><tr><td><table cellspacing="0"><tbody><tr class="x-toolbar-right-row"></tr></tbody></table></td><td><table cellspacing="0"><tbody><tr class="x-toolbar-extras-row"></tr></tbody></table></td></tr></tbody></table></td></tr></tbody></table>');
- this.leftTr = target.child('tr.x-toolbar-left-row', true);
- this.rightTr = target.child('tr.x-toolbar-right-row', true);
+ target.insertHtml('beforeEnd', String.format(this.tableHTML, align));
+
+ this.leftTr = target.child('tr.x-toolbar-left-row', true);
+ this.rightTr = target.child('tr.x-toolbar-right-row', true);
this.extrasTr = target.child('tr.x-toolbar-extras-row', true);
+
+ if (this.hiddenItem == undefined) {
+ <div id="prop-Ext.layout.ToolbarLayout-hiddenItems"></div>/**
+ * @property hiddenItems
+ * @type Array
+ * Holds all items that are currently hidden due to there not being enough space to render them
+ * These items will appear on the expand menu.
+ */
+ this.hiddenItems = [];
+ }
}
- var side = ct.buttonAlign == 'right' ? this.rightTr : this.leftTr,
- pos = 0,
- items = ct.items.items;
+ var side = ct.buttonAlign == 'right' ? this.rightTr : this.leftTr,
+ items = ct.items.items,
+ position = 0;
- for(var i = 0, len = items.length, c; i < len; i++, pos++) {
+ //render each item if not already rendered, place it into the correct (left or right) target
+ for (var i = 0, len = items.length, c; i < len; i++, position++) {
c = items[i];
- if(c.isFill){
- side = this.rightTr;
- pos = -1;
- }else if(!c.rendered){
- c.render(this.insertCell(c, side, pos));
- }else{
- if(!c.xtbHidden && !this.isValidParent(c, side.childNodes[pos])){
- var td = this.insertCell(c, side, pos);
+
+ if (c.isFill) {
+ side = this.rightTr;
+ position = -1;
+ } else if (!c.rendered) {
+ c.render(this.insertCell(c, side, position));
+ } else {
+ if (!c.xtbHidden && !this.isValidParent(c, side.childNodes[position])) {
+ var td = this.insertCell(c, side, position);
td.appendChild(c.getPositionEl().dom);
c.container = Ext.get(td);
}
}
}
+
//strip extra empty cells
this.cleanup(this.leftTr);
this.cleanup(this.rightTr);
this.fitToSize(target);
},
- cleanup : function(row){
- var cn = row.childNodes, i, c;
- for(i = cn.length-1; i >= 0 && (c = cn[i]); i--){
- if(!c.firstChild){
- row.removeChild(c);
+ /**
+ * @private
+ * Removes any empty nodes from the given element
+ * @param {Ext.Element} el The element to clean up
+ */
+ cleanup : function(el) {
+ var cn = el.childNodes, i, c;
+
+ for (i = cn.length-1; i >= 0 && (c = cn[i]); i--) {
+ if (!c.firstChild) {
+ el.removeChild(c);
}
}
},
- insertCell : function(c, side, pos){
+ /**
+ * @private
+ * Inserts the given Toolbar item into the given element
+ * @param {Ext.Component} c The component to add
+ * @param {Ext.Element} target The target to add the component to
+ * @param {Number} position The position to add the component at
+ */
+ insertCell : function(c, target, position) {
var td = document.createElement('td');
- td.className='x-toolbar-cell';
- side.insertBefore(td, side.childNodes[pos]||null);
+ td.className = 'x-toolbar-cell';
+
+ target.insertBefore(td, target.childNodes[position] || null);
+
return td;
},
- hideItem : function(item){
- var h = (this.hiddens = this.hiddens || []);
- h.push(item);
+ /**
+ * @private
+ * Hides an item because it will not fit in the available width. The item will be unhidden again
+ * if the Toolbar is resized to be large enough to show it
+ * @param {Ext.Component} item The item to hide
+ */
+ hideItem : function(item) {
+ this.hiddenItems.push(item);
+
item.xtbHidden = true;
item.xtbWidth = item.getPositionEl().dom.parentNode.offsetWidth;
item.hide();
},
- unhideItem : function(item){
+ /**
+ * @private
+ * Unhides an item that was previously hidden due to there not being enough space left on the Toolbar
+ * @param {Ext.Component} item The item to show
+ */
+ unhideItem : function(item) {
item.show();
item.xtbHidden = false;
- this.hiddens.remove(item);
- if(this.hiddens.length < 1){
- delete this.hiddens;
- }
+ this.hiddenItems.remove(item);
},
- getItemWidth : function(c){
+ /**
+ * @private
+ * Returns the width of the given toolbar item. If the item is currently hidden because there
+ * is not enough room to render it, its previous width is returned
+ * @param {Ext.Component} c The component to measure
+ * @return {Number} The width of the item
+ */
+ getItemWidth : function(c) {
return c.hidden ? (c.xtbWidth || 0) : c.getPositionEl().dom.parentNode.offsetWidth;
},
- fitToSize : function(t){
- if(this.container.enableOverflow === false){
+ /**
+ * @private
+ * Called at the end of onLayout. At this point the Toolbar has already been resized, so we need
+ * to fit the items into the available width. We add up the width required by all of the items in
+ * the toolbar - if we don't have enough space we hide the extra items and render the expand menu
+ * trigger.
+ * @param {Ext.Element} target The Element the Toolbar is currently laid out within
+ */
+ fitToSize : function(target) {
+ if (this.container.enableOverflow === false) {
return;
}
- var w = t.dom.clientWidth,
- lw = this.lastWidth || 0,
- iw = t.dom.firstChild.offsetWidth,
- clipWidth = w - this.triggerWidth,
- hideIndex = -1;
-
- this.lastWidth = w;
-
- if(iw > w || (this.hiddens && w >= lw)){
- var i, items = this.container.items.items,
- len = items.length, c,
- loopWidth = 0;
-
- for(i = 0; i < len; i++) {
- c = items[i];
- if(!c.isFill){
- loopWidth += this.getItemWidth(c);
- if(loopWidth > clipWidth){
- if(!(c.hidden || c.xtbHidden)){
- this.hideItem(c);
+
+ var width = target.dom.clientWidth,
+ tableWidth = target.dom.firstChild.offsetWidth,
+ clipWidth = width - this.triggerWidth,
+ lastWidth = this.lastWidth || 0,
+
+ hiddenItems = this.hiddenItems,
+ hasHiddens = hiddenItems.length != 0,
+ isLarger = width >= lastWidth;
+
+ this.lastWidth = width;
+
+ if (tableWidth > width || (hasHiddens && isLarger)) {
+ var items = this.container.items.items,
+ len = items.length,
+ loopWidth = 0,
+ item;
+
+ for (var i = 0; i < len; i++) {
+ item = items[i];
+
+ if (!item.isFill) {
+ loopWidth += this.getItemWidth(item);
+ if (loopWidth > clipWidth) {
+ if (!(item.hidden || item.xtbHidden)) {
+ this.hideItem(item);
}
- }else if(c.xtbHidden){
- this.unhideItem(c);
+ } else if (item.xtbHidden) {
+ this.unhideItem(item);
}
}
}
}
- if(this.hiddens){
+
+ //test for number of hidden items again here because they may have changed above
+ hasHiddens = hiddenItems.length != 0;
+
+ if (hasHiddens) {
this.initMore();
- if(!this.lastOverflow){
+
+ if (!this.lastOverflow) {
this.container.fireEvent('overflowchange', this.container, true);
this.lastOverflow = true;
}
- }else if(this.more){
+ } else if (this.more) {
this.clearMenu();
this.more.destroy();
delete this.more;
- if(this.lastOverflow){
+
+ if (this.lastOverflow) {
this.container.fireEvent('overflowchange', this.container, false);
this.lastOverflow = false;
}
}
},
- createMenuConfig : function(c, hideOnClick){
- var cfg = Ext.apply({}, c.initialConfig),
- group = c.toggleGroup;
-
- Ext.apply(cfg, {
- text: c.overflowText || c.text,
- iconCls: c.iconCls,
- icon: c.icon,
- itemId: c.itemId,
- disabled: c.disabled,
- handler: c.handler,
- scope: c.scope,
- menu: c.menu,
+ /**
+ * @private
+ * Returns a menu config for a given component. This config is used to create a menu item
+ * to be added to the expander menu
+ * @param {Ext.Component} component The component to create the config for
+ * @param {Boolean} hideOnClick Passed through to the menu item
+ */
+ createMenuConfig : function(component, hideOnClick){
+ var config = Ext.apply({}, component.initialConfig),
+ group = component.toggleGroup;
+
+ Ext.copyTo(config, component, [
+ 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
+ ]);
+
+ Ext.apply(config, {
+ text : component.overflowText || component.text,
hideOnClick: hideOnClick
});
- if(group || c.enableToggle){
- Ext.apply(cfg, {
- group: group,
- checked: c.pressed,
+
+ if (group || component.enableToggle) {
+ Ext.apply(config, {
+ group : group,
+ checked: component.pressed,
listeners: {
checkchange: function(item, checked){
- c.toggle(checked);
+ component.toggle(checked);
}
}
});
}
- delete cfg.ownerCt;
- delete cfg.xtype;
- delete cfg.id;
- return cfg;
+
+ delete config.ownerCt;
+ delete config.xtype;
+ delete config.id;
+
+ return config;
},
- // private
- addComponentToMenu : function(m, c){
- if(c instanceof Ext.Toolbar.Separator){
- m.add('-');
- }else if(Ext.isFunction(c.isXType)){
- if(c.isXType('splitbutton')){
- m.add(this.createMenuConfig(c, true));
- }else if(c.isXType('button')){
- m.add(this.createMenuConfig(c, !c.menu));
- }else if(c.isXType('buttongroup')){
- c.items.each(function(item){
- this.addComponentToMenu(m, item);
+ /**
+ * @private
+ * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
+ * @param {Ext.menu.Menu} menu The menu to add to
+ * @param {Ext.Component} component The component to add
+ */
+ addComponentToMenu : function(menu, component) {
+ if (component instanceof Ext.Toolbar.Separator) {
+ menu.add('-');
+
+ } else if (Ext.isFunction(component.isXType)) {
+ if (component.isXType('splitbutton')) {
+ menu.add(this.createMenuConfig(component, true));
+
+ } else if (component.isXType('button')) {
+ menu.add(this.createMenuConfig(component, !component.menu));
+
+ } else if (component.isXType('buttongroup')) {
+ component.items.each(function(item){
+ this.addComponentToMenu(menu, item);
}, this);
}
}
},
+ /**
+ * @private
+ * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
+ * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
+ */
clearMenu : function(){
- var m = this.moreMenu;
- if(m && m.items){
- m.items.each(function(item){
+ var menu = this.moreMenu;
+ if (menu && menu.items) {
+ menu.items.each(function(item){
delete item.menu;
});
}
},
- // private
- beforeMoreShow : function(m){
- var h = this.container.items.items,
- len = h.length,
- c,
- prev,
- needsSep = function(group, item){
- return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
- };
+ /**
+ * @private
+ * Called before the expand menu is shown, this rebuilds the menu since it was last shown because
+ * it is possible that the items hidden due to space limitations on the Toolbar have changed since.
+ * @param {Ext.menu.Menu} m The menu
+ */
+ beforeMoreShow : function(menu) {
+ var items = this.container.items.items,
+ len = items.length,
+ item,
+ prev;
+
+ var needsSep = function(group, item){
+ return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
+ };
this.clearMenu();
- m.removeAll();
- for(var i = 0; i < len; i++){
- c = h[i];
- if(c.xtbHidden){
- if(prev && (needsSep(c, prev) || needsSep(prev, c))){
- m.add('-');
+ menu.removeAll();
+ for (var i = 0; i < len; i++) {
+ item = items[i];
+ if (item.xtbHidden) {
+ if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
+ menu.add('-');
}
- this.addComponentToMenu(m, c);
- prev = c;
+ this.addComponentToMenu(menu, item);
+ prev = item;
}
}
- // put something so the menu isn't empty
- // if no compatible items found
- if(m.items.length < 1){
- m.add(this.noItemsMenuText);
+
+ // put something so the menu isn't empty if no compatible items found
+ if (menu.items.length < 1) {
+ menu.add(this.noItemsMenuText);
}
},
+ /**
+ * @private
+ * Creates the expand trigger and menu, adding them to the <tr> at the extreme right of the
+ * Toolbar table
+ */
initMore : function(){
- if(!this.more){
+ if (!this.more) {
+ /**
+ * @private
+ * @property moreMenu
+ * @type Ext.menu.Menu
+ * The expand menu - holds items for every Toolbar item that cannot be shown
+ * because the Toolbar is currently not wide enough.
+ */
this.moreMenu = new Ext.menu.Menu({
ownerCt : this.container,
listeners: {
beforeshow: this.beforeMoreShow,
scope: this
}
-
});
+
+ /**
+ * @private
+ * @property more
+ * @type Ext.Button
+ * The expand button which triggers the overflow menu to be shown
+ */
this.more = new Ext.Button({
- iconCls : 'x-toolbar-more-icon',
- cls : 'x-toolbar-more',
- menu : this.moreMenu,
- ownerCt : this.container
+ iconCls: 'x-toolbar-more-icon',
+ cls : 'x-toolbar-more',
+ menu : this.moreMenu,
+ ownerCt: this.container
});
+
var td = this.insertCell(this.more, this.extrasTr, 100);
this.more.render(td);
}
}
});
-Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout;</pre> \r
-</body>\r
+Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout;
+</pre>
+</body>
</html>
\ No newline at end of file