Upgrade to ExtJS 3.1.1 - Released 02/08/2010
[extjs.git] / src / widgets / layout / ToolbarLayout.js
1 /*!
2  * Ext JS Library 3.1.1
3  * Copyright(c) 2006-2010 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * @class Ext.layout.ToolbarLayout
9  * @extends Ext.layout.ContainerLayout
10  * Layout manager implicitly used by Ext.Toolbar.
11  */
12 Ext.layout.ToolbarLayout = Ext.extend(Ext.layout.ContainerLayout, {
13     monitorResize : true,
14     triggerWidth : 18,
15     lastOverflow : false,
16
17     noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
18
19     // private
20     onLayout : function(ct, target){
21         if(!this.leftTr){
22             var align = ct.buttonAlign == 'center' ? 'center' : 'left';
23             target.addClass('x-toolbar-layout-ct');
24             target.insertHtml('beforeEnd',
25                  '<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>');
26             this.leftTr = target.child('tr.x-toolbar-left-row', true);
27             this.rightTr = target.child('tr.x-toolbar-right-row', true);
28             this.extrasTr = target.child('tr.x-toolbar-extras-row', true);
29         }
30
31         var side = ct.buttonAlign == 'right' ? this.rightTr : this.leftTr,
32             pos = 0,
33             items = ct.items.items;
34
35         for(var i = 0, len = items.length, c; i < len; i++, pos++) {
36             c = items[i];
37             if(c.isFill){
38                 side = this.rightTr;
39                 pos = -1;
40             }else if(!c.rendered){
41                 c.render(this.insertCell(c, side, pos));
42             }else{
43                 if(!c.xtbHidden && !this.isValidParent(c, side.childNodes[pos])){
44                     var td = this.insertCell(c, side, pos);
45                     td.appendChild(c.getPositionEl().dom);
46                     c.container = Ext.get(td);
47                 }
48             }
49         }
50         //strip extra empty cells
51         this.cleanup(this.leftTr);
52         this.cleanup(this.rightTr);
53         this.cleanup(this.extrasTr);
54         this.fitToSize(target);
55     },
56
57     cleanup : function(row){
58         var cn = row.childNodes, i, c;
59         for(i = cn.length-1; i >= 0 && (c = cn[i]); i--){
60             if(!c.firstChild){
61                 row.removeChild(c);
62             }
63         }
64     },
65
66     insertCell : function(c, side, pos){
67         var td = document.createElement('td');
68         td.className='x-toolbar-cell';
69         side.insertBefore(td, side.childNodes[pos]||null);
70         return td;
71     },
72
73     hideItem : function(item){
74         var h = (this.hiddens = this.hiddens || []);
75         h.push(item);
76         item.xtbHidden = true;
77         item.xtbWidth = item.getPositionEl().dom.parentNode.offsetWidth;
78         item.hide();
79     },
80
81     unhideItem : function(item){
82         item.show();
83         item.xtbHidden = false;
84         this.hiddens.remove(item);
85         if(this.hiddens.length < 1){
86             delete this.hiddens;
87         }
88     },
89
90     getItemWidth : function(c){
91         return c.hidden ? (c.xtbWidth || 0) : c.getPositionEl().dom.parentNode.offsetWidth;
92     },
93
94     fitToSize : function(t){
95         if(this.container.enableOverflow === false){
96             return;
97         }
98         var w = t.dom.clientWidth,
99             lw = this.lastWidth || 0,
100             iw = t.dom.firstChild.offsetWidth,
101             clipWidth = w - this.triggerWidth,
102             hideIndex = -1;
103
104         this.lastWidth = w;
105
106         if(iw > w || (this.hiddens && w >= lw)){
107             var i, items = this.container.items.items,
108                 len = items.length, c,
109                 loopWidth = 0;
110
111             for(i = 0; i < len; i++) {
112                 c = items[i];
113                 if(!c.isFill){
114                     loopWidth += this.getItemWidth(c);
115                     if(loopWidth > clipWidth){
116                         if(!(c.hidden || c.xtbHidden)){
117                             this.hideItem(c);
118                         }
119                     }else if(c.xtbHidden){
120                         this.unhideItem(c);
121                     }
122                 }
123             }
124         }
125         if(this.hiddens){
126             this.initMore();
127             if(!this.lastOverflow){
128                 this.container.fireEvent('overflowchange', this.container, true);
129                 this.lastOverflow = true;
130             }
131         }else if(this.more){
132             this.clearMenu();
133             this.more.destroy();
134             delete this.more;
135             if(this.lastOverflow){
136                 this.container.fireEvent('overflowchange', this.container, false);
137                 this.lastOverflow = false;
138             }
139         }
140     },
141
142     createMenuConfig : function(c, hideOnClick){
143         var cfg = Ext.apply({}, c.initialConfig),
144             group = c.toggleGroup;
145
146         Ext.apply(cfg, {
147             text: c.overflowText || c.text,
148             iconCls: c.iconCls,
149             icon: c.icon,
150             itemId: c.itemId,
151             disabled: c.disabled,
152             handler: c.handler,
153             scope: c.scope,
154             menu: c.menu,
155             hideOnClick: hideOnClick
156         });
157         if(group || c.enableToggle){
158             Ext.apply(cfg, {
159                 group: group,
160                 checked: c.pressed,
161                 listeners: {
162                     checkchange: function(item, checked){
163                         c.toggle(checked);
164                     }
165                 }
166             });
167         }
168         delete cfg.ownerCt;
169         delete cfg.xtype;
170         delete cfg.id;
171         return cfg;
172     },
173
174     // private
175     addComponentToMenu : function(m, c){
176         if(c instanceof Ext.Toolbar.Separator){
177             m.add('-');
178         }else if(Ext.isFunction(c.isXType)){
179             if(c.isXType('splitbutton')){
180                 m.add(this.createMenuConfig(c, true));
181             }else if(c.isXType('button')){
182                 m.add(this.createMenuConfig(c, !c.menu));
183             }else if(c.isXType('buttongroup')){
184                 c.items.each(function(item){
185                      this.addComponentToMenu(m, item);
186                 }, this);
187             }
188         }
189     },
190
191     clearMenu : function(){
192         var m = this.moreMenu;
193         if(m && m.items){
194             m.items.each(function(item){
195                 delete item.menu;
196             });
197         }
198     },
199
200     // private
201     beforeMoreShow : function(m){
202         var h = this.container.items.items,
203             len = h.length,
204             c,
205             prev,
206             needsSep = function(group, item){
207                 return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
208             };
209
210         this.clearMenu();
211         m.removeAll();
212         for(var i = 0; i < len; i++){
213             c = h[i];
214             if(c.xtbHidden){
215                 if(prev && (needsSep(c, prev) || needsSep(prev, c))){
216                     m.add('-');
217                 }
218                 this.addComponentToMenu(m, c);
219                 prev = c;
220             }
221         }
222         // put something so the menu isn't empty
223         // if no compatible items found
224         if(m.items.length < 1){
225             m.add(this.noItemsMenuText);
226         }
227     },
228
229     initMore : function(){
230         if(!this.more){
231             this.moreMenu = new Ext.menu.Menu({
232                 ownerCt : this.container,
233                 listeners: {
234                     beforeshow: this.beforeMoreShow,
235                     scope: this
236                 }
237
238             });
239             this.more = new Ext.Button({
240                 iconCls : 'x-toolbar-more-icon',
241                 cls     : 'x-toolbar-more',
242                 menu    : this.moreMenu,
243                 ownerCt : this.container
244             });
245             var td = this.insertCell(this.more, this.extrasTr, 100);
246             this.more.render(td);
247         }
248     },
249
250     destroy : function(){
251         Ext.destroy(this.more, this.moreMenu);
252         delete this.leftTr;
253         delete this.rightTr;
254         delete this.extrasTr;
255         Ext.layout.ToolbarLayout.superclass.destroy.call(this);
256     }
257 });
258
259 Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout;