網頁

搜尋此網誌

2010年1月3日 星期日

Ext JS

使用Ext JS程式庫到現在將近兩個多月,直接和大家說:這是個好東西!學習和使用曲線都不會很困難,而且Ext JS的API寫得十分詳盡,參考http://www.extjs.com/deploy/dev/docs/,對於初學者來說,可以參考Community Learning Center  http://www.extjs.com/learn/Main_Page(這個網址不是很好找),大家可以上去看看!

當你要使用Ext JS時,基本上僅需加入下列這三列程式碼:

<link rel="stylesheet" type="text/css" href="ext/resources/css/ext-all.css" />
<script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext/ext-all.js"></script>

另外建立一個自己的JavaScript檔案,內容大概是這樣:
Ext.BLANK_IMAGE_URL = 'ext/resources/images/default/s.gif';
Ext.onReady(function(){
//填入你的程式碼
});
onReady( Function fn, [Object scope], [boolean options] ) : void實際上是onDocumentReady( Function fn, [Object scope], [boolean options] ) : void的縮寫,此函式方法需要三個參數(parameter),後兩個可選擇使用,因此呼叫時需要傳遞引數(argument)來呼叫。

目前最新的版本是3.1.0,我從3.0.0和3.0.3用到現在,程式庫的更新也都很方便,只要將檔案更換就可以繼續使用新功能。

一樣的,推薦一本書:
徐會生、何啟偉、康愛媛,Ext JS開發實戰:次世代Ajax解決方案,台北:精誠資訊(悅知文化),2009。

Ext JS中所有的物件都是Ext.Component元件,元件的設定都是使用JSON格式(沒有使用過Ext JS要特別注意和熟悉)。

另外,因為開發Web Desktop網頁應用程式的需求,因而使用ext-3.1.0\examples\desktop的範例程式,加上分析與修改程式碼符合自己的需要,在這裡貼上程式的五個Ext JS的JavaScript供大家參考。

App.js

/*!
 * Ext JS Library 3.0.3
 * Copyright(c) 2006-2009 Ext JS, LLC
 * licensing@extjs.com
 * http://www.extjs.com/license
 */
/*--------------------------------------------------*/
//定義桌面應用程式物件
Ext.app.App = function(cfg){
    Ext.apply(this, cfg);//複製cfg屬性到本物件
    //自行定義兩個事件為ready與beforeunload
    this.addEvents({
        'ready': true,//自行定義
        'beforeunload': true//自行定義
    });
    
    Ext.onReady(this.initApp, this);//呼叫initApp方法,初始化物件
};
/*--------------------------------------------------*/
//定義桌面應用程式物件子類別Ext.app.App,繼承父類別Ext.util.Observable。
Ext.extend(Ext.app.App, Ext.util.Observable, {
    //以下為繼承之後新增的成員
    isReady: false,
    startMenu: null,//開始選單
    modules: null,//應用程式模組
    getStartConfig: function(){//讓使用者建立物件時填入
    },
    
    //建立桌面應用程式物件之後,會執行initApp函數
    initApp: function(){//初始化桌面應用程式
        this.startConfig = this.startConfig || this.getStartConfig();//開始功能表組態
        this.desktop = new Ext.Desktop(this);//建立桌面物件,參考Desktop.js
        //desktop物件之中,包含taskbar物件,其中taskbar物件含有startMenu
        this.launcher = this.desktop.taskbar.startMenu;
        //launcher發射器
        
        this.modules = this.getModules();//取得模組建立
        if (this.modules) {
            this.initModules(this.modules);//如果模組存在,初始化模組
        }
        
        this.init();
        
        //appends an event handler to an element, shorthand for addListener
        //參數:HTML元素,事件名稱,事件處理函數,執行範圍
        Ext.EventManager.on(window, 'beforeunload', this.onUnload, this);
        
        //觸發ready事件
        this.fireEvent('ready', this);
        this.isReady = true;//完成初始化
    },
    
    getModules: Ext.emptyFn,//A reusable empty function讓使用者建立物件時填入
    init: Ext.emptyFn,//A reusable empty function讓使用者建立物件時填入
    
 //這裡將模組加入開始功能表
    initModules: function(ms){//初始化模組
        for (var i = 0, len = ms.length; i < len; i++) {
            var m = ms[i];
   //modify!!
   if(m.show==true)
             this.launcher.add(m.launcher);
            m.app = this;
        }
    },
    
    getModule: function(name){//取得模組
        var ms = this.modules;
        for (var i = 0, len = ms.length; i < len; i++) {
            if (ms[i].id == name || ms[i].appType == name) {
                return ms[i];
            }
        }
        return '';
    },
    
    //定義事件處理
    onReady: function(fn, scope){
        if (!this.isReady) {
            this.on('ready', fn, scope);
        }
        else {
            fn.call(scope, this);
        }
    },
    
    getDesktop: function(){
        return this.desktop;
    },
    
    //定義事件處理
    onUnload: function(e){
        if (this.fireEvent('beforeunload', this) === false) {
            e.stopEvent();
        }
    }
});
/*--------------------------------------------------*/



Desktop.js

/*!
 * Ext JS Library 3.0.3
 * Copyright(c) 2006-2009 Ext JS, LLC
 * licensing@extjs.com
 * http://www.extjs.com/license
 */
/*--------------------------------------------------*/
//定義桌面物件(函數物件)
Ext.Desktop = function(app){
 //呼叫new Ext.Desktop(this);時,將執行下列指令碼
    this.taskbar = new Ext.ux.TaskBar(app);//新增工作列
    /*--------------------------------------------------*/
 //定義區域變數
    var taskbar = this.taskbar;//工作列物件
    var desktopEl = Ext.get('x-desktop');//桌面DOM元素物件
    var taskbarEl = Ext.get('ux-taskbar');//工作列DOM元素物件
    var shortcuts = Ext.get('x-shortcuts');//桌面捷徑DOM元素物件
    var windows = new Ext.WindowGroup();//視窗群組
    var activeWindow;//目前正在動作的視窗
    /*--------------------------------------------------*/
 //定義函數變數
    function minimizeWin(win){//最小化視窗
        win.minimized = true;
        win.hide();
    }
    
    function markActive(win){
        if (activeWindow && activeWindow != win) {
            markInactive(activeWindow);
        }
        taskbar.setActiveButton(win.taskButton);
        activeWindow = win;
        Ext.fly(win.taskButton.el).addClass('active-win');
        win.minimized = false;
    }
    
    function markInactive(win){
        if (win == activeWindow) {
            activeWindow = null;
            Ext.fly(win.taskButton.el).removeClass('active-win');
        }
    }
    
    function removeWin(win){//移動視窗
        taskbar.removeTaskButton(win.taskButton);
        layout();
    }
    
    function layout(){
        desktopEl.setHeight(Ext.lib.Dom.getViewHeight() - taskbarEl.getHeight());
    }
    
    /*--------------------------------------------------*/
    //當WindowsResize時觸發layout函數
    Ext.EventManager.onWindowResize(layout);
    
 //定義物件的屬性與方法(this.開始的)
    this.layout = layout;
    
    this.createWindow = function(config, cls){//建立視窗
        var win = new (cls || Ext.Window)(Ext.applyIf(config || {}, {
            manager: windows,
            minimizable: true,
            maximizable: true
        }));
        win.render(desktopEl);
        win.taskButton = taskbar.addTaskButton(win);
        
        win.cmenu = new Ext.menu.Menu({
            items: []
        });
        
        win.animateTarget = win.taskButton.el;
        
        win.on({
            'activate': {
                fn: markActive
            },
            'beforeshow': {
                fn: markActive
            },
            'deactivate': {
                fn: markInactive
            },
            'minimize': {
                fn: minimizeWin
            },
            'close': {
                fn: removeWin
            }
        });
        
        layout();//呼叫私有函數function layout()
        return win;
    };
    
    this.getManager = function(){
        return windows;
    };
    
    this.getWindow = function(id){//取得特定ID之視窗
        return windows.get(id);
    }
    
    this.getWinWidth = function(){//取得視窗寬度
        var width = Ext.lib.Dom.getViewWidth();
        return width < 200 ? 200 : width;
    }
    
    this.getWinHeight = function(){//取得視窗高度
        var height = (Ext.lib.Dom.getViewHeight() - taskbarEl.getHeight());
        return height < 100 ? 100 : height;
    }
    
    this.getWinX = function(width){//取得視窗X座標
        return (Ext.lib.Dom.getViewWidth() - width) / 2
    }
    
    this.getWinY = function(height){//取得視窗Y座標
        return (Ext.lib.Dom.getViewHeight() - taskbarEl.getHeight() - height) / 2;
    }
    /*--------------------------------------------------*/
    layout();
    
    if (shortcuts) {
        shortcuts.on('click', function(e, t){//Ext.lib.Event事件程式庫,Ext.EventObject
            if (t = e.getTarget('dt', shortcuts)) {
                e.stopEvent();//停止事件
                var module = app.getModule(t.id.replace('-shortcut', ''));
                if (module) {
                    module.createWindow();//當點選時,執行模組內部的createWindow函數
                }
            }
        });
    }
    
};

Module.js

/*!
 * Ext JS Library 3.0.3
 * Copyright(c) 2006-2009 Ext JS, LLC
 * licensing@extjs.com
 * http://www.extjs.com/license
 */
/*--------------------------------------------------*/
//定義桌面模組物件
Ext.app.Module = function(config){
    Ext.apply(this, config);//複製config的屬性至this物件
    Ext.app.Module.superclass.constructor.call(this);
    this.init();
}
/*--------------------------------------------------*/
//定義桌面模組物件子類別Ext.app.Module,繼承父類別Ext.util.Observable。
Ext.extend(Ext.app.Module, Ext.util.Observable, {
 //新增成員函數
    init: Ext.emptyFn//a reusable empty function讓使用者建立物件時填入
});
/*--------------------------------------------------*/

StartMenu.js

/*!
 * Ext JS Library 3.0.3
 * Copyright(c) 2006-2009 Ext JS, LLC
 * licensing@extjs.com
 * http://www.extjs.com/license
 */
/**
 * @class Ext.ux.StartMenu
 * @extends Ext.menu.Menu
 * A start menu object.
 * @constructor
 * Creates a new StartMenu
 * @param {Object} config Configuration options
 *
 * SAMPLE USAGE:
 *
 * this.startMenu = new Ext.ux.StartMenu({
 *  iconCls: 'user',
 *  height: 300,
 *  shadow: true,
 *  title: get_cookie('memberName'),
 *  width: 300
 * });
 *
 * this.startMenu.add({
 *  text: 'Grid Window',
 *  iconCls:'icon-grid',
 *  handler : this.createWindow,
 *  scope: this
 * });
 *
 * this.startMenu.addTool({
 *  text:'Logout',
 *  iconCls:'logout',
 *  handler:function(){ window.location = "logout.php"; },
 *  scope:this
 * });
 */
/*--------------------------------------------------*/
//開始功能表
Ext.namespace("Ext.ux");
//由ExtJS建立兩個物件,分別是Ext和Ext.ux兩個物件,避免命名衝突

/*--------------------------------------------------*/
//定義StartMenu物件繼承Ext.menu.Menu物件建立子物件
Ext.ux.StartMenu = Ext.extend(Ext.menu.Menu, {
 
 //初始化元件
    initComponent: function(config) {//覆寫父物件方法
     Ext.ux.StartMenu.superclass.initComponent.call(this, config);

        var tools = this.toolItems;//工具項
        this.toolItems = new Ext.util.MixedCollection();//混合型集合類別
        if(tools){
            this.addTool.apply(this, tools);//複製tools至this物件
        }
    },

    //物件的方法
    onRender : function(ct, position){
        Ext.ux.StartMenu.superclass.onRender.call(this, ct, position);
        var el = this.el.addClass('ux-start-menu');

        var header = el.createChild({
         tag: "div",
         cls: "x-window-header x-unselectable x-panel-icon "+this.iconCls
        });

  this.header = header;

  var headerText = header.createChild({
   tag: "span",
   cls: "x-window-header-text"
  });
  var tl = header.wrap({
   cls: "ux-start-menu-tl"
  });
  var tr = header.wrap({
   cls: "ux-start-menu-tr"
  });
  var tc = header.wrap({
   cls: "ux-start-menu-tc"
  });

  this.menuBWrap = el.createChild({
   tag: "div",
   cls: "x-window-body x-border-layout-ct ux-start-menu-body"
  });
  var ml = this.menuBWrap.wrap({
   cls: "ux-start-menu-ml"
  });
  var mc = this.menuBWrap.wrap({
   cls: "x-window-mc ux-start-menu-bwrap"
  });

  this.menuPanel = this.menuBWrap.createChild({
   tag: "div",
   cls: "x-panel x-border-panel ux-start-menu-apps-panel"
  });
  this.toolsPanel = this.menuBWrap.createChild({
   tag: "div",
   cls: "x-panel x-border-panel ux-start-menu-tools-panel"
  });

  var bwrap = ml.wrap({cls: "x-window-bwrap"});
  var bc = bwrap.createChild({
   tag: "div",
   cls: "ux-start-menu-bc"
  });
  var bl = bc.wrap({
   cls: "ux-start-menu-bl x-panel-nofooter"
  });
  var br = bc.wrap({
   cls: "ux-start-menu-br"
  });

        this.ul.appendTo(this.menuPanel);

        var toolsUl = this.toolsPanel.createChild({
         tag: "ul",
         cls: "x-menu-list"
        });

        this.mon(toolsUl, 'click', this.onClick, this);
        this.mon(toolsUl, 'mouseover', this.onMouseOver, this);
        this.mon(toolsUl, 'mouseout', this.onMouseOut, this);

        this.items.each(function(item){
            item.parentMenu = this;
        }, this);

        this.toolItems.each(
         function(item){
             var li = document.createElement("li");
             li.className = "x-menu-list-item";
             toolsUl.dom.appendChild(li);
             item.render(li);
                item.parentMenu = this;
         }, this);

        this.toolsUl = toolsUl;

        this.menuBWrap.setStyle('position', 'relative');
        this.menuBWrap.setHeight(this.height - 28);

        this.menuPanel.setStyle({
         padding: '2px',
         position: 'absolute',
         overflow: 'auto'
        });

        this.toolsPanel.setStyle({
         padding: '2px 4px 2px 2px',
         position: 'absolute',
         overflow: 'auto'
        });

        this.setTitle(this.title);
    },

    //物件的方法
    findTargetItem : function(e){
        var t = e.getTarget(".x-menu-list-item", this.ul,  true);
        if(t && t.menuItemId){
         if(this.items.get(t.menuItemId)){
             return this.items.get(t.menuItemId);
            }else{
             return this.toolItems.get(t.menuItemId);
            }
        }
    },

    /**
     * Displays this menu relative to another element
     * @param {Mixed} element The element to align to
     * @param {String} position (optional) The {@link Ext.Element#alignTo} anchor position to use in aligning to
     * the element (defaults to this.defaultAlign)
     * @param {Ext.ux.StartMenu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
     */
    show : function(el, pos, parentMenu){
        this.parentMenu = parentMenu;
        if(!this.el){
            this.render();
        }

        this.fireEvent("beforeshow", this);
        this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
        var tPanelWidth = 120;
        var box = this.menuBWrap.getBox();
        this.menuPanel.setWidth(box.width-tPanelWidth);
        this.menuPanel.setHeight(box.height);

        this.toolsPanel.setWidth(tPanelWidth);
        this.toolsPanel.setX(box.x+box.width-tPanelWidth);
        this.toolsPanel.setHeight(box.height);
    },

    addTool : function(){
        var a = arguments, l = a.length, item;
        for(var i = 0; i < l; i++){
            var el = a[i];
            if(el.render){ // some kind of Item
                item = this.addToolItem(el);
            }else if(typeof el == "string"){ // string
                if(el == "separator" || el == "-"){
                    item = this.addToolSeparator();
                }else{
                    item = this.addText(el);
                }
            }else if(el.tagName || el.el){ // element
                item = this.addElement(el);
            }else if(typeof el == "object"){ // must be menu item config?
                item = this.addToolMenuItem(el);
            }
        }
        return item;
    },

    /**
     * Adds a separator bar to the Tools
     * @return {Ext.menu.Item} The menu item that was added
     */
    addToolSeparator : function(){
        return this.addToolItem(new Ext.menu.Separator({itemCls: 'ux-toolmenu-sep'}));
    },

    addToolItem : function(item){
        this.toolItems.add(item);
        if(this.ul){
            var li = document.createElement("li");
            li.className = "x-menu-list-item";
            this.ul.dom.appendChild(li);
            item.render(li, this);
            this.delayAutoWidth();
        }
        return item;
    },

    addToolMenuItem : function(config){
        if(!(config instanceof Ext.menu.Item)){
            if(typeof config.checked == "boolean"){ // must be check menu item config?
                config = new Ext.menu.CheckItem(config);
            }else{
                config = new Ext.menu.Item(config);
            }
        }
        return this.addToolItem(config);
    },

    setTitle : function(title, iconCls){
        this.title = title;
        this.header.child('span').update(title);
        return this;
    }
});

TaskBar.js

/*!
 * Ext JS Library 3.0.3
 * Copyright(c) 2006-2009 Ext JS, LLC
 * licensing@extjs.com
 * http://www.extjs.com/license
 */
/**
 * @class Ext.ux.TaskBar
 * @extends Ext.util.Observable
 */
/*--------------------------------------------------*/
//定義工作列物件
Ext.ux.TaskBar = function(app){
    this.app = app; 
    this.init();
}

/*--------------------------------------------------*/
//子類別Ext.ux.TaskBar,繼承父類別Ext.util.Observable。(3-argument)
Ext.extend(Ext.ux.TaskBar, Ext.util.Observable, {
 
 //新增初始化成員函數
    init : function(){
  //建立開始功能表物件
  this.startMenu = new Ext.ux.StartMenu(Ext.apply({//複製開始功能表組態
   iconCls: 'user',
   height: 300,
   shadow: true,
   title: 'Web Desktop',
   width: 300
  }, this.app.startConfig));
  
  this.startBtn = new Ext.Button({
            text: '開始',
            id: 'ux-startbutton',
            iconCls:'start',
            menu: this.startMenu,//設定開始選單
            menuAlign: 'bl-tl',//對齊buttom left corner + top left corner
            renderTo: 'ux-taskbar-start',
            clickEvent: 'mousedown',
            template: new Ext.Template(
    '<table cellspacing="0" class="x-btn {3}"><tbody><tr>',
    '<td class="ux-startbutton-left"><i>&#160;</i></td>',
                '<td class="ux-startbutton-center"><em class="{5} unselectable="on">',
                    '<button class="x-btn-text {2}" type="{1}" style="height:30px;">{0}</button>',
                '</em></td>',
                '<td class="ux-startbutton-right"><i>&#160;</i></td>',
    "</tr></tbody></table>")
        });

        var width = this.startBtn.getEl().getWidth()+10;
        
  //開始功能表容器
        var sbBox = new Ext.BoxComponent({
   el: 'ux-taskbar-start',
         id: 'TaskBarStart',
         minWidth: width,
   region:'west',
   split: true,
   width: width
  });
  
  //工作列按鈕容器
  this.tbPanel = new Ext.ux.TaskButtonsPanel({
   el: 'ux-taskbuttons-panel',
   id: 'TaskBarButtons',
   region:'center'
  });
  
  //工作列配置容器,使用border配置,包含sbBox與tbPanel兩元素   
        var container = new Ext.ux.TaskBarContainer({
   el: 'ux-taskbar',
   layout: 'border',
   items: [sbBox,this.tbPanel]
  });
  
  return this;
    },
    
 //新增成員函數
    addTaskButton : function(win){
  return this.tbPanel.addButton(win, 'ux-taskbuttons-panel');
 },
 //新增成員函數
 removeTaskButton : function(btn){
  this.tbPanel.removeButton(btn);
 },
 //新增成員函數
 setActiveButton : function(btn){
  this.tbPanel.setActiveButton(btn);
 }
});


/*--------------------------------------------------*/
/**
 * @class Ext.ux.TaskBarContainer
 * @extends Ext.Container
 */
//子類別Ext.ux.TaskBarContainer,繼承父類別Ext.Container。(2-argument)
Ext.ux.TaskBarContainer = Ext.extend(Ext.Container, {
 
 //新增成員函數
    initComponent : function() {
        Ext.ux.TaskBarContainer.superclass.initComponent.call(this);
        
        this.el = Ext.get(this.el) || Ext.getBody();
        this.el.setHeight = Ext.emptyFn;
        this.el.setWidth = Ext.emptyFn;
        this.el.setSize = Ext.emptyFn;
        this.el.setStyle({
            overflow:'hidden',
            margin:'0',
            border:'0 none'
        });
        this.el.dom.scroll = 'no';
        this.allowDomMove = false;
        this.autoWidth = true;
        this.autoHeight = true;
        Ext.EventManager.onWindowResize(this.fireResize, this);
        this.renderTo = this.el;
    },
 
 //新增成員函數
    fireResize : function(w, h){
        this.fireEvent('resize', this, w, h, w, h);
    }
});


/*--------------------------------------------------*/
/**
 * @class Ext.ux.TaskButtonsPanel
 * @extends Ext.BoxComponent
 */
//子類別Ext.ux.TaskBarContainer,繼承父類別Ext.Container。(2-argument)
Ext.ux.TaskButtonsPanel = Ext.extend(Ext.BoxComponent, {//工作列按鈕容器
 activeButton: null,
 enableScroll: true,
 scrollIncrement: 0,
    scrollRepeatInterval: 400,
    scrollDuration: .35,
    animScroll: true,
    resizeButtons: true,
    buttonWidth: 168,
    minButtonWidth: 118,
    buttonMargin: 2,
    buttonWidthSet: false,
 
 initComponent : function() {
        Ext.ux.TaskButtonsPanel.superclass.initComponent.call(this);
        this.on('resize', this.delegateUpdates);
        this.items = [];
        
        this.stripWrap = Ext.get(this.el).createChild({
         cls: 'ux-taskbuttons-strip-wrap',
         cn: {
             tag:'ul', cls:'ux-taskbuttons-strip'
            }
  });
        this.stripSpacer = Ext.get(this.el).createChild({
         cls:'ux-taskbuttons-strip-spacer'
        });
        this.strip = new Ext.Element(this.stripWrap.dom.firstChild);
        
        this.edge = this.strip.createChild({
         tag:'li',
         cls:'ux-taskbuttons-edge'
        });
        this.strip.createChild({
         cls:'x-clear'
        });
 },
 
 addButton : function(win){
  var li = this.strip.createChild({tag:'li'}, this.edge); // insert before the edge
        var btn = new Ext.ux.TaskBar.TaskButton(win, li);
  
  this.items.push(btn);
  
  if(!this.buttonWidthSet){
   this.lastButtonWidth = btn.container.getWidth();
  }
  
  this.setActiveButton(btn);
  return btn;
 },
 
 removeButton : function(btn){
  var li = document.getElementById(btn.container.id);
  btn.destroy();
  li.parentNode.removeChild(li);
  
  var s = [];
  for(var i = 0, len = this.items.length; i < len; i++) {
   if(this.items[i] != btn){
    s.push(this.items[i]);
   }
  }
  this.items = s;
  
  this.delegateUpdates();
 },
 
 setActiveButton : function(btn){
  this.activeButton = btn;
  this.delegateUpdates();
 },
 
 delegateUpdates : function(){
  /*if(this.suspendUpdates){
            return;
        }*/
        if(this.resizeButtons && this.rendered){
            this.autoSize();
        }
        if(this.enableScroll && this.rendered){
            this.autoScroll();
        }
    },
    
    autoSize : function(){
        var count = this.items.length;
        var ow = this.el.dom.offsetWidth;
        var aw = this.el.dom.clientWidth;

        if(!this.resizeButtons || count < 1 || !aw){ // !aw for display:none
            return;
        }
        
        var each = Math.max(Math.min(Math.floor((aw-4) / count) - this.buttonMargin, this.buttonWidth), this.minButtonWidth); // -4 for float errors in IE
        var btns = this.stripWrap.dom.getElementsByTagName('button');
        
        this.lastButtonWidth = Ext.get(btns[0].id).findParent('li').offsetWidth;
        
        for(var i = 0, len = btns.length; i < len; i++) {            
            var btn = btns[i];
            
            var tw = Ext.get(btns[i].id).findParent('li').offsetWidth;
            var iw = btn.offsetWidth;
            
            btn.style.width = (each - (tw-iw)) + 'px';
        }
    },
    
    autoScroll : function(){
     var count = this.items.length;
        var ow = this.el.dom.offsetWidth;
        var tw = this.el.dom.clientWidth;
        
        var wrap = this.stripWrap;
        var cw = wrap.dom.offsetWidth;
        var pos = this.getScrollPos();
        var l = this.edge.getOffsetsTo(this.stripWrap)[0] + pos;
        
        if(!this.enableScroll || count < 1 || cw < 20){ // 20 to prevent display:none issues
            return;
        }
        
        wrap.setWidth(tw); // moved to here because of problem in Safari
        
        if(l <= tw){
            wrap.dom.scrollLeft = 0;
            //wrap.setWidth(tw); moved from here because of problem in Safari
            if(this.scrolling){
                this.scrolling = false;
                this.el.removeClass('x-taskbuttons-scrolling');
                this.scrollLeft.hide();
                this.scrollRight.hide();
            }
        }else{
            if(!this.scrolling){
                this.el.addClass('x-taskbuttons-scrolling');
            }
            tw -= wrap.getMargins('lr');
            wrap.setWidth(tw > 20 ? tw : 20);
            if(!this.scrolling){
                if(!this.scrollLeft){
                    this.createScrollers();
                }else{
                    this.scrollLeft.show();
                    this.scrollRight.show();
                }
            }
            this.scrolling = true;
            if(pos > (l-tw)){ // ensure it stays within bounds
                wrap.dom.scrollLeft = l-tw;
            }else{ // otherwise, make sure the active button is still visible
    this.scrollToButton(this.activeButton, true); // true to animate
            }
            this.updateScrollButtons();
        }
    },

    createScrollers : function(){
        var h = this.el.dom.offsetHeight; //var h = this.stripWrap.dom.offsetHeight;
  
        // left
        var sl = this.el.insertFirst({
            cls:'ux-taskbuttons-scroller-left'
        });
        sl.setHeight(h);
        sl.addClassOnOver('ux-taskbuttons-scroller-left-over');
        this.leftRepeater = new Ext.util.ClickRepeater(sl, {
            interval : this.scrollRepeatInterval,
            handler: this.onScrollLeft,
            scope: this
        });
        this.scrollLeft = sl;

        // right
        var sr = this.el.insertFirst({
            cls:'ux-taskbuttons-scroller-right'
        });
        sr.setHeight(h);
        sr.addClassOnOver('ux-taskbuttons-scroller-right-over');
        this.rightRepeater = new Ext.util.ClickRepeater(sr, {
            interval : this.scrollRepeatInterval,
            handler: this.onScrollRight,
            scope: this
        });
        this.scrollRight = sr;
    },
    
    getScrollWidth : function(){
        return this.edge.getOffsetsTo(this.stripWrap)[0] + this.getScrollPos();
    },

    getScrollPos : function(){
        return parseInt(this.stripWrap.dom.scrollLeft, 10) || 0;
    },

    getScrollArea : function(){
        return parseInt(this.stripWrap.dom.clientWidth, 10) || 0;
    },

    getScrollAnim : function(){
        return {
         duration: this.scrollDuration,
         callback: this.updateScrollButtons,
         scope: this
        };
    },

    getScrollIncrement : function(){
     return (this.scrollIncrement || this.lastButtonWidth+2);
    },
    
    /* getBtnEl : function(item){
        return document.getElementById(item.id);
    }, */
    
    scrollToButton : function(item, animate){
     item = item.el.dom.parentNode; // li
        if(!item){ return; }
        var el = item; //this.getBtnEl(item);
        var pos = this.getScrollPos(), area = this.getScrollArea();
        var left = Ext.fly(el).getOffsetsTo(this.stripWrap)[0] + pos;
        var right = left + el.offsetWidth;
        if(left < pos){
            this.scrollTo(left, animate);
        }else if(right > (pos + area)){
            this.scrollTo(right - area, animate);
        }
    },
    
    scrollTo : function(pos, animate){
        this.stripWrap.scrollTo('left', pos, animate ? this.getScrollAnim() : false);
        if(!animate){
            this.updateScrollButtons();
        }
    },
    
    onScrollRight : function(){
        var sw = this.getScrollWidth()-this.getScrollArea();
        var pos = this.getScrollPos();
        var s = Math.min(sw, pos + this.getScrollIncrement());
        if(s != pos){
         this.scrollTo(s, this.animScroll);
        }        
    },

    onScrollLeft : function(){
        var pos = this.getScrollPos();
        var s = Math.max(0, pos - this.getScrollIncrement());
        if(s != pos){
            this.scrollTo(s, this.animScroll);
        }
    },
    
    updateScrollButtons : function(){
        var pos = this.getScrollPos();
        this.scrollLeft[pos == 0 ? 'addClass' : 'removeClass']('ux-taskbuttons-scroller-left-disabled');
        this.scrollRight[pos >= (this.getScrollWidth()-this.getScrollArea()) ? 'addClass' : 'removeClass']('ux-taskbuttons-scroller-right-disabled');
    }
});


/*--------------------------------------------------*/
/**
 * @class Ext.ux.TaskBar.TaskButton
 * @extends Ext.Button
 */
Ext.ux.TaskBar.TaskButton = function(win, el){
 this.win = win;
    Ext.ux.TaskBar.TaskButton.superclass.constructor.call(this, {
        iconCls: win.iconCls,
        text: Ext.util.Format.ellipsis(win.title, 12),
        renderTo: el,
        handler : function(){
            if(win.minimized || win.hidden){
                win.show();
            }else if(win == win.manager.getActive()){
                win.minimize();
            }else{
                win.toFront();
            }
        },
        clickEvent:'mousedown',
        template: new Ext.Template(
   '<table cellspacing="0" class="x-btn {3}"><tbody><tr>',
   '<td class="ux-taskbutton-left"><i>&#160;</i></td>',
            '<td class="ux-taskbutton-center"><em class="{5} unselectable="on">',
                '<button class="x-btn-text {2}" type="{1}" style="height:28px;">{0}</button>',
            '</em></td>',
            '<td class="ux-taskbutton-right"><i>&#160;</i></td>',
   "</tr></tbody></table>")            
    });
};

/*--------------------------------------------------*/
//子類別Ext.ux.TaskBar.TaskButton,繼承父類別Ext.Button。(2-argument)
Ext.extend(Ext.ux.TaskBar.TaskButton, Ext.Button, {
    onRender : function(){
        Ext.ux.TaskBar.TaskButton.superclass.onRender.apply(this, arguments);

        this.cmenu = new Ext.menu.Menu({
            items: [{
                text: '還原',
                handler: function(){
                    if(!this.win.isVisible()){
                        this.win.show();
                    }else{
                        this.win.restore();
                    }
                },
                scope: this
            },{
                text: '最小化',
                handler: this.win.minimize,
                scope: this.win
            },{
                text: '最大化',
                handler: this.win.maximize,
                scope: this.win
            }, '-', {
                text: '關閉',
                handler: this.closeWin.createDelegate(this, this.win, true),
                scope: this.win
            }]
        });

        this.cmenu.on('beforeshow', function(){
            var items = this.cmenu.items.items;
            var w = this.win;
            items[0].setDisabled(w.maximized !== true && w.hidden !== true);
            items[1].setDisabled(w.minimized === true);
            items[2].setDisabled(w.maximized === true || w.hidden === true);
        }, this);

        this.el.on('contextmenu', function(e){
            e.stopEvent();
            if(!this.cmenu.el){
                this.cmenu.render();
            }
            var xy = e.getXY();
            xy[1] -= this.cmenu.el.getHeight();
            this.cmenu.showAt(xy);
        }, this);
    },
    
    closeWin : function(cMenu, e, win){
  if(!win.isVisible()){
   win.show();
  }else{
   win.restore();
  }
  win.close();
 }
});

1 則留言:

  1. 您好,我最近在研究ExtJS,想請教您,若要將這五個JS引入Html的話,那html的語法該怎麼寫,可否麻煩您提供小弟原始碼呢,打擾您實在非常抱歉,感謝您的回覆

    回覆刪除

熱門文章