Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / examples / desktop / js / TaskBar.js
index bfbb787..0837014 100644 (file)
+/*
+
+This file is part of Ext JS 4
+
+Copyright (c) 2011 Sencha Inc
+
+Contact:  http://www.sencha.com/contact
+
+GNU General Public License Usage
+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.
+
+If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
+
+*/
 /*!
- * Ext JS Library 3.1.1
- * Copyright(c) 2006-2010 Ext JS, LLC
- * licensing@extjs.com
- * http://www.extjs.com/license
+ * Ext JS Library 4.0
+ * Copyright(c) 2006-2011 Sencha Inc.
+ * licensing@sencha.com
+ * http://www.sencha.com/license
  */
-/**\r
- * @class Ext.ux.TaskBar\r
- * @extends Ext.util.Observable\r
- */\r
-Ext.ux.TaskBar = function(app){\r
-    this.app = app;\r
-    this.init();\r
-}\r
-\r
-Ext.extend(Ext.ux.TaskBar, Ext.util.Observable, {\r
-    init : function(){\r
-        this.startMenu = new Ext.ux.StartMenu(Ext.apply({\r
-            iconCls: 'user',\r
-            height: 300,\r
-            shadow: true,\r
-            title: 'Jack Slocum',\r
-            width: 300\r
-        }, this.app.startConfig));\r
-\r
-        this.startBtn = new Ext.Button({\r
-            text: 'Start',\r
-            id: 'ux-startbutton',\r
-            iconCls:'start',\r
-            menu: this.startMenu,\r
-            menuAlign: 'bl-tl',\r
-            renderTo: 'ux-taskbar-start',\r
-            clickEvent: 'mousedown',\r
-            template: new Ext.Template(\r
-                '<table cellspacing="0" class="x-btn {3}"><tbody><tr>',\r
-                '<td class="ux-startbutton-left"><i>&#160;</i></td>',\r
-                '<td class="ux-startbutton-center"><em class="{5} unselectable="on">',\r
-                    '<button class="x-btn-text {2}" type="{1}" style="height:30px;">{0}</button>',\r
-                '</em></td>',\r
-                '<td class="ux-startbutton-right"><i>&#160;</i></td>',\r
-                "</tr></tbody></table>")\r
-        });\r
-\r
-        var width = this.startBtn.getEl().getWidth()+10;\r
-\r
-        var sbBox = new Ext.BoxComponent({\r
-            el: 'ux-taskbar-start',\r
-            id: 'TaskBarStart',\r
-            minWidth: width,\r
-            region:'west',\r
-            split: true,\r
-            width: width\r
-        });\r
-\r
-        this.tbPanel = new Ext.ux.TaskButtonsPanel({\r
-            el: 'ux-taskbuttons-panel',\r
-            id: 'TaskBarButtons',\r
-            region:'center'\r
-        });\r
-\r
-        var container = new Ext.ux.TaskBarContainer({\r
-            el: 'ux-taskbar',\r
-            layout: 'border',\r
-            items: [sbBox,this.tbPanel]\r
-        });\r
-\r
-        return this;\r
-    },\r
-\r
-    addTaskButton : function(win){\r
-        return this.tbPanel.addButton(win, 'ux-taskbuttons-panel');\r
-    },\r
-\r
-    removeTaskButton : function(btn){\r
-        this.tbPanel.removeButton(btn);\r
-    },\r
-\r
-    setActiveButton : function(btn){\r
-        this.tbPanel.setActiveButton(btn);\r
-    }\r
-});\r
-\r
-\r
-\r
-/**\r
- * @class Ext.ux.TaskBarContainer\r
- * @extends Ext.Container\r
- */\r
-Ext.ux.TaskBarContainer = Ext.extend(Ext.Container, {\r
-    initComponent : function() {\r
-        Ext.ux.TaskBarContainer.superclass.initComponent.call(this);\r
-\r
-        this.el = Ext.get(this.el) || Ext.getBody();\r
-        this.el.setHeight = Ext.emptyFn;\r
-        this.el.setWidth = Ext.emptyFn;\r
-        this.el.setSize = Ext.emptyFn;\r
-        this.el.setStyle({\r
-            overflow:'hidden',\r
-            margin:'0',\r
-            border:'0 none'\r
-        });\r
-        this.el.dom.scroll = 'no';\r
-        this.allowDomMove = false;\r
-        this.autoWidth = true;\r
-        this.autoHeight = true;\r
-        Ext.EventManager.onWindowResize(this.fireResize, this);\r
-        this.renderTo = this.el;\r
-    },\r
-\r
-    fireResize : function(w, h){\r
-        this.onResize(w, h, w, h);\r
-    }\r
-});\r
-\r
-\r
-\r
-/**\r
- * @class Ext.ux.TaskButtonsPanel\r
- * @extends Ext.BoxComponent\r
- */\r
-Ext.ux.TaskButtonsPanel = Ext.extend(Ext.BoxComponent, {\r
-    activeButton: null,\r
-    enableScroll: true,\r
-    scrollIncrement: 0,\r
-    scrollRepeatInterval: 400,\r
-    scrollDuration: .35,\r
-    animScroll: true,\r
-    resizeButtons: true,\r
-    buttonWidth: 168,\r
-    minButtonWidth: 118,\r
-    buttonMargin: 2,\r
-    buttonWidthSet: false,\r
-\r
-    initComponent : function() {\r
-        Ext.ux.TaskButtonsPanel.superclass.initComponent.call(this);\r
-        this.on('resize', this.delegateUpdates);\r
-        this.items = [];\r
-\r
-        this.stripWrap = Ext.get(this.el).createChild({\r
-            cls: 'ux-taskbuttons-strip-wrap',\r
-            cn: {\r
-                tag:'ul', cls:'ux-taskbuttons-strip'\r
-            }\r
-        });\r
-        this.stripSpacer = Ext.get(this.el).createChild({\r
-            cls:'ux-taskbuttons-strip-spacer'\r
-        });\r
-        this.strip = new Ext.Element(this.stripWrap.dom.firstChild);\r
-\r
-        this.edge = this.strip.createChild({\r
-            tag:'li',\r
-            cls:'ux-taskbuttons-edge'\r
-        });\r
-        this.strip.createChild({\r
-            cls:'x-clear'\r
-        });\r
-    },\r
-\r
-    addButton : function(win){\r
-        var li = this.strip.createChild({tag:'li'}, this.edge); // insert before the edge\r
-        var btn = new Ext.ux.TaskBar.TaskButton(win, li);\r
-\r
-        this.items.push(btn);\r
-\r
-        if(!this.buttonWidthSet){\r
-            this.lastButtonWidth = btn.container.getWidth();\r
-        }\r
-\r
-        this.setActiveButton(btn);\r
-        return btn;\r
-    },\r
-\r
-    removeButton : function(btn){\r
-        var li = document.getElementById(btn.container.id);\r
-        btn.destroy();\r
-        li.parentNode.removeChild(li);\r
-\r
-        var s = [];\r
-        for(var i = 0, len = this.items.length; i < len; i++) {\r
-            if(this.items[i] != btn){\r
-                s.push(this.items[i]);\r
-            }\r
-        }\r
-        this.items = s;\r
-\r
-        this.delegateUpdates();\r
-    },\r
-\r
-    setActiveButton : function(btn){\r
-        this.activeButton = btn;\r
-        this.delegateUpdates();\r
-    },\r
-\r
-    delegateUpdates : function(){\r
-        /*if(this.suspendUpdates){\r
-            return;\r
-        }*/\r
-        if(this.resizeButtons && this.rendered){\r
-            this.autoSize();\r
-        }\r
-        if(this.enableScroll && this.rendered){\r
-            this.autoScroll();\r
-        }\r
-    },\r
-\r
-    autoSize : function(){\r
-        var count = this.items.length;\r
-        var ow = this.el.dom.offsetWidth;\r
-        var aw = this.el.dom.clientWidth;\r
-\r
-        if(!this.resizeButtons || count < 1 || !aw){ // !aw for display:none\r
-            return;\r
-        }\r
-\r
-        var each = Math.max(Math.min(Math.floor((aw-4) / count) - this.buttonMargin, this.buttonWidth), this.minButtonWidth); // -4 for float errors in IE\r
-        var btns = this.stripWrap.dom.getElementsByTagName('button');\r
-\r
-        this.lastButtonWidth = Ext.get(btns[0].id).findParent('li').offsetWidth;\r
-\r
-        for(var i = 0, len = btns.length; i < len; i++) {\r
-            var btn = btns[i];\r
-\r
-            var tw = Ext.get(btns[i].id).findParent('li').offsetWidth;\r
-            var iw = btn.offsetWidth;\r
-\r
-            btn.style.width = (each - (tw-iw)) + 'px';\r
-        }\r
-    },\r
-\r
-    autoScroll : function(){\r
-        var count = this.items.length;\r
-        var ow = this.el.dom.offsetWidth;\r
-        var tw = this.el.dom.clientWidth;\r
-\r
-        var wrap = this.stripWrap;\r
-        var cw = wrap.dom.offsetWidth;\r
-        var pos = this.getScrollPos();\r
-        var l = this.edge.getOffsetsTo(this.stripWrap)[0] + pos;\r
-\r
-        if(!this.enableScroll || count < 1 || cw < 20){ // 20 to prevent display:none issues\r
-            return;\r
-        }\r
-\r
-        wrap.setWidth(tw); // moved to here because of problem in Safari\r
-\r
-        if(l <= tw){\r
-            wrap.dom.scrollLeft = 0;\r
-            //wrap.setWidth(tw); moved from here because of problem in Safari\r
-            if(this.scrolling){\r
-                this.scrolling = false;\r
-                this.el.removeClass('x-taskbuttons-scrolling');\r
-                this.scrollLeft.hide();\r
-                this.scrollRight.hide();\r
-            }\r
-        }else{\r
-            if(!this.scrolling){\r
-                this.el.addClass('x-taskbuttons-scrolling');\r
-            }\r
-            tw -= wrap.getMargins('lr');\r
-            wrap.setWidth(tw > 20 ? tw : 20);\r
-            if(!this.scrolling){\r
-                if(!this.scrollLeft){\r
-                    this.createScrollers();\r
-                }else{\r
-                    this.scrollLeft.show();\r
-                    this.scrollRight.show();\r
-                }\r
-            }\r
-            this.scrolling = true;\r
-            if(pos > (l-tw)){ // ensure it stays within bounds\r
-                wrap.dom.scrollLeft = l-tw;\r
-            }else{ // otherwise, make sure the active button is still visible\r
-                this.scrollToButton(this.activeButton, true); // true to animate\r
-            }\r
-            this.updateScrollButtons();\r
-        }\r
-    },\r
-\r
-    createScrollers : function(){\r
-        var h = this.el.dom.offsetHeight; //var h = this.stripWrap.dom.offsetHeight;\r
-\r
-        // left\r
-        var sl = this.el.insertFirst({\r
-            cls:'ux-taskbuttons-scroller-left'\r
-        });\r
-        sl.setHeight(h);\r
-        sl.addClassOnOver('ux-taskbuttons-scroller-left-over');\r
-        this.leftRepeater = new Ext.util.ClickRepeater(sl, {\r
-            interval : this.scrollRepeatInterval,\r
-            handler: this.onScrollLeft,\r
-            scope: this\r
-        });\r
-        this.scrollLeft = sl;\r
-\r
-        // right\r
-        var sr = this.el.insertFirst({\r
-            cls:'ux-taskbuttons-scroller-right'\r
-        });\r
-        sr.setHeight(h);\r
-        sr.addClassOnOver('ux-taskbuttons-scroller-right-over');\r
-        this.rightRepeater = new Ext.util.ClickRepeater(sr, {\r
-            interval : this.scrollRepeatInterval,\r
-            handler: this.onScrollRight,\r
-            scope: this\r
-        });\r
-        this.scrollRight = sr;\r
-    },\r
-\r
-    getScrollWidth : function(){\r
-        return this.edge.getOffsetsTo(this.stripWrap)[0] + this.getScrollPos();\r
-    },\r
-\r
-    getScrollPos : function(){\r
-        return parseInt(this.stripWrap.dom.scrollLeft, 10) || 0;\r
-    },\r
-\r
-    getScrollArea : function(){\r
-        return parseInt(this.stripWrap.dom.clientWidth, 10) || 0;\r
-    },\r
-\r
-    getScrollAnim : function(){\r
-        return {\r
-            duration: this.scrollDuration,\r
-            callback: this.updateScrollButtons,\r
-            scope: this\r
-        };\r
-    },\r
-\r
-    getScrollIncrement : function(){\r
-        return (this.scrollIncrement || this.lastButtonWidth+2);\r
-    },\r
-\r
-    /* getBtnEl : function(item){\r
-        return document.getElementById(item.id);\r
-    }, */\r
-\r
-    scrollToButton : function(item, animate){\r
-        item = item.el.dom.parentNode; // li\r
-        if(!item){ return; }\r
-        var el = item; //this.getBtnEl(item);\r
-        var pos = this.getScrollPos(), area = this.getScrollArea();\r
-        var left = Ext.fly(el).getOffsetsTo(this.stripWrap)[0] + pos;\r
-        var right = left + el.offsetWidth;\r
-        if(left < pos){\r
-            this.scrollTo(left, animate);\r
-        }else if(right > (pos + area)){\r
-            this.scrollTo(right - area, animate);\r
-        }\r
-    },\r
-\r
-    scrollTo : function(pos, animate){\r
-        this.stripWrap.scrollTo('left', pos, animate ? this.getScrollAnim() : false);\r
-        if(!animate){\r
-            this.updateScrollButtons();\r
-        }\r
-    },\r
-\r
-    onScrollRight : function(){\r
-        var sw = this.getScrollWidth()-this.getScrollArea();\r
-        var pos = this.getScrollPos();\r
-        var s = Math.min(sw, pos + this.getScrollIncrement());\r
-        if(s != pos){\r
-            this.scrollTo(s, this.animScroll);\r
-        }\r
-    },\r
-\r
-    onScrollLeft : function(){\r
-        var pos = this.getScrollPos();\r
-        var s = Math.max(0, pos - this.getScrollIncrement());\r
-        if(s != pos){\r
-            this.scrollTo(s, this.animScroll);\r
-        }\r
-    },\r
-\r
-    updateScrollButtons : function(){\r
-        var pos = this.getScrollPos();\r
-        this.scrollLeft[pos == 0 ? 'addClass' : 'removeClass']('ux-taskbuttons-scroller-left-disabled');\r
-        this.scrollRight[pos >= (this.getScrollWidth()-this.getScrollArea()) ? 'addClass' : 'removeClass']('ux-taskbuttons-scroller-right-disabled');\r
-    }\r
-});\r
-\r
-\r
-\r
-/**\r
- * @class Ext.ux.TaskBar.TaskButton\r
- * @extends Ext.Button\r
- */\r
-Ext.ux.TaskBar.TaskButton = function(win, el){\r
-    this.win = win;\r
-    Ext.ux.TaskBar.TaskButton.superclass.constructor.call(this, {\r
-        iconCls: win.iconCls,\r
-        text: Ext.util.Format.ellipsis(win.title, 12),\r
-        renderTo: el,\r
-        handler : function(){\r
-            if(win.minimized || win.hidden){\r
-                win.show();\r
-            }else if(win == win.manager.getActive()){\r
-                win.minimize();\r
-            }else{\r
-                win.toFront();\r
-            }\r
-        },\r
-        clickEvent:'mousedown',\r
-        template: new Ext.Template(\r
-            '<table cellspacing="0" class="x-btn {3}"><tbody><tr>',\r
-            '<td class="ux-taskbutton-left"><i>&#160;</i></td>',\r
-            '<td class="ux-taskbutton-center"><em class="{5} unselectable="on">',\r
-                '<button class="x-btn-text {2}" type="{1}" style="height:28px;">{0}</button>',\r
-            '</em></td>',\r
-            '<td class="ux-taskbutton-right"><i>&#160;</i></td>',\r
-            "</tr></tbody></table>")\r
-    });\r
-};\r
-\r
-Ext.extend(Ext.ux.TaskBar.TaskButton, Ext.Button, {\r
-    onRender : function(){\r
-        Ext.ux.TaskBar.TaskButton.superclass.onRender.apply(this, arguments);\r
-\r
-        this.cmenu = new Ext.menu.Menu({\r
-            items: [{\r
-                text: 'Restore',\r
-                handler: function(){\r
-                    if(!this.win.isVisible()){\r
-                        this.win.show();\r
-                    }else{\r
-                        this.win.restore();\r
-                    }\r
-                },\r
-                scope: this\r
-            },{\r
-                text: 'Minimize',\r
-                handler: this.win.minimize,\r
-                scope: this.win\r
-            },{\r
-                text: 'Maximize',\r
-                handler: this.win.maximize,\r
-                scope: this.win\r
-            }, '-', {\r
-                text: 'Close',\r
-                handler: this.closeWin.createDelegate(this, this.win, true),\r
-                scope: this.win\r
-            }]\r
-        });\r
-\r
-        this.cmenu.on('beforeshow', function(){\r
-            var items = this.cmenu.items.items;\r
-            var w = this.win;\r
-            items[0].setDisabled(w.maximized !== true && w.hidden !== true);\r
-            items[1].setDisabled(w.minimized === true);\r
-            items[2].setDisabled(w.maximized === true || w.hidden === true);\r
-        }, this);\r
-\r
-        this.el.on('contextmenu', function(e){\r
-            e.stopEvent();\r
-            if(!this.cmenu.el){\r
-                this.cmenu.render();\r
-            }\r
-            var xy = e.getXY();\r
-            xy[1] -= this.cmenu.el.getHeight();\r
-            this.cmenu.showAt(xy);\r
-        }, this);\r
-    },\r
-\r
-    closeWin : function(cMenu, e, win){\r
-        if(!win.isVisible()){\r
-            win.show();\r
-        }else{\r
-            win.restore();\r
-        }\r
-        win.close();\r
-    }\r
-});
\ No newline at end of file
+
+/**
+ * @class Ext.ux.desktop.TaskBar
+ * @extends Ext.toolbar.Toolbar
+ */
+Ext.define('Ext.ux.desktop.TaskBar', {
+    extend: 'Ext.toolbar.Toolbar', // TODO - make this a basic hbox panel...
+
+    requires: [
+        'Ext.button.Button',
+        'Ext.resizer.Splitter',
+        'Ext.menu.Menu',
+
+        'Ext.ux.desktop.StartMenu'
+    ],
+
+    alias: 'widget.taskbar',
+
+    cls: 'ux-taskbar',
+
+    /**
+     * @cfg {String} startBtnText
+     * The text for the Start Button.
+     */
+    startBtnText: 'Start',
+
+    initComponent: function () {
+        var me = this;
+
+        me.startMenu = new Ext.ux.desktop.StartMenu(me.startConfig);
+
+        me.quickStart = new Ext.toolbar.Toolbar(me.getQuickStart());
+
+        me.windowBar = new Ext.toolbar.Toolbar(me.getWindowBarConfig());
+
+        me.tray = new Ext.toolbar.Toolbar(me.getTrayConfig());
+
+        me.items = [
+            {
+                xtype: 'button',
+                cls: 'ux-start-button',
+                iconCls: 'ux-start-button-icon',
+                menu: me.startMenu,
+                menuAlign: 'bl-tl',
+                text: me.startBtnText
+            },
+            me.quickStart,
+            {
+                xtype: 'splitter', html: '&#160;',
+                height: 14, width: 2, // TODO - there should be a CSS way here
+                cls: 'x-toolbar-separator x-toolbar-separator-horizontal'
+            },
+            //'-',
+            me.windowBar,
+            '-',
+            me.tray
+        ];
+
+        me.callParent();
+    },
+
+    afterLayout: function () {
+        var me = this;
+        me.callParent();
+        me.windowBar.el.on('contextmenu', me.onButtonContextMenu, me);
+    },
+
+    /**
+     * This method returns the configuration object for the Quick Start toolbar. A derived
+     * class can override this method, call the base version to build the config and
+     * then modify the returned object before returning it.
+     */
+    getQuickStart: function () {
+        var me = this, ret = {
+            minWidth: 20,
+            width: 60,
+            items: [],
+            enableOverflow: true
+        };
+
+        Ext.each(this.quickStart, function (item) {
+            ret.items.push({
+                tooltip: { text: item.name, align: 'bl-tl' },
+                //tooltip: item.name,
+                overflowText: item.name,
+                iconCls: item.iconCls,
+                module: item.module,
+                handler: me.onQuickStartClick,
+                scope: me
+            });
+        });
+
+        return ret;
+    },
+
+    /**
+     * This method returns the configuration object for the Tray toolbar. A derived
+     * class can override this method, call the base version to build the config and
+     * then modify the returned object before returning it.
+     */
+    getTrayConfig: function () {
+        var ret = {
+            width: 80,
+            items: this.trayItems
+        };
+        delete this.trayItems;
+        return ret;
+    },
+
+    getWindowBarConfig: function () {
+        return {
+            flex: 1,
+            cls: 'ux-desktop-windowbar',
+            items: [ '&#160;' ],
+            layout: { overflowHandler: 'Scroller' }
+        };
+    },
+
+    getWindowBtnFromEl: function (el) {
+        var c = this.windowBar.getChildByElement(el);
+        return c || null;
+    },
+
+    onQuickStartClick: function (btn) {
+        var module = this.app.getModule(btn.module);
+        if (module) {
+            module.createWindow();
+        }
+    },
+    
+    onButtonContextMenu: function (e) {
+        var me = this, t = e.getTarget(), btn = me.getWindowBtnFromEl(t);
+        if (btn) {
+            e.stopEvent();
+            me.windowMenu.theWin = btn.win;
+            me.windowMenu.showBy(t);
+        }
+    },
+
+    onWindowBtnClick: function (btn) {
+        var win = btn.win;
+
+        if (win.minimized || win.hidden) {
+            win.show();
+        } else if (win.active) {
+            win.minimize();
+        } else {
+            win.toFront();
+        }
+    },
+
+    addTaskButton: function(win) {
+        var config = {
+            iconCls: win.iconCls,
+            enableToggle: true,
+            toggleGroup: 'all',
+            width: 140,
+            text: Ext.util.Format.ellipsis(win.title, 20),
+            listeners: {
+                click: this.onWindowBtnClick,
+                scope: this
+            },
+            win: win
+        };
+
+        var cmp = this.windowBar.add(config);
+        cmp.toggle(true);
+        return cmp;
+    },
+
+    removeTaskButton: function (btn) {
+        var found, me = this;
+        me.windowBar.items.each(function (item) {
+            if (item === btn) {
+                found = item;
+            }
+            return !found;
+        });
+        if (found) {
+            me.windowBar.remove(found);
+        }
+        return found;
+    },
+
+    setActiveButton: function(btn) {
+        if (btn) {
+            btn.toggle(true);
+        } else {
+            this.windowBar.items.each(function (item) {
+                if (item.isButton) {
+                    item.toggle(false);
+                }
+            });
+        }
+    }
+});
+
+/**
+ * @class Ext.ux.desktop.TrayClock
+ * @extends Ext.toolbar.TextItem
+ * This class displays a clock on the toolbar.
+ */
+Ext.define('Ext.ux.desktop.TrayClock', {
+    extend: 'Ext.toolbar.TextItem',
+
+    alias: 'widget.trayclock',
+
+    cls: 'ux-desktop-trayclock',
+
+    html: '&#160;',
+
+    timeFormat: 'g:i A',
+
+    tpl: '{time}',
+
+    initComponent: function () {
+        var me = this;
+
+        me.callParent();
+
+        if (typeof(me.tpl) == 'string') {
+            me.tpl = new Ext.XTemplate(me.tpl);
+        }
+    },
+
+    afterRender: function () {
+        var me = this;
+        Ext.Function.defer(me.updateTime, 100, me);
+        me.callParent();
+    },
+
+    onDestroy: function () {
+        var me = this;
+
+        if (me.timer) {
+            window.clearTimeout(me.timer);
+            me.timer = null;
+        }
+
+        me.callParent();
+    },
+
+    updateTime: function () {
+        var me = this, time = Ext.Date.format(new Date(), me.timeFormat),
+            text = me.tpl.apply({ time: time });
+        if (me.lastText != text) {
+            me.setText(text);
+            me.lastText = text;
+        }
+        me.timer = Ext.Function.defer(me.updateTime, 10000, me);
+    }
+});
+