| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 | <!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-Anchor'>/**</span> * This is a layout that enables anchoring of contained elements relative to the container's dimensions. * If the container is resized, all anchored items are automatically rerendered according to their * `{@link #anchor}` rules. * * This class is intended to be extended or created via the {@link Ext.container.AbstractContainer#layout layout}: 'anchor'  * config, and should generally not need to be created directly via the new keyword. *  * AnchorLayout does not have any direct config options (other than inherited ones). By default, * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the * container using the AnchorLayout can supply an anchoring-specific config property of `anchorSize`. * * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring * logic if necessary. * *     @example *     Ext.create('Ext.Panel', { *         width: 500, *         height: 400, *         title: "AnchorLayout Panel", *         layout: 'anchor', *         renderTo: Ext.getBody(), *         items: [ *             { *                 xtype: 'panel', *                 title: '75% Width and 20% Height', *                 anchor: '75% 20%' *             }, *             { *                 xtype: 'panel', *                 title: 'Offset -300 Width & -200 Height', *                 anchor: '-300 -200'		 *             }, *             { *                 xtype: 'panel', *                 title: 'Mixed Offset and Percent', *                 anchor: '-250 20%' *             } *         ] *     }); */Ext.define('Ext.layout.container.Anchor', {    /* Begin Definitions */    alias: 'layout.anchor',    extend: 'Ext.layout.container.Container',    alternateClassName: 'Ext.layout.AnchorLayout',    /* End Definitions */    type: 'anchor',    manageOverflow: 2,    renderTpl: [        '{%this.renderBody(out,values);this.renderPadder(out,values)%}'    ],<span id='Ext-layout-container-Anchor-cfg-anchor'>    /**</span>     * @cfg {String} anchor     *     * This configuation option is to be applied to **child `items`** of a container managed by     * this layout (ie. configured with `layout:'anchor'`).     *     * This value is what tells the layout how an item should be anchored to the container. `items`     * added to an AnchorLayout accept an anchoring-specific config property of **anchor** which is a string     * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').     * The following types of anchor values are supported:     *     * - **Percentage** : Any value between 1 and 100, expressed as a percentage.     *     *   The first anchor is the percentage width that the item should take up within the container, and the     *   second is the percentage height.  For example:     *     *       // two values specified     *       anchor: '100% 50%' // render item complete width of the container and     *                          // 1/2 height of the container     *       // one value specified     *       anchor: '100%'     // the width value; the height will default to auto     *     * - **Offsets** : Any positive or negative integer value.     *     *   This is a raw adjustment where the first anchor is the offset from the right edge of the container,     *   and the second is the offset from the bottom edge. For example:     *     *       // two values specified     *       anchor: '-50 -100' // render item the complete width of the container     *                          // minus 50 pixels and     *                          // the complete height minus 100 pixels.     *       // one value specified     *       anchor: '-50'      // anchor value is assumed to be the right offset value     *                          // bottom offset will default to 0     *     * - **Sides** : Valid values are `right` (or `r`) and `bottom` (or `b`).     *     *   Either the container must have a fixed size or an anchorSize config value defined at render time in     *   order for these to have any effect.     *        * - **Mixed** :     *     *   Anchor values can also be mixed as needed.  For example, to render the width offset from the container     *   right edge by 50 pixels and 75% of the container's height use:     *        *       anchor:   '-50 75%'     */<span id='Ext-layout-container-Anchor-cfg-defaultAnchor'>    /**</span>     * @cfg {String} defaultAnchor     * Default anchor for all child **container** items applied if no anchor or specific width is set on the child item.     */    defaultAnchor: '100%',    parseAnchorRE: /^(r|right|b|bottom)$/i,    beginLayout: function (ownerContext) {        var me = this,            dimensions = 0,            anchorSpec, childContext, childItems, i, length, target;        me.callParent(arguments);        childItems = ownerContext.childItems; // populated by callParent        length = childItems.length;        for (i = 0; i < length; ++i) {            childContext = childItems[i];            anchorSpec = childContext.target.anchorSpec;            if (anchorSpec) {                if (childContext.widthModel.calculated && anchorSpec.right) {                    dimensions |= 1;                }                if (childContext.heightModel.calculated && anchorSpec.bottom) {                    dimensions |= 2;                }                if (dimensions == 3) { // if (both dimensions in play)                    break;                }            }        }        ownerContext.anchorDimensions = dimensions;        // Work around WebKit RightMargin bug. We're going to inline-block all the children        // only ONCE and remove it when we're done        if (!Ext.supports.RightMargin && !me.rightMarginCleanerFn) {            target = ownerContext.targetContext.el; // targetContext is added by superclass            me.rightMarginCleanerFn = Ext.Element.getRightMarginFixCleaner(target);            target.addCls(Ext.baseCSSPrefix + 'inline-children');        }        //<debug>        me.sanityCheck(ownerContext);        //</debug>    },    calculate: function (ownerContext) {        var me = this,            containerSize = me.getContainerSize(ownerContext);        if (ownerContext.anchorDimensions !== ownerContext.state.calculatedAnchors) {            me.calculateAnchors(ownerContext, containerSize);        }        if (ownerContext.hasDomProp('containerChildrenDone')) {            // Once the child layouts are done we can determine the content sizes...            if (!containerSize.gotAll) {                me.done = false;            }            me.calculateContentSize(ownerContext, ownerContext.anchorDimensions);            if (me.done) {                me.calculateOverflow(ownerContext, containerSize, ownerContext.anchorDimensions);                return;            }        }        me.done = false;    },    calculateAnchors: function (ownerContext, containerSize) {        var me = this,            childItems = ownerContext.childItems,            length = childItems.length,            gotHeight = containerSize.gotHeight,            gotWidth = containerSize.gotWidth,            ownerHeight = containerSize.height,            ownerWidth = containerSize.width,            state = ownerContext.state,            calculatedAnchors = (gotWidth ? 1 : 0) | (gotHeight ? 2 : 0),            anchorSpec, childContext, childMargins, height, i, width;        state.calculatedAnchors = (state.calculatedAnchors || 0) | calculatedAnchors;        for (i = 0; i < length; i++) {            childContext = childItems[i];            childMargins = childContext.getMarginInfo();            anchorSpec = childContext.target.anchorSpec;            // Check widthModel in case "defaults" has applied an anchor to a component            // that also has width (which must win). If we did not make this check in this            // way, we would attempt to calculate a width where it had been configured.            //            if (gotWidth && childContext.widthModel.calculated) {                width = anchorSpec.right(ownerWidth) - childMargins.width;                width = me.adjustWidthAnchor(width, childContext);                childContext.setWidth(width);            }            // Repeat for height            if (gotHeight && childContext.heightModel.calculated) {                height = anchorSpec.bottom(ownerHeight) - childMargins.height;                height = me.adjustHeightAnchor(height, childContext);                childContext.setHeight(height);            }        }    },    finishedLayout: function (ownerContext) {        var cleanerFn = this.rightMarginCleanerFn;        if (cleanerFn) {            delete this.rightMarginCleanerFn;            ownerContext.targetContext.el.removeCls(Ext.baseCSSPrefix + 'inline-children');            cleanerFn();        }    },    //<debug>    sanityCheck: function (ownerContext) {        var shrinkWrapWidth = ownerContext.widthModel.shrinkWrap,            shrinkWrapHeight = ownerContext.heightModel.shrinkWrap,            children = ownerContext.childItems,            anchorSpec, comp, childContext,            i, length;        for (i = 0, length = children.length; i < length; ++i) {            childContext = children[i];            comp = childContext.target;            anchorSpec = comp.anchorSpec;            if (anchorSpec) {                if (childContext.widthModel.calculated && anchorSpec.right) {                    if (shrinkWrapWidth) {                        Ext.log({                            level: 'warn',                            msg: 'Right anchor on '+comp.id+' in shrinkWrap width container'                        });                    }                }                if (childContext.heightModel.calculated && anchorSpec.bottom) {                    if (shrinkWrapHeight) {                        Ext.log({                            level: 'warn',                            msg: 'Bottom anchor on '+comp.id+' in shrinkWrap height container'                        });                    }                }            }        }    },    //</debug>    // private    anchorFactory: {        offset: function (delta) {            return function(v) {                return v + delta;            };        },        ratio: function (ratio) {            return function(v) {                return Math.floor(v * ratio);            };        },        standard: function (diff) {            return function(v) {                return v - diff;            };        }    },    parseAnchor: function(a, start, cstart) {        if (a && a != 'none') {            var factory = this.anchorFactory,                delta;            if (this.parseAnchorRE.test(a)) {                return factory.standard(cstart - start);            }                if (a.indexOf('%') != -1) {                return factory.ratio(parseFloat(a.replace('%', '')) * 0.01);            }                delta = parseInt(a, 10);            if (!isNaN(delta)) {                return factory.offset(delta);            }        }        return null;    },    // private    adjustWidthAnchor: function(value, childContext) {        return value;    },    // private    adjustHeightAnchor: function(value, childContext) {        return value;    },    configureItem: function(item) {        var me = this,            owner = me.owner,            anchor= item.anchor,            anchorsArray,            anchorWidth,            anchorHeight;        me.callParent(arguments);        if (!item.anchor && item.items && !Ext.isNumber(item.width) && !(Ext.isIE6 && Ext.isStrict)) {            item.anchor = anchor = me.defaultAnchor;        }<span id='Ext-container-Container-cfg-anchorSize'>        /**</span>         * @cfg {Number/Object} anchorSize         * Defines the anchoring size of container.         * Either a number to define the width of the container or an object with `width` and `height` fields.         * @member Ext.container.Container         */         if (owner.anchorSize) {            if (typeof owner.anchorSize == 'number') {                anchorWidth = owner.anchorSize;            } else {                anchorWidth = owner.anchorSize.width;                anchorHeight = owner.anchorSize.height;            }        } else {            anchorWidth = owner.initialConfig.width;            anchorHeight = owner.initialConfig.height;        }        if (anchor) {            // cache all anchor values            anchorsArray = anchor.split(' ');            item.anchorSpec = {                right: me.parseAnchor(anchorsArray[0], item.initialConfig.width, anchorWidth),                bottom: me.parseAnchor(anchorsArray[1], item.initialConfig.height, anchorHeight)            };        }    },    sizePolicy: {        '': {            setsWidth: 0,            setsHeight: 0        },        b: {            setsWidth: 0,            setsHeight: 1        },        r: {            '': {                setsWidth: 1,                setsHeight: 0            },            b: {                setsWidth: 1,                setsHeight: 1            }        }    },    getItemSizePolicy: function (item) {        var anchorSpec = item.anchorSpec,            key = '',            policy = this.sizePolicy,            sizeModel;        if (anchorSpec) {            sizeModel = this.owner.getSizeModel();            if (anchorSpec.right && !sizeModel.width.shrinkWrap) {                policy = policy.r;            }            if (anchorSpec.bottom && !sizeModel.height.shrinkWrap) {                key = 'b';            }        }        return policy[key];    }});</pre></body></html>
 |