Subversion Repositories eFlore/Applications.cel

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

/*
 * Ext JS Library 0.20
 * Copyright(c) 2006-2008, Ext JS, LLC.
 * licensing@extjs.com
 * 
 * http://extjs.com/license
 */

// custom menu item to contain Ext trees
Ext.menu.TreeItem = Ext.extend(Ext.menu.Adapter, {
        constructor : function(config){
        Ext.menu.TreeItem.superclass.constructor.call(this, config.tree, config);
        this.tree = this.component;
        this.addEvents('selectionchange');

        this.tree.on("render", function(tree){
            tree.body.swallowEvent(['click','keydown', 'keypress', 'keyup']);
        });

        this.tree.getSelectionModel().on("selectionchange", this.onSelect, this);
    },

    onSelect : function(tree, sel){
        this.fireEvent("select", this, sel, tree);
    }
});


// custom menu containing a single tree
Ext.menu.TreeMenu = Ext.extend(Ext.menu.Menu, {
    cls:'x-tree-menu',
        keyNav: true,
        hideOnClick:false,
    plain: true,

    constructor : function(config){
        Ext.menu.TreeMenu.superclass.constructor.call(this, config);
        this.treeItem = new Ext.menu.TreeItem(config);
        this.add(this.treeItem);

        this.tree = this.treeItem.tree;
        this.tree.on('click', this.onNodeClick, this);
        this.relayEvents(this.treeItem, ["selectionchange"]);
    },

    // private
    beforeDestroy : function() {
        this.tree.destroy();
    },
        
        onNodeClick : function(node, e){
                if(!node.attributes.isFolder){
                        this.treeItem.handleClick(e);
                }
        }
});


// custom form field for displaying a tree, similar to select or combo
Ext.ux.TreeSelector = Ext.extend(Ext.form.TriggerField, {
        initComponent : function(){
                Ext.ux.TreeSelector.superclass.initComponent.call(this);
                this.addEvents('selectionchange');

                this.tree.getSelectionModel().on('selectionchange', this.onSelection, this);
                this.tree.on({
                        'expandnode': this.sync,
                        'collapsenode' : this.sync,
                        'append' : this.sync,
                        'remove' : this.sync,
                        'insert' : this.sync,
                        scope: this
                });
                this.on('focus', this.onTriggerClick, this);
    },

        sync : function(){
                if(this.menu && this.menu.isVisible()){
                        if(this.tree.body.getHeight() > this.maxHeight){
                                this.tree.body.setHeight(this.maxHeight);
                                this.restricted = true;
                        }else if(this.restricted && this.tree.body.dom.firstChild.offsetHeight < this.maxHeight){
                                this.tree.body.setHeight('');
                                this.restricted = false;
                        }
                        this.menu.el.sync();
                }
        },

        onSelection : function(tree, node){
                if(!node){
                        this.setRawValue('');
                }else{
                        this.setRawValue(node.text);
                }
        },

        initEvents : function(){
                Ext.ux.TreeSelector.superclass.initEvents.call(this);
                this.el.on('mousedown', this.onTriggerClick, this);
                this.el.on("keydown", this.onKeyDown,  this);
        },

        onKeyDown : function(e){
                if(e.getKey() == e.DOWN){
                        this.onTriggerClick();
                }
        },

    validateBlur : function(){
        return !this.menu || !this.menu.isVisible();
    },

    getValue : function(){
                var sm = this.tree.getSelectionModel();
                var s = sm.getSelectedNode();
        return s ? s.id : '';
    },

    setValue : function(id){
                var n = this.tree.getNodeById(id);
                if(n){
                        n.select();
                }else{
                        this.tree.getSelectionModel().clearSelections();
                }
    },

    // private
    onDestroy : function(){
        if(this.menu) {
            this.menu.destroy();
        }
        if(this.wrap){
            this.wrap.remove();
        }
        Ext.ux.TreeSelector.superclass.onDestroy.call(this);
    },

        // private
    menuListeners : {
        show : function(){ // retain focus styling
            this.onFocus();
        },
        hide : function(){
            this.focus.defer(10, this);
            var ml = this.menuListeners;
            this.menu.un("show", ml.show,  this);
            this.menu.un("hide", ml.hide,  this);
        }
    },

    onTriggerClick : function(){
                if(this.disabled){
            return;
        }
        this.menu.on(Ext.apply({}, this.menuListeners, {
            scope:this
        }));

        this.menu.show(this.el, "tl-bl?");
                this.sync();
                var sm = this.tree.getSelectionModel();
                var selected = sm.getSelectedNode();
                if(selected){
                        selected.ensureVisible();
                        sm.activate.defer(250, sm, [selected]);
                }
    },

    beforeBlur : function(){
        //
    },

        onRender : function(){
                Ext.ux.TreeSelector.superclass.onRender.apply(this, arguments);
                this.menu = new Ext.menu.TreeMenu(Ext.apply(this.menuConfig || {}, {tree: this.tree}));
                this.menu.render();

                this.tree.body.addClass('x-tree-selector');
        },

        readOnly: true
});

/*
 * Custom tree keyboard navigation that supports node navigation without selection
 */
Ext.tree.ActivationModel = Ext.extend(Ext.tree.DefaultSelectionModel, {
        select : function(node){
        return this.activate(Ext.tree.ActivationModel.superclass.select.call(this, node));
    },
    
    activate : function(node){
                if(!node){
                        return;
                }
                if(this.activated != node) {
                        if(this.activated){
                                this.activated.ui.removeClass('x-tree-activated');
                        }
                        this.activated = node;
                        node.ui.addClass('x-tree-activated');
                }
                node.ui.focus();
                return node;    
        },
        
        activatePrevious : function(){
        var s = this.activated;
        if(!s){
            return null;
        }
        var ps = s.previousSibling;
        if(ps){
            if(!ps.isExpanded() || ps.childNodes.length < 1){
                return this.activate(ps);
            } else{
                var lc = ps.lastChild;
                while(lc && lc.isExpanded() && lc.childNodes.length > 0){
                    lc = lc.lastChild;
                }
                return this.activate(lc);
            }
        } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
            return this.activate(s.parentNode);
        }
        return null;
    },

    activateNext : function(){
        var s = this.activated;
        if(!s){
            return null;
        }
        if(s.firstChild && s.isExpanded()){
             return this.activate(s.firstChild);
         }else if(s.nextSibling){
             return this.activate(s.nextSibling);
         }else if(s.parentNode){
            var newS = null;
            s.parentNode.bubble(function(){
                if(this.nextSibling){
                    newS = this.getOwnerTree().selModel.activate(this.nextSibling);
                    return false;
                }
            });
            return newS;
         }
        return null;
    },

    onKeyDown : function(e){
        var s = this.activated;
        // undesirable, but required
        var sm = this;
        if(!s){
            return;
        }
        var k = e.getKey();
        switch(k){
             case e.DOWN:
                 e.stopEvent();
                 this.activateNext();
             break;
             case e.UP:
                 e.stopEvent();
                 this.activatePrevious();
             break;
             case e.RIGHT:
                 e.preventDefault();
                 if(s.hasChildNodes()){
                     if(!s.isExpanded()){
                         s.expand();
                     }else if(s.firstChild){
                         this.activate(s.firstChild, e);
                     }
                 }
             break;
             case e.LEFT:
                 e.preventDefault();
                 if(s.hasChildNodes() && s.isExpanded()){
                     s.collapse();
                 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
                     this.activate(s.parentNode, e);
                 }
             break;
        };
    }
});