Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / examples / sandbox / js / TaskBar.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /*!
16  * Ext JS Library 3.3.1
17  * Copyright(c) 2006-2010 Sencha Inc.
18  * licensing@sencha.com
19  * http://www.sencha.com/license
20  */
21 /**
22  * @class Ext.ux.TaskBar
23  * @extends Ext.util.Observable
24  */
25 Ext.ux.TaskBar = function(app){
26     this.app = app;
27     this.init();
28 }
29
30 Ext.extend(Ext.ux.TaskBar, Ext.util.Observable, {
31     init : function(){
32         this.startMenu = new Ext.ux.StartMenu(Ext.apply({
33             iconCls: 'user',
34             height: 300,
35             shadow: true,
36             title: 'Tommy Maintz',
37             width: 300
38         }, this.app.startConfig));
39
40         this.startBtn = new Ext.Button({
41             text: 'Start',
42             id: 'ux-startbutton',
43             iconCls:'start',
44             menu: this.startMenu,
45             menuAlign: 'bl-tl',
46             renderTo: 'ux-taskbar-start',
47             clickEvent: 'mousedown',
48             template: new Ext.Template(
49                 '<table cellspacing="0" class="x-btn"><tbody class="{1}"><tr>',
50                 '<td class="ux-startbutton-left"><i>&#160;</i></td>',
51                 '<td class="ux-startbutton-center"><em class="{2} unselectable="on">',
52                     '<button class="x-btn-text" type="{0}" style="height:30px;"></button>',
53                 '</em></td>',
54                 '<td class="ux-startbutton-right"><i>&#160;</i></td>',
55                 '</tr></tbody></table>')
56         });
57
58         var width = this.startBtn.getEl().getWidth()+10;
59
60         var sbBox = new Ext.BoxComponent({
61             el: 'ux-taskbar-start',
62             id: 'TaskBarStart',
63             minWidth: width,
64             region:'west',
65             split: true,
66             width: width
67         });
68
69         this.tbPanel = new Ext.ux.TaskButtonsPanel({
70             el: 'ux-taskbuttons-panel',
71             id: 'TaskBarButtons',
72             region:'center'
73         });
74
75         var container = new Ext.ux.TaskBarContainer({
76             el: 'ux-taskbar',
77             layout: 'border',
78             items: [sbBox,this.tbPanel]
79         });
80
81         return this;
82     },
83
84     addTaskButton : function(win){
85         return this.tbPanel.addButton(win, 'ux-taskbuttons-panel');
86     },
87
88     removeTaskButton : function(btn){
89         this.tbPanel.removeButton(btn);
90     },
91
92     setActiveButton : function(btn){
93         this.tbPanel.setActiveButton(btn);
94     }
95 });
96
97
98
99 /**
100  * @class Ext.ux.TaskBarContainer
101  * @extends Ext.Container
102  */
103 Ext.ux.TaskBarContainer = Ext.extend(Ext.Container, {
104     initComponent : function() {
105         Ext.ux.TaskBarContainer.superclass.initComponent.call(this);
106
107         this.el = Ext.get(this.el) || Ext.getBody();
108         this.el.setHeight = Ext.emptyFn;
109         this.el.setWidth = Ext.emptyFn;
110         this.el.setSize = Ext.emptyFn;
111         this.el.setStyle({
112             overflow:'hidden',
113             margin:'0',
114             border:'0 none'
115         });
116         this.el.dom.scroll = 'no';
117         this.allowDomMove = false;
118         this.autoWidth = true;
119         this.autoHeight = true;
120         Ext.EventManager.onWindowResize(this.fireResize, this);
121         this.renderTo = this.el;
122     },
123
124     fireResize : function(w, h){
125         this.onResize(w, h, w, h);
126         this.fireEvent('resize', this, w, h, w, h);
127     }
128 });
129
130
131
132 /**
133  * @class Ext.ux.TaskButtonsPanel
134  * @extends Ext.BoxComponent
135  */
136 Ext.ux.TaskButtonsPanel = Ext.extend(Ext.BoxComponent, {
137     activeButton: null,
138     enableScroll: true,
139     scrollIncrement: 0,
140     scrollRepeatInterval: 400,
141     scrollDuration: .35,
142     animScroll: true,
143     resizeButtons: true,
144     buttonWidth: 168,
145     minButtonWidth: 118,
146     buttonMargin: 2,
147     buttonWidthSet: false,
148
149     initComponent : function() {
150         Ext.ux.TaskButtonsPanel.superclass.initComponent.call(this);
151         this.on('resize', this.delegateUpdates);
152         this.items = [];
153
154         this.stripWrap = Ext.get(this.el).createChild({
155             cls: 'ux-taskbuttons-strip-wrap',
156             cn: {
157                 tag:'ul', cls:'ux-taskbuttons-strip'
158             }
159         });
160         this.stripSpacer = Ext.get(this.el).createChild({
161             cls:'ux-taskbuttons-strip-spacer'
162         });
163         this.strip = new Ext.Element(this.stripWrap.dom.firstChild);
164
165         this.edge = this.strip.createChild({
166             tag:'li',
167             cls:'ux-taskbuttons-edge'
168         });
169         this.strip.createChild({
170             cls:'x-clear'
171         });
172     },
173
174     addButton : function(win){
175         var li = this.strip.createChild({tag:'li'}, this.edge); // insert before the edge
176         var btn = new Ext.ux.TaskBar.TaskButton(win, li);
177
178         this.items.push(btn);
179
180         if(!this.buttonWidthSet){
181             this.lastButtonWidth = btn.container.getWidth();
182         }
183
184         this.setActiveButton(btn);
185         return btn;
186     },
187
188     removeButton : function(btn){
189         var li = document.getElementById(btn.container.id);
190         btn.destroy();
191         li.parentNode.removeChild(li);
192
193         var s = [];
194         for(var i = 0, len = this.items.length; i < len; i++) {
195             if(this.items[i] != btn){
196                 s.push(this.items[i]);
197             }
198         }
199         this.items = s;
200
201         this.delegateUpdates();
202     },
203
204     setActiveButton : function(btn){
205         this.activeButton = btn;
206         this.delegateUpdates();
207     },
208
209     delegateUpdates : function(){
210         /*if(this.suspendUpdates){
211             return;
212         }*/
213         if(this.resizeButtons && this.rendered){
214             this.autoSize();
215         }
216         if(this.enableScroll && this.rendered){
217             this.autoScroll();
218         }
219     },
220
221     autoSize : function(){
222         var count = this.items.length;
223         var ow = this.el.dom.offsetWidth;
224         var aw = this.el.dom.clientWidth;
225
226         if(!this.resizeButtons || count < 1 || !aw){ // !aw for display:none
227             return;
228         }
229
230         var each = Math.max(Math.min(Math.floor((aw-4) / count) - this.buttonMargin, this.buttonWidth), this.minButtonWidth); // -4 for float errors in IE
231         var btns = this.stripWrap.dom.getElementsByTagName('button');
232
233         this.lastButtonWidth = Ext.get(btns[0].id).findParent('li').offsetWidth;
234
235         for(var i = 0, len = btns.length; i < len; i++) {
236             var btn = btns[i];
237
238             var tw = Ext.get(btns[i].id).findParent('li').offsetWidth;
239             var iw = btn.offsetWidth;
240
241             btn.style.width = (each - (tw-iw)) + 'px';
242         }
243     },
244
245     autoScroll : function(){
246         var count = this.items.length;
247         var ow = this.el.dom.offsetWidth;
248         var tw = this.el.dom.clientWidth;
249
250         var wrap = this.stripWrap;
251         var cw = wrap.dom.offsetWidth;
252         var pos = this.getScrollPos();
253         var l = this.edge.getOffsetsTo(this.stripWrap)[0] + pos;
254
255         if(!this.enableScroll || count < 1 || cw < 20){ // 20 to prevent display:none issues
256             return;
257         }
258
259         wrap.setWidth(tw); // moved to here because of problem in Safari
260
261         if(l <= tw){
262             wrap.dom.scrollLeft = 0;
263             //wrap.setWidth(tw); moved from here because of problem in Safari
264             if(this.scrolling){
265                 this.scrolling = false;
266                 this.el.removeClass('x-taskbuttons-scrolling');
267                 this.scrollLeft.hide();
268                 this.scrollRight.hide();
269             }
270         }else{
271             if(!this.scrolling){
272                 this.el.addClass('x-taskbuttons-scrolling');
273             }
274             tw -= wrap.getMargins('lr');
275             wrap.setWidth(tw > 20 ? tw : 20);
276             if(!this.scrolling){
277                 if(!this.scrollLeft){
278                     this.createScrollers();
279                 }else{
280                     this.scrollLeft.show();
281                     this.scrollRight.show();
282                 }
283             }
284             this.scrolling = true;
285             if(pos > (l-tw)){ // ensure it stays within bounds
286                 wrap.dom.scrollLeft = l-tw;
287             }else{ // otherwise, make sure the active button is still visible
288                 this.scrollToButton(this.activeButton, true); // true to animate
289             }
290             this.updateScrollButtons();
291         }
292     },
293
294     createScrollers : function(){
295         var h = this.el.dom.offsetHeight; //var h = this.stripWrap.dom.offsetHeight;
296
297         // left
298         var sl = this.el.insertFirst({
299             cls:'ux-taskbuttons-scroller-left'
300         });
301         sl.setHeight(h);
302         sl.addClassOnOver('ux-taskbuttons-scroller-left-over');
303         this.leftRepeater = new Ext.util.ClickRepeater(sl, {
304             interval : this.scrollRepeatInterval,
305             handler: this.onScrollLeft,
306             scope: this
307         });
308         this.scrollLeft = sl;
309
310         // right
311         var sr = this.el.insertFirst({
312             cls:'ux-taskbuttons-scroller-right'
313         });
314         sr.setHeight(h);
315         sr.addClassOnOver('ux-taskbuttons-scroller-right-over');
316         this.rightRepeater = new Ext.util.ClickRepeater(sr, {
317             interval : this.scrollRepeatInterval,
318             handler: this.onScrollRight,
319             scope: this
320         });
321         this.scrollRight = sr;
322     },
323
324     getScrollWidth : function(){
325         return this.edge.getOffsetsTo(this.stripWrap)[0] + this.getScrollPos();
326     },
327
328     getScrollPos : function(){
329         return parseInt(this.stripWrap.dom.scrollLeft, 10) || 0;
330     },
331
332     getScrollArea : function(){
333         return parseInt(this.stripWrap.dom.clientWidth, 10) || 0;
334     },
335
336     getScrollAnim : function(){
337         return {
338             duration: this.scrollDuration,
339             callback: this.updateScrollButtons,
340             scope: this
341         };
342     },
343
344     getScrollIncrement : function(){
345         return (this.scrollIncrement || this.lastButtonWidth+2);
346     },
347
348     /* getBtnEl : function(item){
349         return document.getElementById(item.id);
350     }, */
351
352     scrollToButton : function(item, animate){
353         item = item.el.dom.parentNode; // li
354         if(!item){ return; }
355         var el = item; //this.getBtnEl(item);
356         var pos = this.getScrollPos(), area = this.getScrollArea();
357         var left = Ext.fly(el).getOffsetsTo(this.stripWrap)[0] + pos;
358         var right = left + el.offsetWidth;
359         if(left < pos){
360             this.scrollTo(left, animate);
361         }else if(right > (pos + area)){
362             this.scrollTo(right - area, animate);
363         }
364     },
365
366     scrollTo : function(pos, animate){
367         this.stripWrap.scrollTo('left', pos, animate ? this.getScrollAnim() : false);
368         if(!animate){
369             this.updateScrollButtons();
370         }
371     },
372
373     onScrollRight : function(){
374         var sw = this.getScrollWidth()-this.getScrollArea();
375         var pos = this.getScrollPos();
376         var s = Math.min(sw, pos + this.getScrollIncrement());
377         if(s != pos){
378             this.scrollTo(s, this.animScroll);
379         }
380     },
381
382     onScrollLeft : function(){
383         var pos = this.getScrollPos();
384         var s = Math.max(0, pos - this.getScrollIncrement());
385         if(s != pos){
386             this.scrollTo(s, this.animScroll);
387         }
388     },
389
390     updateScrollButtons : function(){
391         var pos = this.getScrollPos();
392         this.scrollLeft[pos == 0 ? 'addClass' : 'removeClass']('ux-taskbuttons-scroller-left-disabled');
393         this.scrollRight[pos >= (this.getScrollWidth()-this.getScrollArea()) ? 'addClass' : 'removeClass']('ux-taskbuttons-scroller-right-disabled');
394     }
395 });
396
397
398
399 /**
400  * @class Ext.ux.TaskBar.TaskButton
401  * @extends Ext.Button
402  */
403 Ext.ux.TaskBar.TaskButton = function(win, el){
404     this.win = win;
405     Ext.ux.TaskBar.TaskButton.superclass.constructor.call(this, {
406         iconCls: win.iconCls,
407         text: Ext.util.Format.ellipsis(win.title, 12),
408         renderTo: el,
409         handler : function(){
410             if(win.minimized || win.hidden){
411                 win.show();
412             }else if(win == win.manager.getActive()){
413                 win.minimize();
414             }else{
415                 win.toFront();
416             }
417         },
418         clickEvent:'mousedown',
419         template: new Ext.Template(
420             '<table cellspacing="0" class="x-btn {3}"><tbody><tr>',
421             '<td class="ux-taskbutton-left"><i>&#160;</i></td>',
422             '<td class="ux-taskbutton-center"><em class="{5} unselectable="on">',
423                 '<button class="x-btn-text {2}" type="{1}" style="height:28px;">{0}</button>',
424             '</em></td>',
425             '<td class="ux-taskbutton-right"><i>&#160;</i></td>',
426             "</tr></tbody></table>")
427     });
428 };
429
430 Ext.extend(Ext.ux.TaskBar.TaskButton, Ext.Button, {
431     onRender : function(){
432         Ext.ux.TaskBar.TaskButton.superclass.onRender.apply(this, arguments);
433
434         this.cmenu = new Ext.menu.Menu({
435             items: [{
436                 text: 'Restore',
437                 handler: function(){
438                     if(!this.win.isVisible()){
439                         this.win.show();
440                     }else{
441                         this.win.restore();
442                     }
443                 },
444                 scope: this
445             },{
446                 text: 'Minimize',
447                 handler: this.win.minimize,
448                 scope: this.win
449             },{
450                 text: 'Maximize',
451                 handler: this.win.maximize,
452                 scope: this.win
453             }, '-', {
454                 text: 'Close',
455                 handler: this.closeWin.createDelegate(this, this.win, true),
456                 scope: this.win
457             }]
458         });
459
460         this.cmenu.on('beforeshow', function(){
461             var items = this.cmenu.items.items;
462             var w = this.win;
463             items[0].setDisabled(w.maximized !== true && w.hidden !== true);
464             items[1].setDisabled(w.minimized === true);
465             items[2].setDisabled(w.maximized === true || w.hidden === true);
466         }, this);
467
468         this.el.on('contextmenu', function(e){
469             e.stopEvent();
470             if(!this.cmenu.el){
471                 this.cmenu.render();
472             }
473             var xy = e.getXY();
474             xy[1] -= this.cmenu.el.getHeight();
475             this.cmenu.showAt(xy);
476         }, this);
477     },
478
479     closeWin : function(cMenu, e, win){
480         if(!win.isVisible()){
481             win.show();
482         }else{
483             win.restore();
484         }
485         win.close();
486     }
487 });