2011-08-10 66 views
2

我們在我們的應用程序中使用ExtJS4。但是我們正面臨hbox layout的問題。我們需要從右側顯示項目。通常在ExtJS4中,hbox佈局中的項目從左側開始並朝向但我們需要從右側開始並向左側移動。我認爲我們需要更改ExtJS4庫(框佈局)中的順序。ExtJS4 hbox佈局問題

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); 
    } 
}); 

幫助,將不勝感激。

+1

任何方式,你可以減少你已經發布的*代碼的最低限度*所需的代碼重現所描述的問題? –

+0

其實代碼是boxlayout的,我們無法找到它在哪裏計算位置? – Unknown

+0

通常的策略是刪除件直到問題消失。這就是其他人所要做的,大多數人不會花太多時間回答這麼多代碼的問題。 –

回答

5

你只需要設置你的佈局配置,如:

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

的關鍵有包: 控制如何在容器中的子項都擠在一起。此屬性的可接受配置值:

「開始」:默認 子項目擠在一起,在離開容器

「中心」: 子項目在一起打包中寬容器

「端」: 子項在容器的側擠在一起

希望有幫助