| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 | <!DOCTYPE html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>The source code</title>  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>  <style type="text/css">    .highlight { display: block; background-color: #ddd; }  </style>  <script type="text/javascript">    function highlight() {      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";    }  </script></head><body onload="prettyPrint(); highlight();">  <pre class="prettyprint lang-js"><span id='Ext-layout-container-boxOverflow-Menu'>/**</span> * @private */Ext.define('Ext.layout.container.boxOverflow.Menu', {    /* Begin Definitions */    extend: 'Ext.layout.container.boxOverflow.None',    requires: ['Ext.toolbar.Separator', 'Ext.button.Button'],    alternateClassName: 'Ext.layout.boxOverflow.Menu',        /* End Definitions */<span id='Ext-layout-container-boxOverflow-Menu-cfg-triggerButtonCls'>    /**</span>     * @cfg {String} triggerButtonCls     * CSS class added to the Button which shows the overflow menu.     */<span id='Ext-layout-container-boxOverflow-Menu-property-noItemsMenuText'>    /**</span>     * @property {String} noItemsMenuText     * HTML fragment to render into the toolbar overflow menu if there are no items to display     */    noItemsMenuText : '<div class="' + Ext.baseCSSPrefix + 'toolbar-no-items">(None)</div>',    constructor: function(layout) {        var me = this;        me.callParent(arguments);        me.triggerButtonCls = me.triggerButtonCls || Ext.baseCSSPrefix + 'box-menu-' + layout.getNames().right;<span id='Ext-layout-container-boxOverflow-Menu-property-menuItems'>        /**</span>         * @property {Array} menuItems         * Array of all items that are currently hidden and should go into the dropdown menu         */        me.menuItems = [];    },    beginLayout: function (ownerContext) {        this.callParent(arguments);        // Before layout, we need to re-show all items which we may have hidden due to a        // previous overflow...        this.clearOverflow(ownerContext);    },    beginLayoutCycle: function (ownerContext, firstCycle) {        this.callParent(arguments);        if (!firstCycle) {            // if we are being re-run, we need to clear any overflow from the last run and            // recache the childItems collection            this.clearOverflow(ownerContext);            this.layout.cacheChildItems(ownerContext);        }    },    onRemove: function(comp){        Ext.Array.remove(this.menuItems, comp);    },    // We don't define a prefix in menu overflow.    getSuffixConfig: function() {        var me = this,            layout = me.layout,            oid = layout.owner.id;<span id='Ext-layout-container-boxOverflow-Menu-property-menu'>        /**</span>         * @private         * @property {Ext.menu.Menu} menu         * The expand menu - holds items for every item that cannot be shown         * because the container is currently not large enough.         */        me.menu = new Ext.menu.Menu({            listeners: {                scope: me,                beforeshow: me.beforeMenuShow            }        });<span id='Ext-layout-container-boxOverflow-Menu-property-menuTrigger'>        /**</span>         * @private         * @property {Ext.button.Button} menuTrigger         * The expand button which triggers the overflow menu to be shown         */        me.menuTrigger = new Ext.button.Button({            id      : oid + '-menu-trigger',            cls     : Ext.layout.container.Box.prototype.innerCls + ' ' + me.triggerButtonCls,            hidden  : true,            ownerCt : layout.owner, // To enable the Menu to ascertain a valid zIndexManager owner in the same tree            ownerLayout: layout,            iconCls : Ext.baseCSSPrefix + me.getOwnerType(layout.owner) + '-more-icon',            ui      : layout.owner instanceof Ext.toolbar.Toolbar ? 'default-toolbar' : 'default',            menu    : me.menu,            getSplitCls: function() { return '';}        });        return me.menuTrigger.getRenderTree();    },        getOverflowCls: function() {        return Ext.baseCSSPrefix + this.layout.direction + '-box-overflow-body';    },    handleOverflow: function(ownerContext) {        var me = this,            layout = me.layout,            names = layout.getNames(),            plan = ownerContext.state.boxPlan,            posArgs = [null, null];        me.showTrigger(ownerContext);        // Center the menuTrigger button.        // TODO: Should we emulate align: 'middle' like this, or should we 'stretchmax' the menuTrigger?        posArgs[names.heightIndex] = (plan.maxSize - me.menuTrigger[names.getHeight]()) / 2;        me.menuTrigger.setPosition.apply(me.menuTrigger, posArgs);        return {            reservedSpace: me.menuTrigger[names.getWidth]()        };    },<span id='Ext-layout-container-boxOverflow-Menu-method-captureChildElements'>    /**</span>     * Finishes the render operation of the trigger Button.     * @private     */    captureChildElements: function() {        var menuTrigger = this.menuTrigger;        if (menuTrigger.rendering) {            menuTrigger.finishRender();        }    },    _asLayoutRoot: { isRoot: true },<span id='Ext-layout-container-boxOverflow-Menu-method-clearOverflow'>    /**</span>     * @private     * Called by the layout, when it determines that there is no overflow.     * Also called as an interceptor to the layout's onLayout method to reshow     * previously hidden overflowing items.     */    clearOverflow: function(ownerContext) {        var me = this,            items = me.menuItems,            item,            i = 0,            length = items.length,            owner = me.layout.owner,            asLayoutRoot = me._asLayoutRoot;        owner.suspendLayouts();        me.captureChildElements();        me.hideTrigger();        owner.resumeLayouts();        for (; i < length; i++) {            item = items[i];            // What we are doing here is preventing the layout bubble from invalidating our            // owner component. We need just the button to be added to the layout run.            item.suspendLayouts();            item.show();            item.resumeLayouts(asLayoutRoot);        }        items.length = 0;    },<span id='Ext-layout-container-boxOverflow-Menu-method-showTrigger'>    /**</span>     * @private     * Shows the overflow trigger when enableOverflow is set to true and the items     * in the layout are too wide to fit in the space available     */    showTrigger: function(ownerContext) {        var me = this,            layout = me.layout,            owner = layout.owner,            names = layout.getNames(),            startProp = names.x,            sizeProp = names.width,            plan = ownerContext.state.boxPlan,            available = plan.targetSize[sizeProp],            childItems = ownerContext.childItems,            len = childItems.length,            menuTrigger = me.menuTrigger,            childContext,            comp, i, props;        // We don't want the menuTrigger.show to cause owner's layout to be invalidated, so        // we force just the button to be invalidated and added to the current run.        menuTrigger.suspendLayouts();        menuTrigger.show();        menuTrigger.resumeLayouts(me._asLayoutRoot);        available -= me.menuTrigger.getWidth();        owner.suspendLayouts();        // Hide all items which are off the end, and store them to allow them to be restored        // before each layout operation.        me.menuItems.length = 0;        for (i = 0; i < len; i++) {            childContext = childItems[i];            props = childContext.props;            if (props[startProp] + props[sizeProp] > available) {                comp = childContext.target;                me.menuItems.push(comp);                comp.hide();            }        }        owner.resumeLayouts();    },<span id='Ext-layout-container-boxOverflow-Menu-method-hideTrigger'>    /**</span>     * @private     */    hideTrigger: function() {        var menuTrigger = this.menuTrigger;        if (menuTrigger) {            menuTrigger.hide();        }    },<span id='Ext-layout-container-boxOverflow-Menu-method-beforeMenuShow'>    /**</span>     * @private     * Called before the overflow menu is shown. This constructs the menu's items, caching them for as long as it can.     */    beforeMenuShow: function(menu) {        var me = this,            items = me.menuItems,            i = 0,            len   = items.length,            item,            prev,            needsSep = function(group, prev){                return group.isXType('buttongroup') && !(prev instanceof Ext.toolbar.Separator);            };        menu.suspendLayouts();        me.clearMenu();        menu.removeAll();        for (; i < len; i++) {            item = items[i];            // Do not show a separator as a first item            if (!i && (item instanceof Ext.toolbar.Separator)) {                continue;            }            if (prev && (needsSep(item, prev) || needsSep(prev, item))) {                menu.add('-');            }            me.addComponentToMenu(menu, item);            prev = item;        }        // put something so the menu isn't empty if no compatible items found        if (menu.items.length < 1) {            menu.add(me.noItemsMenuText);        }        menu.resumeLayouts();    },    <span id='Ext-layout-container-boxOverflow-Menu-method-createMenuConfig'>    /**</span>     * @private     * Returns a menu config for a given component. This config is used to create a menu item     * to be added to the expander menu     * @param {Ext.Component} component The component to create the config for     * @param {Boolean} hideOnClick Passed through to the menu item     */    createMenuConfig : function(component, hideOnClick) {        var config = Ext.apply({}, component.initialConfig),            group  = component.toggleGroup;        Ext.copyTo(config, component, [            'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'        ]);        Ext.apply(config, {            text       : component.overflowText || component.text,            hideOnClick: hideOnClick,            destroyMenu: false        });        // Clone must have same value, and must sync original's value on change        if (component.isFormField) {            config.value = component.getValue();            // We're going to add a listener            if (!config.listeners) {                config.listeners = {};            }            // Sync the original component's value when the clone changes value.            // This intentionally overwrites any developer-configured change listener on the clone.            // That's because we monitor the clone's change event, and sync the            // original field by calling setValue, so the original field's change            // event will still fire.            config.listeners.change = function(c, newVal, oldVal) {                                            component.setValue(newVal);            }        }        // ToggleButtons become CheckItems        else if (group || component.enableToggle) {            Ext.apply(config, {                iconAlign: 'right',                hideOnClick: false,                group  : group,                checked: component.pressed,                listeners: {                    checkchange: function(item, checked) {                        component.toggle(checked);                    }                }            });        }        delete config.ownerCt;        delete config.xtype;        delete config.id;        return config;    },<span id='Ext-layout-container-boxOverflow-Menu-method-addComponentToMenu'>    /**</span>     * @private     * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.     * @param {Ext.menu.Menu} menu The menu to add to     * @param {Ext.Component} component The component to add     * TODO: Implement overrides in Ext.layout.container.boxOverflow which create overrides     * for SplitButton, Button, ButtonGroup, and TextField. And a generic one for Component     * which create clones suitable for use in an overflow menu.     */    addComponentToMenu : function(menu, component) {        var me = this,        i, items, iLen;        if (component instanceof Ext.toolbar.Separator) {            menu.add('-');        } else if (component.isComponent) {            if (component.isXType('splitbutton')) {                menu.add(me.createMenuConfig(component, true));            } else if (component.isXType('button')) {                menu.add(me.createMenuConfig(component, !component.menu));            } else if (component.isXType('buttongroup')) {                items = component.items.items;                iLen  = items.length;                for (i = 0; i < iLen; i++) {                    me.addComponentToMenu(menu, items[i]);                }            } else {                menu.add(Ext.create(Ext.getClassName(component), me.createMenuConfig(component)));            }        }    },<span id='Ext-layout-container-boxOverflow-Menu-method-clearMenu'>    /**</span>     * @private     * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as     * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item     */    clearMenu : function() {        var menu = this.menu,            items, i, iLen, item;                if (menu && menu.items) {            items = menu.items.items;            iLen  = items.length;                        for (i = 0; i < iLen; i++) {                item = items[i];                if (item.setMenu) {                    item.setMenu(null);                }            }        }    },<span id='Ext-layout-container-boxOverflow-Menu-method-destroy'>    /**</span>     * @private     */    destroy: function() {        var trigger = this.menuTrigger;                    if (trigger && !this.layout.owner.items.contains(trigger)) {            // Ensure we delete the ownerCt if it's not in the items            // so we don't get spurious container remove warnings.            delete trigger.ownerCt;        }        Ext.destroy(this.menu, trigger);    }});</pre></body></html>
 |