[76] | 1 | /*! |
---|
| 2 | * Ext JS Library 3.4.0 |
---|
| 3 | * Copyright(c) 2006-2011 Sencha Inc. |
---|
| 4 | * licensing@sencha.com |
---|
| 5 | * http://www.sencha.com/license |
---|
| 6 | */ |
---|
| 7 | /** |
---|
| 8 | * @class Ext.layout.BoxLayout |
---|
| 9 | * @extends Ext.layout.ContainerLayout |
---|
| 10 | * <p>Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.</p> |
---|
| 11 | */ |
---|
| 12 | Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, { |
---|
| 13 | /** |
---|
| 14 | * @cfg {Object} defaultMargins |
---|
| 15 | * <p>If the individual contained items do not have a <tt>margins</tt> |
---|
| 16 | * property specified, the default margins from this property will be |
---|
| 17 | * applied to each item.</p> |
---|
| 18 | * <br><p>This property may be specified as an object containing margins |
---|
| 19 | * to apply in the format:</p><pre><code> |
---|
| 20 | { |
---|
| 21 | top: (top margin), |
---|
| 22 | right: (right margin), |
---|
| 23 | bottom: (bottom margin), |
---|
| 24 | left: (left margin) |
---|
| 25 | }</code></pre> |
---|
| 26 | * <p>This property may also be specified as a string containing |
---|
| 27 | * space-separated, numeric margin values. The order of the sides associated |
---|
| 28 | * with each value matches the way CSS processes margin values:</p> |
---|
| 29 | * <div class="mdetail-params"><ul> |
---|
| 30 | * <li>If there is only one value, it applies to all sides.</li> |
---|
| 31 | * <li>If there are two values, the top and bottom borders are set to the |
---|
| 32 | * first value and the right and left are set to the second.</li> |
---|
| 33 | * <li>If there are three values, the top is set to the first value, the left |
---|
| 34 | * and right are set to the second, and the bottom is set to the third.</li> |
---|
| 35 | * <li>If there are four values, they apply to the top, right, bottom, and |
---|
| 36 | * left, respectively.</li> |
---|
| 37 | * </ul></div> |
---|
| 38 | * <p>Defaults to:</p><pre><code> |
---|
| 39 | * {top:0, right:0, bottom:0, left:0} |
---|
| 40 | * </code></pre> |
---|
| 41 | */ |
---|
| 42 | defaultMargins : {left:0,top:0,right:0,bottom:0}, |
---|
| 43 | /** |
---|
| 44 | * @cfg {String} padding |
---|
| 45 | * <p>Sets the padding to be applied to all child items managed by this layout.</p> |
---|
| 46 | * <p>This property must be specified as a string containing |
---|
| 47 | * space-separated, numeric padding values. The order of the sides associated |
---|
| 48 | * with each value matches the way CSS processes padding values:</p> |
---|
| 49 | * <div class="mdetail-params"><ul> |
---|
| 50 | * <li>If there is only one value, it applies to all sides.</li> |
---|
| 51 | * <li>If there are two values, the top and bottom borders are set to the |
---|
| 52 | * first value and the right and left are set to the second.</li> |
---|
| 53 | * <li>If there are three values, the top is set to the first value, the left |
---|
| 54 | * and right are set to the second, and the bottom is set to the third.</li> |
---|
| 55 | * <li>If there are four values, they apply to the top, right, bottom, and |
---|
| 56 | * left, respectively.</li> |
---|
| 57 | * </ul></div> |
---|
| 58 | * <p>Defaults to: <code>"0"</code></p> |
---|
| 59 | */ |
---|
| 60 | padding : '0', |
---|
| 61 | // documented in subclasses |
---|
| 62 | pack : 'start', |
---|
| 63 | |
---|
| 64 | // private |
---|
| 65 | monitorResize : true, |
---|
| 66 | type: 'box', |
---|
| 67 | scrollOffset : 0, |
---|
| 68 | extraCls : 'x-box-item', |
---|
| 69 | targetCls : 'x-box-layout-ct', |
---|
| 70 | innerCls : 'x-box-inner', |
---|
| 71 | |
---|
| 72 | constructor : function(config){ |
---|
| 73 | Ext.layout.BoxLayout.superclass.constructor.call(this, config); |
---|
| 74 | |
---|
| 75 | if (Ext.isString(this.defaultMargins)) { |
---|
| 76 | this.defaultMargins = this.parseMargins(this.defaultMargins); |
---|
| 77 | } |
---|
| 78 | |
---|
| 79 | var handler = this.overflowHandler; |
---|
| 80 | |
---|
| 81 | if (typeof handler == 'string') { |
---|
| 82 | handler = { |
---|
| 83 | type: handler |
---|
| 84 | }; |
---|
| 85 | } |
---|
| 86 | |
---|
| 87 | var handlerType = 'none'; |
---|
| 88 | if (handler && handler.type != undefined) { |
---|
| 89 | handlerType = handler.type; |
---|
| 90 | } |
---|
| 91 | |
---|
| 92 | var constructor = Ext.layout.boxOverflow[handlerType]; |
---|
| 93 | if (constructor[this.type]) { |
---|
| 94 | constructor = constructor[this.type]; |
---|
| 95 | } |
---|
| 96 | |
---|
| 97 | this.overflowHandler = new constructor(this, handler); |
---|
| 98 | }, |
---|
| 99 | |
---|
| 100 | /** |
---|
| 101 | * @private |
---|
| 102 | * Runs the child box calculations and caches them in childBoxCache. Subclasses can used these cached values |
---|
| 103 | * when laying out |
---|
| 104 | */ |
---|
| 105 | onLayout: function(container, target) { |
---|
| 106 | Ext.layout.BoxLayout.superclass.onLayout.call(this, container, target); |
---|
| 107 | |
---|
| 108 | var tSize = this.getLayoutTargetSize(), |
---|
| 109 | items = this.getVisibleItems(container), |
---|
| 110 | calcs = this.calculateChildBoxes(items, tSize), |
---|
| 111 | boxes = calcs.boxes, |
---|
| 112 | meta = calcs.meta; |
---|
| 113 | |
---|
| 114 | //invoke the overflow handler, if one is configured |
---|
| 115 | if (tSize.width > 0) { |
---|
| 116 | var handler = this.overflowHandler, |
---|
| 117 | method = meta.tooNarrow ? 'handleOverflow' : 'clearOverflow'; |
---|
| 118 | |
---|
| 119 | var results = handler[method](calcs, tSize); |
---|
| 120 | |
---|
| 121 | if (results) { |
---|
| 122 | if (results.targetSize) { |
---|
| 123 | tSize = results.targetSize; |
---|
| 124 | } |
---|
| 125 | |
---|
| 126 | if (results.recalculate) { |
---|
| 127 | items = this.getVisibleItems(container); |
---|
| 128 | calcs = this.calculateChildBoxes(items, tSize); |
---|
| 129 | boxes = calcs.boxes; |
---|
| 130 | } |
---|
| 131 | } |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | /** |
---|
| 135 | * @private |
---|
| 136 | * @property layoutTargetLastSize |
---|
| 137 | * @type Object |
---|
| 138 | * Private cache of the last measured size of the layout target. This should never be used except by |
---|
| 139 | * BoxLayout subclasses during their onLayout run. |
---|
| 140 | */ |
---|
| 141 | this.layoutTargetLastSize = tSize; |
---|
| 142 | |
---|
| 143 | /** |
---|
| 144 | * @private |
---|
| 145 | * @property childBoxCache |
---|
| 146 | * @type Array |
---|
| 147 | * Array of the last calculated height, width, top and left positions of each visible rendered component |
---|
| 148 | * within the Box layout. |
---|
| 149 | */ |
---|
| 150 | this.childBoxCache = calcs; |
---|
| 151 | |
---|
| 152 | this.updateInnerCtSize(tSize, calcs); |
---|
| 153 | this.updateChildBoxes(boxes); |
---|
| 154 | |
---|
| 155 | // Putting a box layout into an overflowed container is NOT correct and will make a second layout pass necessary. |
---|
| 156 | this.handleTargetOverflow(tSize, container, target); |
---|
| 157 | }, |
---|
| 158 | |
---|
| 159 | /** |
---|
| 160 | * Resizes and repositions each child component |
---|
| 161 | * @param {Array} boxes The box measurements |
---|
| 162 | */ |
---|
| 163 | updateChildBoxes: function(boxes) { |
---|
| 164 | for (var i = 0, length = boxes.length; i < length; i++) { |
---|
| 165 | var box = boxes[i], |
---|
| 166 | comp = box.component; |
---|
| 167 | |
---|
| 168 | if (box.dirtySize) { |
---|
| 169 | comp.setSize(box.width, box.height); |
---|
| 170 | } |
---|
| 171 | // Don't set positions to NaN |
---|
| 172 | if (isNaN(box.left) || isNaN(box.top)) { |
---|
| 173 | continue; |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | comp.setPosition(box.left, box.top); |
---|
| 177 | } |
---|
| 178 | }, |
---|
| 179 | |
---|
| 180 | /** |
---|
| 181 | * @private |
---|
| 182 | * Called by onRender just before the child components are sized and positioned. This resizes the innerCt |
---|
| 183 | * to make sure all child items fit within it. We call this before sizing the children because if our child |
---|
| 184 | * items are larger than the previous innerCt size the browser will insert scrollbars and then remove them |
---|
| 185 | * again immediately afterwards, giving a performance hit. |
---|
| 186 | * Subclasses should provide an implementation. |
---|
| 187 | * @param {Object} currentSize The current height and width of the innerCt |
---|
| 188 | * @param {Array} calculations The new box calculations of all items to be laid out |
---|
| 189 | */ |
---|
| 190 | updateInnerCtSize: function(tSize, calcs) { |
---|
| 191 | var align = this.align, |
---|
| 192 | padding = this.padding, |
---|
| 193 | width = tSize.width, |
---|
| 194 | height = tSize.height; |
---|
| 195 | |
---|
| 196 | if (this.type == 'hbox') { |
---|
| 197 | var innerCtWidth = width, |
---|
| 198 | innerCtHeight = calcs.meta.maxHeight + padding.top + padding.bottom; |
---|
| 199 | |
---|
| 200 | if (align == 'stretch') { |
---|
| 201 | innerCtHeight = height; |
---|
| 202 | } else if (align == 'middle') { |
---|
| 203 | innerCtHeight = Math.max(height, innerCtHeight); |
---|
| 204 | } |
---|
| 205 | } else { |
---|
| 206 | var innerCtHeight = height, |
---|
| 207 | innerCtWidth = calcs.meta.maxWidth + padding.left + padding.right; |
---|
| 208 | |
---|
| 209 | if (align == 'stretch') { |
---|
| 210 | innerCtWidth = width; |
---|
| 211 | } else if (align == 'center') { |
---|
| 212 | innerCtWidth = Math.max(width, innerCtWidth); |
---|
| 213 | } |
---|
| 214 | } |
---|
| 215 | |
---|
| 216 | this.innerCt.setSize(innerCtWidth || undefined, innerCtHeight || undefined); |
---|
| 217 | }, |
---|
| 218 | |
---|
| 219 | /** |
---|
| 220 | * @private |
---|
| 221 | * This should be called after onLayout of any BoxLayout subclass. If the target's overflow is not set to 'hidden', |
---|
| 222 | * we need to lay out a second time because the scrollbars may have modified the height and width of the layout |
---|
| 223 | * target. Having a Box layout inside such a target is therefore not recommended. |
---|
| 224 | * @param {Object} previousTargetSize The size and height of the layout target before we just laid out |
---|
| 225 | * @param {Ext.Container} container The container |
---|
| 226 | * @param {Ext.Element} target The target element |
---|
| 227 | */ |
---|
| 228 | handleTargetOverflow: function(previousTargetSize, container, target) { |
---|
| 229 | var overflow = target.getStyle('overflow'); |
---|
| 230 | |
---|
| 231 | if (overflow && overflow != 'hidden' &&!this.adjustmentPass) { |
---|
| 232 | var newTargetSize = this.getLayoutTargetSize(); |
---|
| 233 | if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height){ |
---|
| 234 | this.adjustmentPass = true; |
---|
| 235 | this.onLayout(container, target); |
---|
| 236 | } |
---|
| 237 | } |
---|
| 238 | |
---|
| 239 | delete this.adjustmentPass; |
---|
| 240 | }, |
---|
| 241 | |
---|
| 242 | // private |
---|
| 243 | isValidParent : function(c, target) { |
---|
| 244 | return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom; |
---|
| 245 | }, |
---|
| 246 | |
---|
| 247 | /** |
---|
| 248 | * @private |
---|
| 249 | * Returns all items that are both rendered and visible |
---|
| 250 | * @return {Array} All matching items |
---|
| 251 | */ |
---|
| 252 | getVisibleItems: function(ct) { |
---|
| 253 | var ct = ct || this.container, |
---|
| 254 | t = ct.getLayoutTarget(), |
---|
| 255 | cti = ct.items.items, |
---|
| 256 | len = cti.length, |
---|
| 257 | |
---|
| 258 | i, c, items = []; |
---|
| 259 | |
---|
| 260 | for (i = 0; i < len; i++) { |
---|
| 261 | if((c = cti[i]).rendered && this.isValidParent(c, t) && c.hidden !== true && c.collapsed !== true && c.shouldLayout !== false){ |
---|
| 262 | items.push(c); |
---|
| 263 | } |
---|
| 264 | } |
---|
| 265 | |
---|
| 266 | return items; |
---|
| 267 | }, |
---|
| 268 | |
---|
| 269 | // private |
---|
| 270 | renderAll : function(ct, target) { |
---|
| 271 | if (!this.innerCt) { |
---|
| 272 | // the innerCt prevents wrapping and shuffling while the container is resizing |
---|
| 273 | this.innerCt = target.createChild({cls:this.innerCls}); |
---|
| 274 | this.padding = this.parseMargins(this.padding); |
---|
| 275 | } |
---|
| 276 | Ext.layout.BoxLayout.superclass.renderAll.call(this, ct, this.innerCt); |
---|
| 277 | }, |
---|
| 278 | |
---|
| 279 | getLayoutTargetSize : function() { |
---|
| 280 | var target = this.container.getLayoutTarget(), ret; |
---|
| 281 | |
---|
| 282 | if (target) { |
---|
| 283 | ret = target.getViewSize(); |
---|
| 284 | |
---|
| 285 | // IE in strict mode will return a width of 0 on the 1st pass of getViewSize. |
---|
| 286 | // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly |
---|
| 287 | // with getViewSize |
---|
| 288 | if (Ext.isIE && Ext.isStrict && ret.width == 0){ |
---|
| 289 | ret = target.getStyleSize(); |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | ret.width -= target.getPadding('lr'); |
---|
| 293 | ret.height -= target.getPadding('tb'); |
---|
| 294 | } |
---|
| 295 | |
---|
| 296 | return ret; |
---|
| 297 | }, |
---|
| 298 | |
---|
| 299 | // private |
---|
| 300 | renderItem : function(c) { |
---|
| 301 | if(Ext.isString(c.margins)){ |
---|
| 302 | c.margins = this.parseMargins(c.margins); |
---|
| 303 | }else if(!c.margins){ |
---|
| 304 | c.margins = this.defaultMargins; |
---|
| 305 | } |
---|
| 306 | Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments); |
---|
| 307 | }, |
---|
| 308 | |
---|
| 309 | /** |
---|
| 310 | * @private |
---|
| 311 | */ |
---|
| 312 | destroy: function() { |
---|
| 313 | Ext.destroy(this.overflowHandler); |
---|
| 314 | |
---|
| 315 | Ext.layout.BoxLayout.superclass.destroy.apply(this, arguments); |
---|
| 316 | } |
---|
| 317 | }); |
---|
| 318 | |
---|
| 319 | /** |
---|
| 320 | * @class Ext.layout.boxOverflow.None |
---|
| 321 | * @extends Object |
---|
| 322 | * Base class for Box Layout overflow handlers. These specialized classes are invoked when a Box Layout |
---|
| 323 | * (either an HBox or a VBox) has child items that are either too wide (for HBox) or too tall (for VBox) |
---|
| 324 | * for its container. |
---|
| 325 | */ |
---|
| 326 | |
---|
| 327 | Ext.layout.boxOverflow.None = Ext.extend(Object, { |
---|
| 328 | constructor: function(layout, config) { |
---|
| 329 | this.layout = layout; |
---|
| 330 | |
---|
| 331 | Ext.apply(this, config || {}); |
---|
| 332 | }, |
---|
| 333 | |
---|
| 334 | handleOverflow: Ext.emptyFn, |
---|
| 335 | |
---|
| 336 | clearOverflow: Ext.emptyFn |
---|
| 337 | }); |
---|
| 338 | |
---|
| 339 | |
---|
| 340 | Ext.layout.boxOverflow.none = Ext.layout.boxOverflow.None; |
---|