| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 | <!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-Card'>/**</span> * This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be * visible at any given time.  This layout style is most commonly used for wizards, tab implementations, etc. * This class is intended to be extended or created via the layout:'card' {@link Ext.container.Container#layout} config, * and should generally not need to be created directly via the new keyword. * * The CardLayout's focal method is {@link #setActiveItem}.  Since only one panel is displayed at a time, * the only way to move from one Component to the next is by calling setActiveItem, passing the next panel to display * (or its id or index).  The layout itself does not provide a user interface for handling this navigation, * so that functionality must be provided by the developer. * * To change the active card of a container, call the setActiveItem method of its layout: * *     @example *     var p = Ext.create('Ext.panel.Panel', { *         layout: 'card', *         items: [ *             { html: 'Card 1' }, *             { html: 'Card 2' } *         ], *         renderTo: Ext.getBody() *     }); * *     p.getLayout().setActiveItem(1); * * In the following example, a simplistic wizard setup is demonstrated.  A button bar is added * to the footer of the containing panel to provide navigation buttons.  The buttons will be handled by a * common navigation routine.  Note that other uses of a CardLayout (like a tab control) would require a * completely different implementation.  For serious implementations, a better approach would be to extend * CardLayout to provide the custom functionality needed. * *     @example *     var navigate = function(panel, direction){ *         // This routine could contain business logic required to manage the navigation steps. *         // It would call setActiveItem as needed, manage navigation button state, handle any *         // branching logic that might be required, handle alternate actions like cancellation *         // or finalization, etc.  A complete wizard implementation could get pretty *         // sophisticated depending on the complexity required, and should probably be *         // done as a subclass of CardLayout in a real-world implementation. *         var layout = panel.getLayout(); *         layout[direction](); *         Ext.getCmp('move-prev').setDisabled(!layout.getPrev()); *         Ext.getCmp('move-next').setDisabled(!layout.getNext()); *     }; * *     Ext.create('Ext.panel.Panel', { *         title: 'Example Wizard', *         width: 300, *         height: 200, *         layout: 'card', *         bodyStyle: 'padding:15px', *         defaults: { *             // applied to each contained panel *             border: false *         }, *         // just an example of one possible navigation scheme, using buttons *         bbar: [ *             { *                 id: 'move-prev', *                 text: 'Back', *                 handler: function(btn) { *                     navigate(btn.up("panel"), "prev"); *                 }, *                 disabled: true *             }, *             '->', // greedy spacer so that the buttons are aligned to each side *             { *                 id: 'move-next', *                 text: 'Next', *                 handler: function(btn) { *                     navigate(btn.up("panel"), "next"); *                 } *             } *         ], *         // the panels (or "cards") within the layout *         items: [{ *             id: 'card-0', *             html: '<h1>Welcome to the Wizard!</h1><p>Step 1 of 3</p>' *         },{ *             id: 'card-1', *             html: '<p>Step 2 of 3</p>' *         },{ *             id: 'card-2', *             html: '<h1>Congratulations!</h1><p>Step 3 of 3 - Complete</p>' *         }], *         renderTo: Ext.getBody() *     }); */Ext.define('Ext.layout.container.Card', {    /* Begin Definitions */    extend: 'Ext.layout.container.Fit',    alternateClassName: 'Ext.layout.CardLayout',    alias: 'layout.card',    /* End Definitions */    type: 'card',    hideInactive: true,<span id='Ext-layout-container-Card-cfg-deferredRender'>    /**</span>     * @cfg {Boolean} deferredRender     * True to render each contained item at the time it becomes active, false to render all contained items     * as soon as the layout is rendered (defaults to false).  If there is a significant amount of content or     * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to     * true might improve performance.     */    deferredRender : false,        getRenderTree: function () {        var me = this,            activeItem = me.getActiveItem();        if (activeItem) {            // If they veto the activate, we have no active item            if (activeItem.hasListeners.beforeactivate && activeItem.fireEvent('beforeactivate', activeItem) === false) {                 // We must null our activeItem reference, AND the one in our owning Container.                // Because upon layout invalidation, renderChildren will use this.getActiveItem which                // uses this.activeItem || this.owner.activeItem                activeItem = me.activeItem = me.owner.activeItem = null;            }                        // Item is to be the active one. Fire event after it is first layed out            else if (activeItem.hasListeners.activate) {                activeItem.on({                    boxready: function() {                        activeItem.fireEvent('activate', activeItem);                    },                    single: true                });            }            if (me.deferredRender) {                if (activeItem) {                    return me.getItemsRenderTree([activeItem]);                }            } else {                return me.callParent(arguments);            }        }    },    renderChildren: function () {        var me = this,            active = me.getActiveItem();                    if (!me.deferredRender) {            me.callParent();        } else if (active) {            // ensure the active item is configured for the layout            me.renderItems([active], me.getRenderTarget());        }    },    isValidParent : function(item, target, position) {        // Note: Card layout does not care about order within the target because only one is ever visible.        // We only care whether the item is a direct child of the target.        var itemEl = item.el ? item.el.dom : Ext.getDom(item);        return (itemEl && itemEl.parentNode === (target.dom || target)) || false;    },<span id='Ext-layout-container-Card-method-getActiveItem'>    /**</span>     * Return the active (visible) component in the layout.     * @returns {Ext.Component}     */    getActiveItem: function() {        var me = this,            // Ensure the calculated result references a Component            result = me.parseActiveItem(me.activeItem || (me.owner && me.owner.activeItem));        // Sanitize the result in case the active item is no longer there.        if (result && me.owner.items.indexOf(result) != -1) {            me.activeItem = result;        } else {            me.activeItem = null;        }        return me.activeItem;    },    // @private    parseActiveItem: function(item) {        if (item && item.isComponent) {            return item;        } else if (typeof item == 'number' || item === undefined) {            return this.getLayoutItems()[item || 0];        } else {            return this.owner.getComponent(item);        }    },    // @private. Called before both dynamic render, and bulk render.    // Ensure that the active item starts visible, and inactive ones start invisible    configureItem: function(item) {        if (item === this.getActiveItem()) {            item.hidden = false;        } else {            item.hidden = true;        }        this.callParent(arguments);    },    onRemove: function(component) {        var me = this;                if (component === me.activeItem) {            me.activeItem = null;        }    },    // @private    getAnimation: function(newCard, owner) {        var newAnim = (newCard || {}).cardSwitchAnimation;        if (newAnim === false) {            return false;        }        return newAnim || owner.cardSwitchAnimation;    },<span id='Ext-layout-container-Card-method-getNext'>    /**</span>     * Return the active (visible) component in the layout to the next card     * @returns {Ext.Component} The next component or false.     */    getNext: function() {        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This         //should come back in 4.1        var wrap = arguments[0],            items = this.getLayoutItems(),            index = Ext.Array.indexOf(items, this.activeItem);                    return items[index + 1] || (wrap ? items[0] : false);    },<span id='Ext-layout-container-Card-method-next'>    /**</span>     * Sets the active (visible) component in the layout to the next card     * @return {Ext.Component} the activated component or false when nothing activated.     */    next: function() {        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This         //should come back in 4.1        var anim = arguments[0],             wrap = arguments[1];        return this.setActiveItem(this.getNext(wrap), anim);    },<span id='Ext-layout-container-Card-method-getPrev'>    /**</span>     * Return the active (visible) component in the layout to the previous card     * @returns {Ext.Component} The previous component or false.     */    getPrev: function() {        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This         //should come back in 4.1        var wrap = arguments[0],            items = this.getLayoutItems(),            index = Ext.Array.indexOf(items, this.activeItem);                    return items[index - 1] || (wrap ? items[items.length - 1] : false);    },<span id='Ext-layout-container-Card-method-prev'>    /**</span>     * Sets the active (visible) component in the layout to the previous card     * @return {Ext.Component} the activated component or false when nothing activated.     */    prev: function() {        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This         //should come back in 4.1        var anim = arguments[0],             wrap = arguments[1];        return this.setActiveItem(this.getPrev(wrap), anim);    },<span id='Ext-layout-container-Card-method-setActiveItem'>    /**</span>     * Makes the given card active.     *     *     var card1 = Ext.create('Ext.panel.Panel', {itemId: 'card-1'});     *     var card2 = Ext.create('Ext.panel.Panel', {itemId: 'card-2'});     *     var panel = Ext.create('Ext.panel.Panel', {     *         layout: 'card',     *         activeItem: 0,     *         items: [card1, card2]     *     });     *     // These are all equivalent     *     panel.getLayout().setActiveItem(card2);     *     panel.getLayout().setActiveItem('card-2');     *     panel.getLayout().setActiveItem(1);     *     * @param {Ext.Component/Number/String} newCard  The component, component {@link Ext.Component#id id},     * {@link Ext.Component#itemId itemId}, or index of component.     * @return {Ext.Component} the activated component or false when nothing activated.     * False is returned also when trying to activate an already active card.     */    setActiveItem: function(newCard) {        var me = this,            owner = me.owner,            oldCard = me.activeItem,            rendered = owner.rendered,            newIndex;        newCard = me.parseActiveItem(newCard);        newIndex = owner.items.indexOf(newCard);        // If the card is not a child of the owner, then add it.        // Without doing a layout!        if (newIndex == -1) {            newIndex = owner.items.items.length;            Ext.suspendLayouts();            newCard = owner.add(newCard);            Ext.resumeLayouts();        }        // Is this a valid, different card?        if (newCard && oldCard != newCard) {            // Fire the beforeactivate and beforedeactivate events on the cards            if (newCard.fireEvent('beforeactivate', newCard, oldCard) === false) {                return false;            }            if (oldCard && oldCard.fireEvent('beforedeactivate', oldCard, newCard) === false) {                return false;            }            if (rendered) {                Ext.suspendLayouts();                // If the card has not been rendered yet, now is the time to do so.                if (!newCard.rendered) {                    me.renderItem(newCard, me.getRenderTarget(), owner.items.length);                }                if (oldCard) {                    if (me.hideInactive) {                        oldCard.hide();                        oldCard.hiddenByLayout = true;                    }                    oldCard.fireEvent('deactivate', oldCard, newCard);                }                // Make sure the new card is shown                if (newCard.hidden) {                    newCard.show();                }                // Layout needs activeItem to be correct, so set it if the show has not been vetoed                if (!newCard.hidden) {                    me.activeItem = newCard;                }                Ext.resumeLayouts(true);            } else {                me.activeItem = newCard;            }            newCard.fireEvent('activate', newCard, oldCard);            return me.activeItem;        }        return false;    }});</pre></body></html>
 |