Upgrade to ExtJS 3.1.1 - Released 02/08/2010
[extjs.git] / examples / desktop / js / TaskBar.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 /**\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.onResize(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 });