ExtJS4 hbox布局问题

发布于 2024-11-28 16:19:36 字数 26162 浏览 1 评论 0原文

我们在应用程序中使用 ExtJS4。但是我们遇到了 hbox 布局的问题。我们需要从右侧显示项目。通常在 ExtJS4 中,hbox 布局中的项目从左侧开始并向右侧移动。但是我们需要从右侧开始向左侧移动。我认为我们需要更改 ExtJS4 库(框布局)中的顺序。

ExtJS4 框布局是:

/*

This file is part of Ext JS 4

Copyright (c) 2011 Sencha Inc

Contact:  http://www.sencha.com/contact

GNU General Public License Usage
This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.

If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.

*/

Ext.define('Ext.layout.container.Box', { 
    alias: ['layout.box'],
    extend: 'Ext.layout.container.Container',
    alternateClassName: 'Ext.layout.BoxLayout'      
    requires: [
        'Ext.layout.container.boxOverflow.None',
        'Ext.layout.container.boxOverflow.Menu',
        'Ext.layout.container.boxOverflow.Scroller',
        'Ext.util.Format',
        'Ext.dd.DragDropManager'
    ],
       defaultMargins: {
        top: 0,
        right: 0,
        bottom: 0,
        left: 0
    },  
    padding: '0', 
    type: 'box',
    scrollOffset: 0,
    itemCls: Ext.baseCSSPrefix + 'box-item',
    targetCls: Ext.baseCSSPrefix + 'box-layout-ct',
    innerCls: Ext.baseCSSPrefix + 'box-inner',   
    bindToOwnerCtContainer: true,    
    fixedLayout: false,        
     availableSpaceOffset: 0,
    reserveOffset: true,       
    clearInnerCtOnLayout: false,   
    flexSortFn: function (a, b) {
        var maxParallelPrefix = 'max' + this.parallelPrefixCap,
            infiniteValue = Infinity;
        a = a.component[maxParallelPrefix] || infiniteValue;
        b = b.component[maxParallelPrefix] || infiniteValue;
        // IE 6/7 Don't like Infinity - Infinity...
        if (!isFinite(a) && !isFinite(b)) {
            return false;
        }
        return a - b;
    },   
    // Sort into *descending* order.
    minSizeSortFn: function(a, b) {
        return b.available - a.available;
    },  
    constructor: function(config) {
        var me = this;   
        me.callParent(arguments);
        me.flexSortFn = Ext.Function.bind(me.flexSortFn, me);    
        me.initOverflowHandler();
    },    
        getChildBox: function(child) {
        child = child.el || this.owner.getComponent(child).el;
        return {
            left: child.getLeft(true),
            top: child.getTop(true),
            width: child.getWidth(),
            height: child.getHeight()
        };
    },

       calculateChildBox: function(child) {
        var me = this,
            boxes = me.calculateChildBoxes(me.getVisibleItems(), me.getLayoutTargetSize()).boxes,
            ln = boxes.length,
            i = 0;

        child = me.owner.getComponent(child);
        for (; i < ln; i++) {
            if (boxes[i].component === child) {
                return boxes[i];
            }
        }
    },

       calculateChildBoxes: function(visibleItems, targetSize) {
        var me = this,
            math = Math,
            mmax = math.max,
            infiniteValue = Infinity,
            undefinedValue,    
            parallelPrefix = me.parallelPrefix,
            parallelPrefixCap = me.parallelPrefixCap,
            perpendicularPrefix = me.perpendicularPrefix,
            perpendicularPrefixCap = me.perpendicularPrefixCap,
            parallelMinString = 'min' + parallelPrefixCap,
            perpendicularMinString = 'min' + perpendicularPrefixCap,
            perpendicularMaxString = 'max' + perpendicularPrefixCap,    
            parallelSize = targetSize[parallelPrefix] - me.scrollOffset,
            perpendicularSize = targetSize[perpendicularPrefix],
            padding = me.padding,
            parallelOffset = padding[me.parallelBefore],
            paddingParallel = parallelOffset + padding[me.parallelAfter],
            perpendicularOffset = padding[me.perpendicularLeftTop],
            paddingPerpendicular =  perpendicularOffset + padding[me.perpendicularRightBottom],
            availPerpendicularSize = mmax(0, perpendicularSize - paddingPerpendicular),    
            isStart = me.pack == 'start',
            isCenter = me.pack == 'center',
            isEnd = me.pack == 'end',    
            constrain = Ext.Number.constrain,
            visibleCount = visibleItems.length,
            nonFlexSize = 0,
            totalFlex = 0,
            desiredSize = 0,
            minimumSize = 0,
            maxSize = 0,
            boxes = [],
            minSizes = [],
            calculatedWidth,    
            i, child, childParallel, childPerpendicular, childMargins, childSize, minParallel, tmpObj, shortfall, 
            tooNarrow, availableSpace, minSize, item, length, itemIndex, box, oldSize, newSize, reduction, diff, 
            flexedBoxes, remainingSpace, remainingFlex, flexedSize, parallelMargins, calcs, offset, 
            perpendicularMargins, stretchSize;

        for (i = 0; i < visibleCount; i++) {
            child = visibleItems[i];
            childPerpendicular = child[perpendicularPrefix];
            me.layoutItem(child);
            childMargins = child.margins;
            parallelMargins = childMargins[me.parallelBefore] + childMargins[me.parallelAfter];

            tmpObj = {
                component: child,
                margins: childMargins
            };

            // flex and not 'auto' width
            if (child.flex) {
                totalFlex += child.flex;
                childParallel = undefinedValue;
            }
            // Not flexed or 'auto' width or undefined width
            else {
                if (!(child[parallelPrefix] && childPerpendicular)) {
                    childSize = child.getSize();
                }
                childParallel = child[parallelPrefix] || childSize[parallelPrefix];
                childPerpendicular = childPerpendicular || childSize[perpendicularPrefix];
            }

            nonFlexSize += parallelMargins + (childParallel || 0);
            desiredSize += parallelMargins + (child.flex ? child[parallelMinString] || 0 : childParallel);
            minimumSize += parallelMargins + (child[parallelMinString] || childParallel || 0);

            // Max height for align - force layout of non-laid out subcontainers without a numeric height
            if (typeof childPerpendicular != 'number') {
                // Clear any static sizing and revert to flow so we can get a proper measurement
                childPerpendicular = child['get' + perpendicularPrefixCap]();
            }

            // Track the maximum perpendicular size for use by the stretch and stretchmax align config values.
            maxSize = mmax(maxSize, childPerpendicular + childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom]);

            tmpObj[parallelPrefix] = childParallel || undefinedValue;
            tmpObj[perpendicularPrefix] = childPerpendicular || undefinedValue;
            boxes.push(tmpObj);
        }
        shortfall = desiredSize - parallelSize;
        tooNarrow = minimumSize > parallelSize;

        //the space available to the flexed items
        availableSpace = mmax(0, parallelSize - nonFlexSize - paddingParallel - (me.reserveOffset ? me.availableSpaceOffset : 0));

        if (tooNarrow) {
            for (i = 0; i < visibleCount; i++) {
                box = boxes[i];
                minSize = visibleItems[i][parallelMinString] || visibleItems[i][parallelPrefix] || box[parallelPrefix];
                box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
                box[parallelPrefix] = minSize;
            }
        }
        else {
            if (shortfall > 0) {
                 for (i = 0; i < visibleCount; i++) {
                    item = visibleItems[i];
                    minSize = item[parallelMinString] || 0;
                    if (item.flex) {
                        box = boxes[i];
                        box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
                        box[parallelPrefix] = minSize;
                    }
                    else {
                        minSizes.push({
                            minSize: minSize,
                            available: boxes[i][parallelPrefix] - minSize,
                            index: i
                        });
                    }
                }

                Ext.Array.sort(minSizes, me.minSizeSortFn);

                for (i = 0, length = minSizes.length; i < length; i++) {
                    itemIndex = minSizes[i].index;

                    if (itemIndex == undefinedValue) {
                        continue;
                    }
                    item = visibleItems[itemIndex];
                    minSize = minSizes[i].minSize;

                    box = boxes[itemIndex];
                    oldSize = box[parallelPrefix];
                    newSize = mmax(minSize, oldSize - math.ceil(shortfall / (length - i)));
                    reduction = oldSize - newSize;

                    box.dirtySize = box.dirtySize || box[parallelPrefix] != newSize;
                    box[parallelPrefix] = newSize;
                    shortfall -= reduction;
                }
            }
            else {
                remainingSpace = availableSpace;
                remainingFlex = totalFlex;
                flexedBoxes = [];

                for (i = 0; i < visibleCount; i++) {
                    child = visibleItems[i];
                    if (isStart && child.flex) {
                        flexedBoxes.push(boxes[Ext.Array.indexOf(visibleItems, child)]);
                    }
                }
                Ext.Array.sort(flexedBoxes, me.flexSortFn);

                for (i = 0; i < flexedBoxes.length; i++) {
                    calcs = flexedBoxes[i];
                    child = calcs.component;
                    childMargins = calcs.margins;

                    flexedSize = math.ceil((child.flex / remainingFlex) * remainingSpace);

                    flexedSize = Math.max(child['min' + parallelPrefixCap] || 0, math.min(child['max' + parallelPrefixCap] || infiniteValue, flexedSize));

                    remainingSpace -= flexedSize;
                    remainingFlex -= child.flex;

                    calcs.dirtySize = calcs.dirtySize || calcs[parallelPrefix] != flexedSize;
                    calcs[parallelPrefix] = flexedSize;
                }
            }
        }

        if (isCenter) {
            parallelOffset += availableSpace / 2;
        }
        else if (isEnd) {
            parallelOffset += availableSpace;
        }

        if (me.owner.dock && (Ext.isIE6 || Ext.isIE7 || Ext.isIEQuirks) && !me.owner.width && me.direction == 'vertical') {

            calculatedWidth = maxSize + me.owner.el.getPadding('lr') + me.owner.el.getBorderWidth('lr');
            if (me.owner.frameSize) {
                calculatedWidth += me.owner.frameSize.left + me.owner.frameSize.right;
            }
            availPerpendicularSize = Math.min(availPerpendicularSize, targetSize.width = maxSize + padding.left + padding.right);
        }

        //finally, calculate the left and top position of each item
        for (i = 0; i < visibleCount; i++) {
            child = visibleItems[i];
            calcs = boxes[i];

            childMargins = calcs.margins;

            perpendicularMargins = childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom];

            parallelOffset += childMargins[me.parallelBefore];

            calcs[me.parallelBefore] = parallelOffset;
            calcs[me.perpendicularLeftTop] = perpendicularOffset + childMargins[me.perpendicularLeftTop];

            if (me.align == 'stretch') {
                stretchSize = constrain(availPerpendicularSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
                calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
                calcs[perpendicularPrefix] = stretchSize;
            }
            else if (me.align == 'stretchmax') {
                stretchSize = constrain(maxSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
                calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
                calcs[perpendicularPrefix] = stretchSize;
            }
            else if (me.align == me.alignCenteringString) {
                // When calculating a centered position within the content box of the innerCt, the width of the borders must be subtracted from
                // the size to yield the space available to center within.
                // The updateInnerCtSize method explicitly adds the border widths to the set size of the innerCt.
                diff = mmax(availPerpendicularSize, maxSize) - me.innerCt.getBorderWidth(me.perpendicularLT + me.perpendicularRB) - calcs[perpendicularPrefix];
                if (diff > 0) {
                    calcs[me.perpendicularLeftTop] = perpendicularOffset + Math.round(diff / 2);
                }
            }

            // Advance past the box size and the "after" margin
            parallelOffset += (calcs[parallelPrefix] || 0) + childMargins[me.parallelAfter];
        }

        return {
            boxes: boxes,
            meta : {
                calculatedWidth: calculatedWidth,
                maxSize: maxSize,
                nonFlexSize: nonFlexSize,
                desiredSize: desiredSize,
                minimumSize: minimumSize,
                shortfall: shortfall,
                tooNarrow: tooNarrow
            }
        };
    },

    onRemove: function(comp){
        this.callParent(arguments);
        if (this.overflowHandler) {
            this.overflowHandler.onRemove(comp);
        }
    },

       initOverflowHandler: function() {
        var handler = this.overflowHandler;

        if (typeof handler == 'string') {
            handler = {
                type: handler
            };
        }

        var handlerType = 'None';
        if (handler && handler.type !== undefined) {
            handlerType = handler.type;
        }

        var constructor = Ext.layout.container.boxOverflow[handlerType];
        if (constructor[this.type]) {
            constructor = constructor[this.type];
        }

        this.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.' + handlerType, this, handler);
    },

        onLayout: function() {
        this.callParent();
        // Clear the innerCt size so it doesn't influence the child items.
        if (this.clearInnerCtOnLayout === true && this.adjustmentPass !== true) {
            this.innerCt.setSize(null, null);
        }

        var me = this,
            targetSize = me.getLayoutTargetSize(),
            items = me.getVisibleItems(),
            calcs = me.calculateChildBoxes(items, targetSize),
            boxes = calcs.boxes,
            meta = calcs.meta,
            handler, method, results;

        if (me.autoSize && calcs.meta.desiredSize) {
            targetSize[me.parallelPrefix] = calcs.meta.desiredSize;
        }

        //invoke the overflow handler, if one is configured
        if (meta.shortfall > 0) {
            handler = me.overflowHandler;
            method = meta.tooNarrow ? 'handleOverflow': 'clearOverflow';

            results = handler[method](calcs, targetSize);

            if (results) {
                if (results.targetSize) {
                    targetSize = results.targetSize;
                }

                if (results.recalculate) {
                    items = me.getVisibleItems(owner);
                    calcs = me.calculateChildBoxes(items, targetSize);
                    boxes = calcs.boxes;
                }
            }
        } else {
            me.overflowHandler.clearOverflow();
        }

              me.layoutTargetLastSize = targetSize;

               me.childBoxCache = calcs;

        me.updateInnerCtSize(targetSize, calcs);
        me.updateChildBoxes(boxes);
        me.handleTargetOverflow(targetSize);
    },

       updateChildBoxes: function(boxes) {
        var me = this,
            i = 0,
            length = boxes.length,
            animQueue = [],
            dd = Ext.dd.DDM.getDDById(me.innerCt.id), // Any DD active on this layout's element (The BoxReorderer plugin does this.)
            oldBox, newBox, changed, comp, boxAnim, animCallback;

        for (; i < length; i++) {
            newBox = boxes[i];
            comp = newBox.component;

            // If a Component is being drag/dropped, skip positioning it.
            // Accomodate the BoxReorderer plugin: Its current dragEl must not be positioned by the layout
            if (dd && (dd.getDragEl() === comp.el.dom)) {
                continue;
            }

            changed = false;

            oldBox = me.getChildBox(comp);

            // If we are animating, we build up an array of Anim config objects, one for each
            // child Component which has any changed box properties. Those with unchanged
            // properties are not animated.
            if (me.animate) {
                // Animate may be a config object containing callback.
                animCallback = me.animate.callback || me.animate;
                boxAnim = {
                    layoutAnimation: true,  // Component Target handler must use set*Calculated*Size
                    target: comp,
                    from: {},
                    to: {},
                    listeners: {}
                };
                // Only set from and to properties when there's a change.
                // Perform as few Component setter methods as possible.
                // Temporarily set the property values that we are not animating
                // so that doComponentLayout does not auto-size them.
                if (!isNaN(newBox.width) && (newBox.width != oldBox.width)) {
                    changed = true;
                    // boxAnim.from.width = oldBox.width;
                    boxAnim.to.width = newBox.width;
                }
                if (!isNaN(newBox.height) && (newBox.height != oldBox.height)) {
                    changed = true;
                    // boxAnim.from.height = oldBox.height;
                    boxAnim.to.height = newBox.height;
                }
                if (!isNaN(newBox.left) && (newBox.left != oldBox.left)) {
                    changed = true;
                    // boxAnim.from.left = oldBox.left;
                    boxAnim.to.left = newBox.left;
                }
                if (!isNaN(newBox.top) && (newBox.top != oldBox.top)) {
                    changed = true;
                    // boxAnim.from.top = oldBox.top;
                    boxAnim.to.top = newBox.top;
                }
                if (changed) {
                    animQueue.push(boxAnim);
                }
            } else {
                if (newBox.dirtySize) {
                    if (newBox.width !== oldBox.width || newBox.height !== oldBox.height) {
                        me.setItemSize(comp, newBox.width, newBox.height);
                    }
                }
                // Don't set positions to NaN
                if (isNaN(newBox.left) || isNaN(newBox.top)) {
                    continue;
                }
                comp.setPosition(newBox.left, newBox.top);
            }
        }

        // Kick off any queued animations
        length = animQueue.length;
        if (length) {

            // A function which cleans up when a Component's animation is done.
            // The last one to finish calls the callback.
            var afterAnimate = function(anim) {
                // When we've animated all changed boxes into position, clear our busy flag and call the callback.
                length -= 1;
                if (!length) {
                    me.layoutBusy = false;
                    if (Ext.isFunction(animCallback)) {
                        animCallback();
                    }
                }
            };

            var beforeAnimate = function() {
                me.layoutBusy = true;
            };

            // Start each box animation off
            for (i = 0, length = animQueue.length; i < length; i++) {
                boxAnim = animQueue[i];

                // Clean up the Component after. Clean up the *layout* after the last animation finishes
                boxAnim.listeners.afteranimate = afterAnimate;

                // The layout is busy during animation, and may not be called, so set the flag when the first animation begins
                if (!i) {
                    boxAnim.listeners.beforeanimate = beforeAnimate;
                }
                if (me.animate.duration) {
                    boxAnim.duration = me.animate.duration;
                }
                comp = boxAnim.target;
                delete boxAnim.target;
                // Stop any currently running animation
                comp.stopAnimation();
                comp.animate(boxAnim);
            }
        }
    },

       updateInnerCtSize: function(tSize, calcs) {
        var me = this,
            mmax = Math.max,
            align = me.align,
            padding = me.padding,
            width = tSize.width,
            height = tSize.height,
            meta = calcs.meta,
            innerCtWidth,
            innerCtHeight;

        if (me.direction == 'horizontal') {
            innerCtWidth = width;
            innerCtHeight = meta.maxSize + padding.top + padding.bottom + me.innerCt.getBorderWidth('tb');

            if (align == 'stretch') {
                innerCtHeight = height;
            }
            else if (align == 'middle') {
                innerCtHeight = mmax(height, innerCtHeight);
            }
        } else {
            innerCtHeight = height;
            innerCtWidth = meta.maxSize + padding.left + padding.right + me.innerCt.getBorderWidth('lr');

            if (align == 'stretch') {
                innerCtWidth = width;
            }
            else if (align == 'center') {
                innerCtWidth = mmax(width, innerCtWidth);
            }
        }
        me.getRenderTarget().setSize(innerCtWidth || undefined, innerCtHeight || undefined);

        // If a calculated width has been found (and this only happens for auto-width vertical docked Components in old Microsoft browsers)
        // then, if the Component has not assumed the size of its content, set it to do so.
        if (meta.calculatedWidth && me.owner.el.getWidth() > meta.calculatedWidth) {
            me.owner.el.setWidth(meta.calculatedWidth);
        }

        if (me.innerCt.dom.scrollTop) {
            me.innerCt.dom.scrollTop = 0;
        }
    },

        handleTargetOverflow: function(previousTargetSize) {
        var target = this.getTarget(),
            overflow = target.getStyle('overflow'),
            newTargetSize;

        if (overflow && overflow != 'hidden' && !this.adjustmentPass) {
            newTargetSize = this.getLayoutTargetSize();
            if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height) {
                this.adjustmentPass = true;
                this.onLayout();
                return true;
            }
        }

        delete this.adjustmentPass;
    },

    // private
    isValidParent : function(item, target, position) {
        // Note: Box layouts do not care about order within the innerCt element because it's an absolutely positioning layout
        // We only care whether the item is a direct child of the innerCt element.
        var itemEl = item.el ? item.el.dom : Ext.getDom(item);
        return (itemEl && this.innerCt && itemEl.parentNode === this.innerCt.dom) || false;
    },

    // Overridden method from AbstractContainer.
    // Used in the base AbstractLayout.beforeLayout method to render all items into.
    getRenderTarget: function() {
        if (!this.innerCt) {
            // the innerCt prevents wrapping and shuffling while the container is resizing
            this.innerCt = this.getTarget().createChild({
                cls: this.innerCls,
                role: 'presentation'
            });
            this.padding = Ext.util.Format.parseBox(this.padding);
        }
        return this.innerCt;
    },

    // private
    renderItem: function(item, target) {
        this.callParent(arguments);
        var me = this,
            itemEl = item.getEl(),
            style = itemEl.dom.style,
            margins = item.margins || item.margin;

        // Parse the item's margin/margins specification
        if (margins) {
            if (Ext.isString(margins) || Ext.isNumber(margins)) {
                margins = Ext.util.Format.parseBox(margins);
            } else {
                Ext.applyIf(margins, {top: 0, right: 0, bottom: 0, left: 0});
            }
        } else {
            margins = Ext.apply({}, me.defaultMargins);
        }

        // Add any before/after CSS margins to the configured margins, and zero the CSS margins
        margins.top    += itemEl.getMargin('t');
        margins.right  += itemEl.getMargin('r');
        margins.bottom += itemEl.getMargin('b');
        margins.left   += itemEl.getMargin('l');
        style.marginTop = style.marginRight = style.marginBottom = style.marginLeft = '0';

        // Item must reference calculated margins.
        item.margins = margins;
    },
    destroy: function() {
        Ext.destroy(this.overflowHandler);
        this.callParent(arguments);
    }
});

如有帮助,我们将不胜感激。

We are using ExtJS4 in our application.But we are facing an issue with hbox layout.We need to displat the items from right side.Normally in ExtJS4,items in hbox layout start from left side and move towards right side.But we need to start from right side and move towards left side.I think we need to change the order in ExtJS4 library(box layout).

ExtJS4 box layout is:

/*

This file is part of Ext JS 4

Copyright (c) 2011 Sencha Inc

Contact:  http://www.sencha.com/contact

GNU General Public License Usage
This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.

If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.

*/

Ext.define('Ext.layout.container.Box', { 
    alias: ['layout.box'],
    extend: 'Ext.layout.container.Container',
    alternateClassName: 'Ext.layout.BoxLayout'      
    requires: [
        'Ext.layout.container.boxOverflow.None',
        'Ext.layout.container.boxOverflow.Menu',
        'Ext.layout.container.boxOverflow.Scroller',
        'Ext.util.Format',
        'Ext.dd.DragDropManager'
    ],
       defaultMargins: {
        top: 0,
        right: 0,
        bottom: 0,
        left: 0
    },  
    padding: '0', 
    type: 'box',
    scrollOffset: 0,
    itemCls: Ext.baseCSSPrefix + 'box-item',
    targetCls: Ext.baseCSSPrefix + 'box-layout-ct',
    innerCls: Ext.baseCSSPrefix + 'box-inner',   
    bindToOwnerCtContainer: true,    
    fixedLayout: false,        
     availableSpaceOffset: 0,
    reserveOffset: true,       
    clearInnerCtOnLayout: false,   
    flexSortFn: function (a, b) {
        var maxParallelPrefix = 'max' + this.parallelPrefixCap,
            infiniteValue = Infinity;
        a = a.component[maxParallelPrefix] || infiniteValue;
        b = b.component[maxParallelPrefix] || infiniteValue;
        // IE 6/7 Don't like Infinity - Infinity...
        if (!isFinite(a) && !isFinite(b)) {
            return false;
        }
        return a - b;
    },   
    // Sort into *descending* order.
    minSizeSortFn: function(a, b) {
        return b.available - a.available;
    },  
    constructor: function(config) {
        var me = this;   
        me.callParent(arguments);
        me.flexSortFn = Ext.Function.bind(me.flexSortFn, me);    
        me.initOverflowHandler();
    },    
        getChildBox: function(child) {
        child = child.el || this.owner.getComponent(child).el;
        return {
            left: child.getLeft(true),
            top: child.getTop(true),
            width: child.getWidth(),
            height: child.getHeight()
        };
    },

       calculateChildBox: function(child) {
        var me = this,
            boxes = me.calculateChildBoxes(me.getVisibleItems(), me.getLayoutTargetSize()).boxes,
            ln = boxes.length,
            i = 0;

        child = me.owner.getComponent(child);
        for (; i < ln; i++) {
            if (boxes[i].component === child) {
                return boxes[i];
            }
        }
    },

       calculateChildBoxes: function(visibleItems, targetSize) {
        var me = this,
            math = Math,
            mmax = math.max,
            infiniteValue = Infinity,
            undefinedValue,    
            parallelPrefix = me.parallelPrefix,
            parallelPrefixCap = me.parallelPrefixCap,
            perpendicularPrefix = me.perpendicularPrefix,
            perpendicularPrefixCap = me.perpendicularPrefixCap,
            parallelMinString = 'min' + parallelPrefixCap,
            perpendicularMinString = 'min' + perpendicularPrefixCap,
            perpendicularMaxString = 'max' + perpendicularPrefixCap,    
            parallelSize = targetSize[parallelPrefix] - me.scrollOffset,
            perpendicularSize = targetSize[perpendicularPrefix],
            padding = me.padding,
            parallelOffset = padding[me.parallelBefore],
            paddingParallel = parallelOffset + padding[me.parallelAfter],
            perpendicularOffset = padding[me.perpendicularLeftTop],
            paddingPerpendicular =  perpendicularOffset + padding[me.perpendicularRightBottom],
            availPerpendicularSize = mmax(0, perpendicularSize - paddingPerpendicular),    
            isStart = me.pack == 'start',
            isCenter = me.pack == 'center',
            isEnd = me.pack == 'end',    
            constrain = Ext.Number.constrain,
            visibleCount = visibleItems.length,
            nonFlexSize = 0,
            totalFlex = 0,
            desiredSize = 0,
            minimumSize = 0,
            maxSize = 0,
            boxes = [],
            minSizes = [],
            calculatedWidth,    
            i, child, childParallel, childPerpendicular, childMargins, childSize, minParallel, tmpObj, shortfall, 
            tooNarrow, availableSpace, minSize, item, length, itemIndex, box, oldSize, newSize, reduction, diff, 
            flexedBoxes, remainingSpace, remainingFlex, flexedSize, parallelMargins, calcs, offset, 
            perpendicularMargins, stretchSize;

        for (i = 0; i < visibleCount; i++) {
            child = visibleItems[i];
            childPerpendicular = child[perpendicularPrefix];
            me.layoutItem(child);
            childMargins = child.margins;
            parallelMargins = childMargins[me.parallelBefore] + childMargins[me.parallelAfter];

            tmpObj = {
                component: child,
                margins: childMargins
            };

            // flex and not 'auto' width
            if (child.flex) {
                totalFlex += child.flex;
                childParallel = undefinedValue;
            }
            // Not flexed or 'auto' width or undefined width
            else {
                if (!(child[parallelPrefix] && childPerpendicular)) {
                    childSize = child.getSize();
                }
                childParallel = child[parallelPrefix] || childSize[parallelPrefix];
                childPerpendicular = childPerpendicular || childSize[perpendicularPrefix];
            }

            nonFlexSize += parallelMargins + (childParallel || 0);
            desiredSize += parallelMargins + (child.flex ? child[parallelMinString] || 0 : childParallel);
            minimumSize += parallelMargins + (child[parallelMinString] || childParallel || 0);

            // Max height for align - force layout of non-laid out subcontainers without a numeric height
            if (typeof childPerpendicular != 'number') {
                // Clear any static sizing and revert to flow so we can get a proper measurement
                childPerpendicular = child['get' + perpendicularPrefixCap]();
            }

            // Track the maximum perpendicular size for use by the stretch and stretchmax align config values.
            maxSize = mmax(maxSize, childPerpendicular + childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom]);

            tmpObj[parallelPrefix] = childParallel || undefinedValue;
            tmpObj[perpendicularPrefix] = childPerpendicular || undefinedValue;
            boxes.push(tmpObj);
        }
        shortfall = desiredSize - parallelSize;
        tooNarrow = minimumSize > parallelSize;

        //the space available to the flexed items
        availableSpace = mmax(0, parallelSize - nonFlexSize - paddingParallel - (me.reserveOffset ? me.availableSpaceOffset : 0));

        if (tooNarrow) {
            for (i = 0; i < visibleCount; i++) {
                box = boxes[i];
                minSize = visibleItems[i][parallelMinString] || visibleItems[i][parallelPrefix] || box[parallelPrefix];
                box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
                box[parallelPrefix] = minSize;
            }
        }
        else {
            if (shortfall > 0) {
                 for (i = 0; i < visibleCount; i++) {
                    item = visibleItems[i];
                    minSize = item[parallelMinString] || 0;
                    if (item.flex) {
                        box = boxes[i];
                        box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
                        box[parallelPrefix] = minSize;
                    }
                    else {
                        minSizes.push({
                            minSize: minSize,
                            available: boxes[i][parallelPrefix] - minSize,
                            index: i
                        });
                    }
                }

                Ext.Array.sort(minSizes, me.minSizeSortFn);

                for (i = 0, length = minSizes.length; i < length; i++) {
                    itemIndex = minSizes[i].index;

                    if (itemIndex == undefinedValue) {
                        continue;
                    }
                    item = visibleItems[itemIndex];
                    minSize = minSizes[i].minSize;

                    box = boxes[itemIndex];
                    oldSize = box[parallelPrefix];
                    newSize = mmax(minSize, oldSize - math.ceil(shortfall / (length - i)));
                    reduction = oldSize - newSize;

                    box.dirtySize = box.dirtySize || box[parallelPrefix] != newSize;
                    box[parallelPrefix] = newSize;
                    shortfall -= reduction;
                }
            }
            else {
                remainingSpace = availableSpace;
                remainingFlex = totalFlex;
                flexedBoxes = [];

                for (i = 0; i < visibleCount; i++) {
                    child = visibleItems[i];
                    if (isStart && child.flex) {
                        flexedBoxes.push(boxes[Ext.Array.indexOf(visibleItems, child)]);
                    }
                }
                Ext.Array.sort(flexedBoxes, me.flexSortFn);

                for (i = 0; i < flexedBoxes.length; i++) {
                    calcs = flexedBoxes[i];
                    child = calcs.component;
                    childMargins = calcs.margins;

                    flexedSize = math.ceil((child.flex / remainingFlex) * remainingSpace);

                    flexedSize = Math.max(child['min' + parallelPrefixCap] || 0, math.min(child['max' + parallelPrefixCap] || infiniteValue, flexedSize));

                    remainingSpace -= flexedSize;
                    remainingFlex -= child.flex;

                    calcs.dirtySize = calcs.dirtySize || calcs[parallelPrefix] != flexedSize;
                    calcs[parallelPrefix] = flexedSize;
                }
            }
        }

        if (isCenter) {
            parallelOffset += availableSpace / 2;
        }
        else if (isEnd) {
            parallelOffset += availableSpace;
        }

        if (me.owner.dock && (Ext.isIE6 || Ext.isIE7 || Ext.isIEQuirks) && !me.owner.width && me.direction == 'vertical') {

            calculatedWidth = maxSize + me.owner.el.getPadding('lr') + me.owner.el.getBorderWidth('lr');
            if (me.owner.frameSize) {
                calculatedWidth += me.owner.frameSize.left + me.owner.frameSize.right;
            }
            availPerpendicularSize = Math.min(availPerpendicularSize, targetSize.width = maxSize + padding.left + padding.right);
        }

        //finally, calculate the left and top position of each item
        for (i = 0; i < visibleCount; i++) {
            child = visibleItems[i];
            calcs = boxes[i];

            childMargins = calcs.margins;

            perpendicularMargins = childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom];

            parallelOffset += childMargins[me.parallelBefore];

            calcs[me.parallelBefore] = parallelOffset;
            calcs[me.perpendicularLeftTop] = perpendicularOffset + childMargins[me.perpendicularLeftTop];

            if (me.align == 'stretch') {
                stretchSize = constrain(availPerpendicularSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
                calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
                calcs[perpendicularPrefix] = stretchSize;
            }
            else if (me.align == 'stretchmax') {
                stretchSize = constrain(maxSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
                calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
                calcs[perpendicularPrefix] = stretchSize;
            }
            else if (me.align == me.alignCenteringString) {
                // When calculating a centered position within the content box of the innerCt, the width of the borders must be subtracted from
                // the size to yield the space available to center within.
                // The updateInnerCtSize method explicitly adds the border widths to the set size of the innerCt.
                diff = mmax(availPerpendicularSize, maxSize) - me.innerCt.getBorderWidth(me.perpendicularLT + me.perpendicularRB) - calcs[perpendicularPrefix];
                if (diff > 0) {
                    calcs[me.perpendicularLeftTop] = perpendicularOffset + Math.round(diff / 2);
                }
            }

            // Advance past the box size and the "after" margin
            parallelOffset += (calcs[parallelPrefix] || 0) + childMargins[me.parallelAfter];
        }

        return {
            boxes: boxes,
            meta : {
                calculatedWidth: calculatedWidth,
                maxSize: maxSize,
                nonFlexSize: nonFlexSize,
                desiredSize: desiredSize,
                minimumSize: minimumSize,
                shortfall: shortfall,
                tooNarrow: tooNarrow
            }
        };
    },

    onRemove: function(comp){
        this.callParent(arguments);
        if (this.overflowHandler) {
            this.overflowHandler.onRemove(comp);
        }
    },

       initOverflowHandler: function() {
        var handler = this.overflowHandler;

        if (typeof handler == 'string') {
            handler = {
                type: handler
            };
        }

        var handlerType = 'None';
        if (handler && handler.type !== undefined) {
            handlerType = handler.type;
        }

        var constructor = Ext.layout.container.boxOverflow[handlerType];
        if (constructor[this.type]) {
            constructor = constructor[this.type];
        }

        this.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.' + handlerType, this, handler);
    },

        onLayout: function() {
        this.callParent();
        // Clear the innerCt size so it doesn't influence the child items.
        if (this.clearInnerCtOnLayout === true && this.adjustmentPass !== true) {
            this.innerCt.setSize(null, null);
        }

        var me = this,
            targetSize = me.getLayoutTargetSize(),
            items = me.getVisibleItems(),
            calcs = me.calculateChildBoxes(items, targetSize),
            boxes = calcs.boxes,
            meta = calcs.meta,
            handler, method, results;

        if (me.autoSize && calcs.meta.desiredSize) {
            targetSize[me.parallelPrefix] = calcs.meta.desiredSize;
        }

        //invoke the overflow handler, if one is configured
        if (meta.shortfall > 0) {
            handler = me.overflowHandler;
            method = meta.tooNarrow ? 'handleOverflow': 'clearOverflow';

            results = handler[method](calcs, targetSize);

            if (results) {
                if (results.targetSize) {
                    targetSize = results.targetSize;
                }

                if (results.recalculate) {
                    items = me.getVisibleItems(owner);
                    calcs = me.calculateChildBoxes(items, targetSize);
                    boxes = calcs.boxes;
                }
            }
        } else {
            me.overflowHandler.clearOverflow();
        }

              me.layoutTargetLastSize = targetSize;

               me.childBoxCache = calcs;

        me.updateInnerCtSize(targetSize, calcs);
        me.updateChildBoxes(boxes);
        me.handleTargetOverflow(targetSize);
    },

       updateChildBoxes: function(boxes) {
        var me = this,
            i = 0,
            length = boxes.length,
            animQueue = [],
            dd = Ext.dd.DDM.getDDById(me.innerCt.id), // Any DD active on this layout's element (The BoxReorderer plugin does this.)
            oldBox, newBox, changed, comp, boxAnim, animCallback;

        for (; i < length; i++) {
            newBox = boxes[i];
            comp = newBox.component;

            // If a Component is being drag/dropped, skip positioning it.
            // Accomodate the BoxReorderer plugin: Its current dragEl must not be positioned by the layout
            if (dd && (dd.getDragEl() === comp.el.dom)) {
                continue;
            }

            changed = false;

            oldBox = me.getChildBox(comp);

            // If we are animating, we build up an array of Anim config objects, one for each
            // child Component which has any changed box properties. Those with unchanged
            // properties are not animated.
            if (me.animate) {
                // Animate may be a config object containing callback.
                animCallback = me.animate.callback || me.animate;
                boxAnim = {
                    layoutAnimation: true,  // Component Target handler must use set*Calculated*Size
                    target: comp,
                    from: {},
                    to: {},
                    listeners: {}
                };
                // Only set from and to properties when there's a change.
                // Perform as few Component setter methods as possible.
                // Temporarily set the property values that we are not animating
                // so that doComponentLayout does not auto-size them.
                if (!isNaN(newBox.width) && (newBox.width != oldBox.width)) {
                    changed = true;
                    // boxAnim.from.width = oldBox.width;
                    boxAnim.to.width = newBox.width;
                }
                if (!isNaN(newBox.height) && (newBox.height != oldBox.height)) {
                    changed = true;
                    // boxAnim.from.height = oldBox.height;
                    boxAnim.to.height = newBox.height;
                }
                if (!isNaN(newBox.left) && (newBox.left != oldBox.left)) {
                    changed = true;
                    // boxAnim.from.left = oldBox.left;
                    boxAnim.to.left = newBox.left;
                }
                if (!isNaN(newBox.top) && (newBox.top != oldBox.top)) {
                    changed = true;
                    // boxAnim.from.top = oldBox.top;
                    boxAnim.to.top = newBox.top;
                }
                if (changed) {
                    animQueue.push(boxAnim);
                }
            } else {
                if (newBox.dirtySize) {
                    if (newBox.width !== oldBox.width || newBox.height !== oldBox.height) {
                        me.setItemSize(comp, newBox.width, newBox.height);
                    }
                }
                // Don't set positions to NaN
                if (isNaN(newBox.left) || isNaN(newBox.top)) {
                    continue;
                }
                comp.setPosition(newBox.left, newBox.top);
            }
        }

        // Kick off any queued animations
        length = animQueue.length;
        if (length) {

            // A function which cleans up when a Component's animation is done.
            // The last one to finish calls the callback.
            var afterAnimate = function(anim) {
                // When we've animated all changed boxes into position, clear our busy flag and call the callback.
                length -= 1;
                if (!length) {
                    me.layoutBusy = false;
                    if (Ext.isFunction(animCallback)) {
                        animCallback();
                    }
                }
            };

            var beforeAnimate = function() {
                me.layoutBusy = true;
            };

            // Start each box animation off
            for (i = 0, length = animQueue.length; i < length; i++) {
                boxAnim = animQueue[i];

                // Clean up the Component after. Clean up the *layout* after the last animation finishes
                boxAnim.listeners.afteranimate = afterAnimate;

                // The layout is busy during animation, and may not be called, so set the flag when the first animation begins
                if (!i) {
                    boxAnim.listeners.beforeanimate = beforeAnimate;
                }
                if (me.animate.duration) {
                    boxAnim.duration = me.animate.duration;
                }
                comp = boxAnim.target;
                delete boxAnim.target;
                // Stop any currently running animation
                comp.stopAnimation();
                comp.animate(boxAnim);
            }
        }
    },

       updateInnerCtSize: function(tSize, calcs) {
        var me = this,
            mmax = Math.max,
            align = me.align,
            padding = me.padding,
            width = tSize.width,
            height = tSize.height,
            meta = calcs.meta,
            innerCtWidth,
            innerCtHeight;

        if (me.direction == 'horizontal') {
            innerCtWidth = width;
            innerCtHeight = meta.maxSize + padding.top + padding.bottom + me.innerCt.getBorderWidth('tb');

            if (align == 'stretch') {
                innerCtHeight = height;
            }
            else if (align == 'middle') {
                innerCtHeight = mmax(height, innerCtHeight);
            }
        } else {
            innerCtHeight = height;
            innerCtWidth = meta.maxSize + padding.left + padding.right + me.innerCt.getBorderWidth('lr');

            if (align == 'stretch') {
                innerCtWidth = width;
            }
            else if (align == 'center') {
                innerCtWidth = mmax(width, innerCtWidth);
            }
        }
        me.getRenderTarget().setSize(innerCtWidth || undefined, innerCtHeight || undefined);

        // If a calculated width has been found (and this only happens for auto-width vertical docked Components in old Microsoft browsers)
        // then, if the Component has not assumed the size of its content, set it to do so.
        if (meta.calculatedWidth && me.owner.el.getWidth() > meta.calculatedWidth) {
            me.owner.el.setWidth(meta.calculatedWidth);
        }

        if (me.innerCt.dom.scrollTop) {
            me.innerCt.dom.scrollTop = 0;
        }
    },

        handleTargetOverflow: function(previousTargetSize) {
        var target = this.getTarget(),
            overflow = target.getStyle('overflow'),
            newTargetSize;

        if (overflow && overflow != 'hidden' && !this.adjustmentPass) {
            newTargetSize = this.getLayoutTargetSize();
            if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height) {
                this.adjustmentPass = true;
                this.onLayout();
                return true;
            }
        }

        delete this.adjustmentPass;
    },

    // private
    isValidParent : function(item, target, position) {
        // Note: Box layouts do not care about order within the innerCt element because it's an absolutely positioning layout
        // We only care whether the item is a direct child of the innerCt element.
        var itemEl = item.el ? item.el.dom : Ext.getDom(item);
        return (itemEl && this.innerCt && itemEl.parentNode === this.innerCt.dom) || false;
    },

    // Overridden method from AbstractContainer.
    // Used in the base AbstractLayout.beforeLayout method to render all items into.
    getRenderTarget: function() {
        if (!this.innerCt) {
            // the innerCt prevents wrapping and shuffling while the container is resizing
            this.innerCt = this.getTarget().createChild({
                cls: this.innerCls,
                role: 'presentation'
            });
            this.padding = Ext.util.Format.parseBox(this.padding);
        }
        return this.innerCt;
    },

    // private
    renderItem: function(item, target) {
        this.callParent(arguments);
        var me = this,
            itemEl = item.getEl(),
            style = itemEl.dom.style,
            margins = item.margins || item.margin;

        // Parse the item's margin/margins specification
        if (margins) {
            if (Ext.isString(margins) || Ext.isNumber(margins)) {
                margins = Ext.util.Format.parseBox(margins);
            } else {
                Ext.applyIf(margins, {top: 0, right: 0, bottom: 0, left: 0});
            }
        } else {
            margins = Ext.apply({}, me.defaultMargins);
        }

        // Add any before/after CSS margins to the configured margins, and zero the CSS margins
        margins.top    += itemEl.getMargin('t');
        margins.right  += itemEl.getMargin('r');
        margins.bottom += itemEl.getMargin('b');
        margins.left   += itemEl.getMargin('l');
        style.marginTop = style.marginRight = style.marginBottom = style.marginLeft = '0';

        // Item must reference calculated margins.
        item.margins = margins;
    },
    destroy: function() {
        Ext.destroy(this.overflowHandler);
        this.callParent(arguments);
    }
});

Help would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

烟花易冷人易散 2024-12-05 16:19:36

您只需要设置布局配置,如下所示:

Ext.create('Ext.panel.Panel', {
   layout: {type: 'hbox', pack:'end'}
});

关键是 pack:
控制容器的子项如何打包在一起。此属性可接受的配置值为:

'start' :默认值
子项目打包在容器

“center”的左侧一侧:
子项目在容器

'end' 的中宽处打包在一起:
子物品包装在一起在容器的右侧

希望有帮助

You just need to set your layout config, like this:

Ext.create('Ext.panel.Panel', {
   layout: {type: 'hbox', pack:'end'}
});

The key there is pack:
Controls how the child items of the container are packed together. Acceptable configuration values for this property are:

'start' : Default
child items are packed together at left side of container

'center' :
child items are packed together at mid-width of container

'end' :
child items are packed together at right side of container

Hope that helps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文