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