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