<!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-Layout'>/** </span> * Base Layout class - extended by ComponentLayout and ContainerLayout */ Ext.define('Ext.layout.Layout', { requires: [ 'Ext.XTemplate' ], uses: [ 'Ext.layout.Context' ], <span id='Ext-layout-Layout-property-isLayout'> /** </span> * @property {Boolean} isLayout * `true` in this class to identify an object as an instantiated Layout, or subclass thereof. */ isLayout: true, initialized: false, running: false, autoSizePolicy: { setsWidth: 0, setsHeight: 0 }, statics: { layoutsByType: {}, create: function(layout, defaultType) { var ClassManager = Ext.ClassManager, layoutsByType = this.layoutsByType, alias, className, config, layoutClass, type, load; if (!layout || typeof layout === 'string') { type = layout || defaultType; config = {}; } else if (layout.isLayout) { return layout; } else { config = layout; type = layout.type || defaultType; } if (!(layoutClass = layoutsByType[type])) { alias = 'layout.' + type; className = ClassManager.getNameByAlias(alias); // this is needed to support demand loading of the class if (!className) { load = true; } layoutClass = ClassManager.get(className); if (load || !layoutClass) { return ClassManager.instantiateByAlias(alias, config || {}); } layoutsByType[type] = layoutClass; } return new layoutClass(config); } }, constructor : function(config) { var me = this; me.id = Ext.id(null, me.type + '-'); Ext.apply(me, config); me.layoutCount = 0; }, <span id='Ext-layout-Layout-property-done'> /** </span> * @property {Boolean} done Used only during a layout run, this value indicates that a * layout has finished its calculations. This flag is set to true prior to the call to * {@link #calculate} and should be set to false if this layout has more work to do. */ <span id='Ext-layout-Layout-method-beginLayout'> /** </span> * Called before any calculation cycles to prepare for layout. * * This is a write phase and DOM reads should be strictly avoided when overridding * this method. * * @param {Ext.layout.ContextItem} ownerContext The context item for the layout's owner * component. * @method beginLayout */ beginLayout: Ext.emptyFn, <span id='Ext-layout-Layout-method-beginLayoutCycle'> /** </span> * Called before any calculation cycles to reset DOM values and prepare for calculation. * * This is a write phase and DOM reads should be strictly avoided when overridding * this method. * * @param {Ext.layout.ContextItem} ownerContext The context item for the layout's owner * component. * @method beginLayoutCycle */ beginLayoutCycle: function (ownerContext) { var me = this, context = me.context, changed; if (me.lastWidthModel != ownerContext.widthModel) { if (me.lastWidthModel) { changed = true; } me.lastWidthModel = ownerContext.widthModel; } if (me.lastHeightModel != ownerContext.heightModel) { if (me.lastWidthModel) { changed = true; } me.lastHeightModel = ownerContext.heightModel; } if (changed) { (context = ownerContext.context).clearTriggers(me, false); context.clearTriggers(me, true); me.triggerCount = 0; } }, <span id='Ext-layout-Layout-method-calculate'> /** </span> * Called to perform the calculations for this layout. This method will be called at * least once and may be called repeatedly if the {@link #done} property is cleared * before return to indicate that this layout is not yet done. The {@link #done} property * is always set to `true` before entering this method. * * This is a read phase and DOM writes should be strictly avoided in derived classes. * Instead, DOM writes need to be written to {@link Ext.layout.ContextItem} objects to * be flushed at the next opportunity. * * @param {Ext.layout.ContextItem} ownerContext The context item for the layout's owner * component. * @method calculate * @abstract */ <span id='Ext-layout-Layout-method-completeLayout'> /** </span> * This method (if implemented) is called at the end of the cycle in which this layout * completes (by not setting {@link #done} to `false` in {@link #calculate}). It is * possible for the layout to complete and yet become invalid before the end of the cycle, * in which case, this method will not be called. It is also possible for this method to * be called and then later the layout becomes invalidated. This will result in * {@link #calculate} being called again, followed by another call to this method. * * This is a read phase and DOM writes should be strictly avoided in derived classes. * Instead, DOM writes need to be written to {@link Ext.layout.ContextItem} objects to * be flushed at the next opportunity. * * This method need not be implemented by derived classes and, in fact, should only be * implemented when needed. * * @param {Ext.layout.ContextItem} ownerContext The context item for the layout's owner * component. * @method completeLayout */ <span id='Ext-layout-Layout-method-finalizeLayout'> /** </span> * This method (if implemented) is called after all layouts have completed. In most * ways this is similar to {@link #completeLayout}. This call can cause this (or any * layout) to be become invalid (see {@link Ext.layout.Context#invalidate}), but this * is best avoided. This method is intended to be where final reads are made and so it * is best to avoid invalidating layouts at this point whenever possible. Even so, this * method can be used to perform final checks that may require all other layouts to be * complete and then invalidate some results. * * This is a read phase and DOM writes should be strictly avoided in derived classes. * Instead, DOM writes need to be written to {@link Ext.layout.ContextItem} objects to * be flushed at the next opportunity. * * This method need not be implemented by derived classes and, in fact, should only be * implemented when needed. * * @param {Ext.layout.ContextItem} ownerContext The context item for the layout's owner * component. * @method finalizeLayout */ <span id='Ext-layout-Layout-method-finishedLayout'> /** </span> * This method is called after all layouts are complete and their calculations flushed * to the DOM. No further layouts will be run and this method is only called once per * layout run. The base component layout caches `lastComponentSize`. * * This is a write phase and DOM reads should be avoided if possible when overridding * this method. * * This method need not be implemented by derived classes and, in fact, should only be * implemented when needed. * * @param {Ext.layout.ContextItem} ownerContext The context item for the layout's owner * component. */ finishedLayout: function () { this.ownerContext = null; }, <span id='Ext-layout-Layout-method-notifyOwner'> /** </span> * This method (if implemented) is called after all layouts are finished, and all have * a `lastComponentSize` cached. No further layouts will be run and this method is only * called once per layout run. It is the bookend to {@link #beginLayout}. * * This is a write phase and DOM reads should be avoided if possible when overridding * this method. This is the catch-all tail method to a layout and so the rules are more * relaxed. Even so, for performance reasons, it is best to avoid reading the DOM. If * a read is necessary, consider implementing a {@link #finalizeLayout} method to do the * required reads. * * This method need not be implemented by derived classes and, in fact, should only be * implemented when needed. * * @param {Ext.layout.ContextItem} ownerContext The context item for the layout's owner * component. * @method notifyOwner */ redoLayout: Ext.emptyFn, undoLayout: Ext.emptyFn, getAnimatePolicy: function() { return this.animatePolicy; }, <span id='Ext-layout-Layout-method-getItemSizePolicy'> /** </span> * Returns an object describing how this layout manages the size of the given component. * This method must be implemented by any layout that manages components. * * @param {Ext.Component} item * * @return {Object} An object describing the sizing done by the layout for this item or * null if the layout mimics the size policy of its ownerCt (e.g., 'fit' and 'card'). * @return {Boolean} return.readsWidth True if the natural/auto width of this component * is used by the ownerLayout. * @return {Boolean} return.readsHeight True if the natural/auto height of this component * is used by the ownerLayout. * @return {Boolean} return.setsWidth True if the ownerLayout set this component's width. * @return {Boolean} return.setsHeight True if the ownerLayout set this component's height. * * @protected */ getItemSizePolicy: function (item) { return this.autoSizePolicy; }, isItemBoxParent: function (itemContext) { return false; }, isItemLayoutRoot: function (item) { var sizeModel = item.getSizeModel(), width = sizeModel.width, height = sizeModel.height; // If this component has never had a layout and some of its dimensions are set by // its ownerLayout, we cannot be the layoutRoot... if (!item.componentLayout.lastComponentSize && (width.calculated || height.calculated)) { return false; } // otherwise an ownerCt whose size is not effected by its content is a root return !width.shrinkWrap && !height.shrinkWrap; }, isItemShrinkWrap: function (item) { return item.shrinkWrap; }, isRunning: function () { return !!this.ownerContext; }, //----------------------------------------------------- /* * Clears any styles which must be cleared before layout can take place. * Only DOM WRITES must be performed at this stage. * * An entry for the owner's element ID must be created in the layoutContext containing * a reference to the target which must be sized/positioned/styled by the layout at * the flush stage: * * { * target: me.owner * } * * Component layouts should iterate through managed Elements, * pushing an entry for each element: * * { * target: childElement * } */ //----------------------------------------------------- getItemsRenderTree: function (items, renderCfgs) { var length = items.length, i, item, itemConfig, result; if (length) { result = []; for (i = 0; i < length; ++i) { item = items[i]; // If we are being asked to move an already rendered Component, we must not recalculate its renderTree // and rerun its render process. The Layout's isValidParent check will ensure that the DOM is moved into place. if (!item.rendered) { // If we've already calculated the item's element config, don't calculate it again. // This may happen if the rendering process mutates the owning Container's items // collection, and Ext.layout.Container#getRenderTree runs through the collection again. // Note that the config may be null if a beforerender listener vetoed the operation, so // we must compare to undefined. if (renderCfgs && (renderCfgs[item.id] !== undefined)) { itemConfig = renderCfgs[item.id]; } else { // Perform layout preprocessing in the bulk render path this.configureItem(item); itemConfig = item.getRenderTree(); if (renderCfgs) { renderCfgs[item.id] = itemConfig; } } // itemConfig mey be null if a beforerender listener vetoed the operation. if (itemConfig) { result.push(itemConfig); } } } } return result; }, finishRender: Ext.emptyFn, finishRenderItems: function (target, items) { var length = items.length, i, item; for (i = 0; i < length; i++) { item = items[i]; // Only postprocess items which are being rendered. deferredRender may mean that only one has been rendered. if (item.rendering) { // Tell the item at which index in the Container it is item.finishRender(i); this.afterRenderItem(item); } } }, renderChildren: function () { var me = this, items = me.getLayoutItems(), target = me.getRenderTarget(); me.renderItems(items, target); }, <span id='Ext-layout-Layout-method-renderItems'> /** </span> * Iterates over all passed items, ensuring they are rendered. If the items are already rendered, * also determines if the items are in the proper place in the dom. * @protected */ renderItems : function(items, target) { var me = this, ln = items.length, i = 0, item; if (ln) { Ext.suspendLayouts(); for (; i < ln; i++) { item = items[i]; if (item && !item.rendered) { me.renderItem(item, target, i); } else if (!me.isValidParent(item, target, i)) { me.moveItem(item, target, i); } else { // still need to configure the item, it may have moved in the container. me.configureItem(item); } } Ext.resumeLayouts(true); } }, <span id='Ext-layout-Layout-method-isValidParent'> /** </span> * Validates item is in the proper place in the dom. * @protected */ isValidParent : function(item, target, position) { var itemDom = item.el ? item.el.dom : Ext.getDom(item), targetDom = (target && target.dom) || target; // If it's resizable+wrapped, the position element is the wrapper. if (itemDom.parentNode && itemDom.parentNode.className.indexOf(Ext.baseCSSPrefix + 'resizable-wrap') !== -1) { itemDom = itemDom.parentNode; } // Test DOM nodes for equality using "===" : http://jsperf.com/dom-equality-test if (itemDom && targetDom) { if (typeof position == 'number') { return itemDom === targetDom.childNodes[position]; } return itemDom.parentNode === targetDom; } return false; }, <span id='Ext-layout-Layout-method-configureItem'> /** </span> * Called before an item is rendered to allow the layout to configure the item. * @param {Ext.Component} item The item to be configured * @protected */ configureItem: function(item) { item.ownerLayout = this; }, <span id='Ext-layout-Layout-method-renderItem'> /** </span> * Renders the given Component into the target Element. * @param {Ext.Component} item The Component to render * @param {Ext.dom.Element} target The target Element * @param {Number} position The position within the target to render the item to * @private */ renderItem : function(item, target, position) { var me = this; if (!item.rendered) { me.configureItem(item); item.render(target, position); me.afterRenderItem(item); } }, <span id='Ext-layout-Layout-method-moveItem'> /** </span> * Moves Component to the provided target instead. * @private */ moveItem : function(item, target, position) { target = target.dom || target; if (typeof position == 'number') { position = target.childNodes[position]; } target.insertBefore(item.el.dom, position || null); item.container = Ext.get(target); this.configureItem(item); }, <span id='Ext-layout-Layout-method-onContentChange'> /** </span> * This method is called when a child item changes in some way. By default this calls * {@link Ext.AbstractComponent#updateLayout} on this layout's owner. * * @param {Ext.Component} child The child item that has changed. * @return {Boolean} True if this layout has handled the content change. */ onContentChange: function () { this.owner.updateLayout(); return true; }, <span id='Ext-layout-Layout-method-initLayout'> /** </span> * A one-time initialization method called just before rendering. * @protected */ initLayout : function() { this.initialized = true; }, // @private Sets the layout owner setOwner : function(owner) { this.owner = owner; }, <span id='Ext-layout-Layout-method-getLayoutItems'> /** </span> * Returns the set of items to layout (empty by default). * @protected */ getLayoutItems : function() { return []; }, // Placeholder empty functions for subclasses to extend afterRenderItem: Ext.emptyFn, onAdd : Ext.emptyFn, onRemove : Ext.emptyFn, onDestroy : Ext.emptyFn, <span id='Ext-layout-Layout-method-afterRemove'> /** </span> * Removes layout's itemCls and owning Container's itemCls. * Clears the managed dimensions flags * @protected */ afterRemove : function(item) { var me = this, el = item.el, owner = me.owner, removeClasses; if (item.rendered) { removeClasses = [].concat(me.itemCls || []); if (owner.itemCls) { removeClasses = Ext.Array.push(removeClasses, owner.itemCls); } if (removeClasses.length) { el.removeCls(removeClasses); } } delete item.ownerLayout; }, <span id='Ext-layout-Layout-method-destroy'> /** </span> * Destroys this layout. This method removes a `targetCls` from the `target` * element and calls `onDestroy`. * * A derived class can override either this method or `onDestroy` but in all * cases must call the base class versions of these methods to allow the base class to * perform its cleanup. * * This method (or `onDestroy`) are overridden by subclasses most often to purge * event handlers or remove unmanged DOM nodes. * * @protected */ destroy : function() { var me = this, target; if (me.targetCls) { target = me.getTarget(); if (target) { target.removeCls(me.targetCls); } } me.onDestroy(); }, sortWeightedItems: function (items, reverseProp) { for (var i = 0, length = items.length; i < length; ++i) { items[i].$i = i; } Ext.Array.sort(items, function (item1, item2) { var ret = item2.weight - item1.weight; if (!ret) { ret = item1.$i - item2.$i; if (item1[reverseProp]) { ret = -ret; } } return ret; }); for (i = 0; i < length; ++i) { delete items[i].$i; } } }, function () { var Layout = this, sizeModels = {}, sizeModelsArray = [], i, j, n, pairs, sizeModel; Layout.prototype.sizeModels = Layout.sizeModels = sizeModels; <span id='Ext-layout-SizeModel'> /** </span> * This class describes a size determination strategy or algorithm used by the layout * system. There are special instances of this class stored as static properties to * avoid needless object instantiation. These instances should be treated as readonly. * * * `calculated` * * `configured` * * `constrainedMax` * * `constrainedMin` * * `natural` * * `shrinkWrap` * * `calculatedFromConfigured` * * `calculatedFromNatural` * * `calculatedFromShrinkWrap` * * Using one of these instances is simply: * * var calculated = Ext.layout.SizeModel.calculated; * * @class Ext.layout.SizeModel * @protected */ var SizeModel = function (config) { var me = this, name = config.name; Ext.apply(Ext.apply(me, defaults), config); me[name] = true; // set the one special flag that matches our name SizeModel[name] = sizeModels[name] = me; me.fixed = !(me.auto = me.natural || me.shrinkWrap); <span id='Ext-layout-SizeModel-property-ordinal'> /** </span> * @prop {Number} ordinal * The 0-based ordinal for this `SizeModel` instance. * @readonly */ me.ordinal = sizeModelsArray.length; sizeModelsArray.push(me); }; Ext.layout.SizeModel = SizeModel; var defaults = { <span id='Ext-layout-SizeModel-property-name'> /** </span> * @property {String} name * The name of this size model (e.g., "calculated"). * @readonly */ <span id='Ext-layout-SizeModel-property-auto'> /** </span> * @property {Boolean} auto * True if the size is either `natural` or `shrinkWrap`, otherwise false. * @readonly */ <span id='Ext-layout-SizeModel-property-calculated'> /** </span> * @property {Boolean} calculated * True if the size is calculated by the `ownerLayout`. * @readonly */ calculated: false, <span id='Ext-layout-SizeModel-property-configured'> /** </span> * @property {Boolean} configured * True if the size is configured (e.g., by a `width` or `minWidth`). The names of * configuration properties can be found in the {@link #names} property. * @readonly */ configured: false, <span id='Ext-layout-SizeModel-property-constrainedMax'> /** </span> * @property {Boolean} constrainedMax * True if the size is constrained by a `maxWidth` or `maxHeight` configuration. This * is a flavor of `configured` (since `maxWidth` and `maxHeight` are config options). * If true, the {@link #names} property will be defined as well. * @readonly */ constrainedMax: false, <span id='Ext-layout-SizeModel-property-constrainedMin'> /** </span> * @property {Boolean} constrainedMin * True if the size is constrained by a `minWidth` or `minHeight` configuration. This * is a flavor of `configured` (since `minWidth` and `minHeight` are config options). * If true, the {@link #names} property will be defined as well. * @readonly */ constrainedMin: false, <span id='Ext-layout-SizeModel-property-fixed'> /** </span> * @property {Boolean} fixed * True if the size is either `calculated` or `configured`, otherwise false. * @readonly */ <span id='Ext-layout-SizeModel-property-natural'> /** </span> * @property {Boolean} natural * True if the size is determined by CSS and not by content. Such sizes are assumed to * be dependent on the container box and measurement occurs on the outer-most element. * @readonly */ natural: false, <span id='Ext-layout-SizeModel-property-shrinkWrap'> /** </span> * @property {Boolean} shrinkWrap * True if the size is determined by content irrespective of the container box. * @readonly */ shrinkWrap: false, <span id='Ext-layout-SizeModel-property-calculatedFromConfigured'> /** </span> * @property {Boolean} calculatedFromConfigured * True if the size is calculated by the `ownerLayout` based on a configured size. * @readonly */ calculatedFromConfigured: false, <span id='Ext-layout-SizeModel-property-calculatedFromNatural'> /** </span> * @property {Boolean} calculatedFromNatural * True if the size is calculated by the `ownerLayout` based on `natural` size model * results. * @readonly */ calculatedFromNatural: false, <span id='Ext-layout-SizeModel-property-calculatedFromShrinkWrap'> /** </span> * @property {Boolean} calculatedFromShrinkWrap * True if the size is calculated by the `ownerLayout` based on `shrinkWrap` size model * results. * @readonly */ calculatedFromShrinkWrap: false, <span id='Ext-layout-SizeModel-property-names'> /** </span> * @property {Object} names An object with the config property names that determine the * size. * @property {String} names.width The width property name (e.g., 'width'). * @property {String} names.height The height property name (e.g., 'minHeight'). * @readonly */ names: null }; //------------------------------------------------------------------------------- // These are the 4 fundamental size models. new SizeModel({ name: 'calculated' }); new SizeModel({ name: 'configured', names: { width: 'width', height: 'height' } }); new SizeModel({ name: 'natural' }); new SizeModel({ name: 'shrinkWrap' }); //------------------------------------------------------------------------------- // These are the size models are flavors of the above but with some extra detail // about their dynamic use. new SizeModel({ name: 'calculatedFromConfigured', configured: true, names: { width: 'width', height: 'height' } }); new SizeModel({ name: 'calculatedFromNatural', natural: true }); new SizeModel({ name: 'calculatedFromShrinkWrap', shrinkWrap: true }); new SizeModel({ name: 'constrainedMax', configured: true, constrained: true, names: { width: 'maxWidth', height: 'maxHeight' } }); new SizeModel({ name: 'constrainedMin', configured: true, constrained: true, names: { width: 'minWidth', height: 'minHeight' } }); for (i = 0, n = sizeModelsArray.length; i < n; ++i) { sizeModel = sizeModelsArray[i]; <span id='Ext-layout-SizeModel-property-pairsByHeightOrdinal'> /** </span> * An array of objects indexed by the {@link #ordinal} of a height `SizeModel` on * a width `SizeModel` to yield an object describing both height and width size * models. * * Used like this: * * widthModel.pairsByHeightOrdinal[heightModel.ordinal] * * This provides a reusable object equivalent to the following: * * { * width: widthModel, * height: heightModel * } * * @property {Object[]} pairsByHeightOrdinal * @property {Ext.layout.SizeModel} pairsByHeightOrdinal.width The `SizeModel` for * the width. * @property {Ext.layout.SizeModel} pairsByHeightOrdinal.height The `SizeModel` for * the height. */ sizeModel.pairsByHeightOrdinal = pairs = []; for (j = 0; j < n; ++j) { pairs.push({ width: sizeModel, height: sizeModelsArray[j] }); } } }); </pre> </body> </html>