Форк Rambox
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

767 lines
30 KiB

/**
* @class Ext.layout.container.Auto
*
* The AutoLayout is the default layout manager delegated by {@link Ext.container.Container} to
* render any child Components when no `{@link Ext.container.Container#layout layout}` is configured into
* a `{@link Ext.container.Container Container}.` AutoLayout provides only a passthrough of any layout calls
* to any child containers.
*
* @example
* Ext.create('Ext.Panel', {
* width: 500,
* height: 280,
* title: 'AutoLayout Panel',
* layout: 'auto',
* renderTo: document.body,
* items: [{
* xtype: 'panel',
* title: 'Top Inner Panel',
* width: '75%',
* height: 90
* }, {
* xtype: 'panel',
* title: 'Bottom Inner Panel',
* width: '75%',
* height: 90
* }]
* });
*/
Ext.define('Ext.layout.container.Auto', {
/* Begin Definitions */
alias: ['layout.auto', 'layout.autocontainer'],
extend: 'Ext.layout.container.Container',
/* End Definitions */
type: 'autocontainer',
childEls: [
'outerCt',
'innerCt'
],
/**
* @cfg {Boolean} [reserveScrollbar=false]
* Set to `true` to leave space for a vertical scrollbar (if the OS shows space-consuming scrollbars) regardless
* of whether a scrollbar is needed.
*
* This is useful if content height changes during application usage, but you do not want the calculated width
* of child items to change when a scrollbar appears or disappears. The scrollbar will appear in the reserved space,
* and the calculated width of child Components will not change.
*
* @example
* Ext.define('Employee', {
* extend: 'Ext.data.Model',
* fields: [
* {name: 'rating', type: 'int'},
* {name: 'salary', type: 'float'},
* {name: 'name'}
* ]
* });
*
* function createFakeData(count) {
* var firstNames = ['Ed', 'Tommy', 'Aaron', 'Abe', 'Jamie', 'Adam', 'Dave', 'David', 'Jay', 'Nicolas', 'Nige'],
* lastNames = ['Spencer', 'Maintz', 'Conran', 'Elias', 'Avins', 'Mishcon', 'Kaneda', 'Davis', 'Robinson', 'Ferrero', 'White'],
* ratings = [1, 2, 3, 4, 5],
* salaries = [100, 400, 900, 1500, 1000000];
*
* var data = [];
* for (var i = 0; i < (count || 25); i++) {
* var ratingId = Math.floor(Math.random() * ratings.length),
* salaryId = Math.floor(Math.random() * salaries.length),
* firstNameId = Math.floor(Math.random() * firstNames.length),
* lastNameId = Math.floor(Math.random() * lastNames.length),
*
* rating = ratings[ratingId],
* salary = salaries[salaryId],
* name = Ext.String.format("{0} {1}", firstNames[firstNameId], lastNames[lastNameId]);
*
* data.push({
* rating: rating,
* salary: salary,
* name: name
* });
* }
* store.loadData(data);
* }
*
* // create the Data Store
* var store = Ext.create('Ext.data.Store', {
* id: 'store',
* model: 'Employee',
* proxy: {
* type: 'memory'
* }
* });
* createFakeData(10);
*
* var grid = Ext.create('Ext.grid.Panel', {
* title: 'Grid loaded with varying number of records',
* anchor: '100%',
* store: store,
* columns: [{
* xtype: 'rownumberer',
* width: 40,
* sortable: false
* },{
* text: 'Name',
* flex: 1,
* sortable: true,
* dataIndex: 'name'
* },{
* text: 'Rating',
* width: 125,
* sortable: true,
* dataIndex: 'rating'
* },{
* text: 'Salary',
* width: 125,
* sortable: true,
* dataIndex: 'salary',
* align: 'right',
* renderer: Ext.util.Format.usMoney
* }]
* });
*
* Ext.create('Ext.panel.Panel', {
* renderTo: document.body,
* width: 800,
* height: 600,
* layout: {
* type: 'anchor',
* reserveScrollbar: true // There will be a gap even when there's no scrollbar
* },
* scrollable: true,
* items: grid,
* tbar: {
* defaults: {
* handler: function(b) {
* createFakeData(b.count);
* }
* },
* items: [{
* text: '10 Items',
* count: 10
* },{
* text: '100 Items',
* count: 100
* },{
* text: '300 Items',
* count: 300
* },{
* text: '1000 Items',
* count: 1000
* },{
* text: '5000 Items',
* count: 5000
* }]
* }
* });
*
*/
reserveScrollbar: false,
/**
* @property {Boolean} [managePadding=true]
* indicates that this layout will correct cross browser padding differences when the
* container has overflow.
*
* In some browsers the right and/or bottom padding of a container is lost when
* the container has overflow. If managePadding is true the layout will apply the
* padding to an inner wrapping element instead of the container element that has the
* overflow so that paddding will be included in the scrollable area.
* Note: padding will not be managed if it is configured on the container using
* a style config or css class. In order to be managed, padding must be added to the
* container using the appropriate {@link Ext.Component#contentPaddingProperty
* contentPaddingProperty}. For {@link Ext.panel.Panel Panels} use
* {@link Ext.panel.Panel#bodyPadding}, and for
* {@link Ext.container.Container Containers}, use
* {@link Ext.Component#padding padding}
*/
managePadding: true,
/**
* @property {Boolean} [manageOverflow=false]
* true to rerun the layout if scrollbars are needed.
*/
manageOverflow: false,
// auto layout does not care about the dimensions of individual child items since
// it does not size them, and it measures them as a whole when in shrinkWrap mode.
needsItemSize: false,
setsItemSize: false,
// Begin with no previous adjustments
lastOverflowAdjust: {
width: 0,
height: 0
},
outerCtCls: Ext.baseCSSPrefix + 'autocontainer-outerCt',
innerCtCls: Ext.baseCSSPrefix + 'autocontainer-innerCt',
// Auto layout's renderTpl wraps the content in an outerCt which is used to accomplish
// the following 3 goals:
//
// 1. When the container has a shrink wrapped width and/or height, the outerCt is used
// to measure the size of the content.
// 2. When the container has overflow some browsers lose the container's right and/or
// bottom padding. To fix this, the padding is rendered to the outerCt instead of
// the container target element. This ensures that the padding is included in the
// container's scrollWidth/scrollHeight. In Old IE when a table is used, the padding
// is rendered to the innerCt td element.
// 3. The outerCt contains the margins of its children, that is to say, it prevents
// them from collapsing.
renderTpl: [
// An outerCt with display:table shrink-wraps contents, and contains child
// margins. The table-cell innerCt is required in order to support percentage
// heights on child elements.
'<div id="{ownerId}-outerCt" data-ref="outerCt" class="{outerCtCls}" role="presentation">',
'<div id="{ownerId}-innerCt" data-ref="innerCt" style="{%this.renderPadding(out, values)%}" ',
'class="{innerCtCls}" role="presentation">',
'{%this.renderBody(out,values)%}',
'</div>',
'</div>'
],
beginLayout: function(ownerContext) {
this.callParent(arguments);
this.initContextItems(ownerContext);
},
beforeLayoutCycle: function(ownerContext){
var comp = this.owner,
inheritedState = comp.inheritedState,
inheritedStateInner = comp.inheritedStateInner;
if (!inheritedState || inheritedState.invalid) {
inheritedState = comp.getInherited(); // fixes both
inheritedStateInner = comp.inheritedStateInner;
}
if (ownerContext.widthModel.shrinkWrap) {
inheritedStateInner.inShrinkWrapTable = true;
} else {
delete inheritedStateInner.inShrinkWrapTable;
}
},
beginLayoutCycle: function(ownerContext) {
var me = this,
outerCt = me.outerCt,
lastOuterCtWidth = me.lastOuterCtWidth || '',
lastOuterCtHeight = me.lastOuterCtHeight || '',
lastOuterCtTableLayout = me.lastOuterCtTableLayout || '',
state = ownerContext.state,
overflowXStyle, outerCtWidth, outerCtHeight, outerCtTableLayout,
inheritedStateInner;
me.callParent(arguments);
// Default to "shrink wrap styles".
outerCtWidth = outerCtHeight = outerCtTableLayout = '';
if (!ownerContext.widthModel.shrinkWrap) {
// if we're not shrink wrapping width, we need to get the innerCt out of the
// way to avoid any shrink wrapping effect on child items
// fill the available width within the container
outerCtWidth = '100%';
inheritedStateInner = me.owner.inheritedStateInner;
// expand no further than the available width, even if contents are wider
// unless there is a potential for horizontal overflow, then allow
// the outerCt to expand to the width of the contents
overflowXStyle = me.getOverflowXStyle(ownerContext);
outerCtTableLayout = (inheritedStateInner.inShrinkWrapTable ||
overflowXStyle === 'auto' ||
overflowXStyle === 'scroll') ? '' : 'fixed';
}
if (!ownerContext.heightModel.shrinkWrap &&
!Ext.supports.PercentageHeightOverflowBug) {
// if we're not shrink wrapping height, we need to get the outerCt out of the
// way so that percentage height children will be sized correctly. We do this
// by giving the outerCt a height of '100%' unless the browser is affected by
// the "percentage height overflow bug", in which case the outerCt will get a
// pixel height set during the calculate phase after we know the targetEl size.
outerCtHeight = '100%';
}
// if the outerCt width changed since last time (becuase of a widthModel change)
// or if we set a pixel width on the outerCt last time to work around a browser-
// specific bug, we need to set the width of the outerCt
if ((outerCtWidth !== lastOuterCtWidth) || me.hasOuterCtPxWidth) {
outerCt.setStyle('width', outerCtWidth);
me.lastOuterCtWidth = outerCtWidth;
me.hasOuterCtPxWidth = false;
}
// Set the outerCt table-layout property if different from last time.
if (outerCtTableLayout !== lastOuterCtTableLayout) {
outerCt.setStyle('table-layout', outerCtTableLayout);
me.lastOuterCtTableLayout = outerCtTableLayout;
}
// if the outerCt height changed since last time (becuase of a heightModel change)
// or if we set a pixel height on the outerCt last time to work around a browser-
// specific bug, we need to set the height of the outerCt
if ((outerCtHeight !== lastOuterCtHeight) || me.hasOuterCtPxHeight) {
outerCt.setStyle('height', outerCtHeight);
me.lastOuterCtHeight = outerCtHeight;
me.hasOuterCtPxHeight = false;
}
if (me.hasInnerCtPxHeight) {
me.innerCt.setStyle('height', '');
me.hasInnerCtPxHeight = false;
}
// Begin with the scrollbar adjustment that we used last time - this is more likely
// to be correct than beginning with no adjustment at all, but only if it is not
// already defined - it may have already been set by invalidate()
state.overflowAdjust = state.overflowAdjust || me.lastOverflowAdjust;
},
calculate: function(ownerContext) {
var me = this,
state = ownerContext.state,
containerSize = me.getContainerSize(ownerContext, true),
// If subclass has a calculateItems method, call it and cache the result
calculatedItems = state.calculatedItems ||
(state.calculatedItems = me.calculateItems ?
me.calculateItems(ownerContext, containerSize) : true);
me.setCtSizeIfNeeded(ownerContext, containerSize);
if (calculatedItems && ownerContext.hasDomProp('containerChildrenSizeDone')) {
me.calculateContentSize(ownerContext);
if (containerSize.gotAll) {
if (me.manageOverflow && !ownerContext.state.secondPass && !me.reserveScrollbar) {
me.calculateOverflow(ownerContext, containerSize);
}
return;
}
}
me.done = false;
},
calculateContentSize: function (ownerContext) {
var me = this,
containerDimensions = ((ownerContext.widthModel.shrinkWrap ? 1 : 0) | // jshint ignore:line
(ownerContext.heightModel.shrinkWrap ? 2 : 0)),
calcWidth = (containerDimensions & 1) || undefined, // jshint ignore:line
calcHeight = (containerDimensions & 2) || undefined, // jshint ignore:line
needed = 0,
props = ownerContext.props;
if (calcWidth) {
if (isNaN(props.contentWidth)) {
++needed;
} else {
calcWidth = undefined;
}
}
if (calcHeight) {
if (isNaN(props.contentHeight)) {
++needed;
} else {
calcHeight = undefined;
}
}
if (needed) {
if (calcWidth && !ownerContext.setContentWidth(me.measureContentWidth(ownerContext))) {
me.done = false;
}
if (calcHeight && !ownerContext.setContentHeight(me.measureContentHeight(ownerContext))) {
me.done = false;
}
//if (me.done) {
// var el = ownerContext.targetContext.el.dom;
// Ext.log(this.owner.id, '.contentSize: ', contentWidth, 'x', contentHeight,
// ' => scrollSize: ', el.scrollWidth, 'x', el.scrollHeight);
//}
}
},
/**
* Handles overflow processing for a container. In addition to the ownerContext
* passed to the {@link #calculate} method, this method also needs the containerSize
* (the object returned by {@link #getContainerSize}).
* @protected
*
* @param {Ext.layout.ContextItem} ownerContext
*/
calculateOverflow: function (ownerContext) {
var me = this,
width, height, scrollbarSize, scrollbars, xauto, yauto, targetEl;
// Determine the dimensions that have overflow:auto applied. If these come by
// way of component config, this does not require a DOM read:
xauto = (me.getOverflowXStyle(ownerContext) === 'auto');
yauto = (me.getOverflowYStyle(ownerContext) === 'auto');
if (xauto || yauto) {
scrollbarSize = Ext.getScrollbarSize();
targetEl = ownerContext.overflowContext.el.dom;
scrollbars = 0;
if (targetEl.scrollWidth > targetEl.clientWidth) {
// has horizontal scrollbar
scrollbars |= 1; // jshint ignore:line
}
if (targetEl.scrollHeight > targetEl.clientHeight) {
// has vertical scrollbar
scrollbars |= 2; // jshint ignore:line
}
width = (yauto && (scrollbars & 2)) ? scrollbarSize.width : 0; // jshint ignore:line
height = (xauto && (scrollbars & 1)) ? scrollbarSize.height : 0; // jshint ignore:line
if (width !== me.lastOverflowAdjust.width || height !== me.lastOverflowAdjust.height) {
me.done = false;
// we pass overflowAdjust and overflowState in as state for the next
// cycle (these are discarded if one of our ownerCt's invalidates):
ownerContext.invalidate({
state: {
overflowAdjust: {
width: width,
height: height
},
overflowState: scrollbars,
secondPass: true
}
});
}
}
},
completeLayout: function(ownerContext) {
this.lastOverflowAdjust = ownerContext.state.overflowAdjust;
},
doRenderBody: function (out, renderData) {
// Careful! This method is bolted on to the renderTpl so all we get for context is
// the renderData! The "this" pointer is the renderTpl instance!
var me = renderData.$layout,
XTemplate = Ext.XTemplate,
beforeBodyTpl = me.beforeBodyTpl,
afterBodyTpl = me.afterBodyTpl;
if (beforeBodyTpl) {
XTemplate.getTpl(me, 'beforeBodyTpl').applyOut(renderData, out);
}
this.renderItems(out, renderData);
this.renderContent(out, renderData);
if (afterBodyTpl) {
XTemplate.getTpl(me, 'afterBodyTpl').applyOut(renderData, out);
}
},
doRenderPadding: function(out, renderData) {
// Careful! This method is bolted on to the renderTpl so all we get for context is
// the renderData! The "this" pointer is the renderTpl instance!
var me = renderData.$layout,
owner = renderData.$layout.owner,
padding = owner[owner.contentPaddingProperty];
if (me.managePadding && padding) {
out.push('padding:', owner.unitizeBox(padding));
}
},
finishedLayout: function (ownerContext) {
var innerCt = this.innerCt;
this.callParent(arguments);
if (Ext.isIE8) {
// IE8 needs a repaint to render percentage sized child items.
innerCt.repaint();
}
if (Ext.isOpera) {
// Opera also needs a repaint to render percentage sized child items. but
// the normal repaint() method doesn't seem to do the trick, but tweaking
// the position property in combination with reading scrollWidth does.
innerCt.setStyle('position', 'relative');
innerCt.dom.scrollWidth; // jshint ignore:line
innerCt.setStyle('position', '');
}
},
/**
* Returns the container size (that of the target). Only the fixed-sized dimensions can
* be returned because the shrinkWrap dimensions are based on the contentWidth/Height
* as determined by the container layout.
*
* If the {@link #calculateOverflow} method is used and if {@link #manageOverflow} is
* true, this will adjust the width/height by the size of scrollbars.
*
* @param {Ext.layout.ContextItem} ownerContext The owner's context item.
* @param {Boolean} [inDom=false] True if the container size must be in the DOM.
* @return {Object} The size
* @return {Number} return.width The width
* @return {Number} return.height The height
* @protected
*/
getContainerSize : function(ownerContext, inDom) {
// Subtle But Important:
//
// We don't want to call getProp/hasProp et.al. unless we in fact need that value
// for our results! If we call it and don't need it, the layout manager will think
// we depend on it and will schedule us again should it change.
var size = this.callParent(arguments),
overflowAdjust = ownerContext.state.overflowAdjust;
if (overflowAdjust) {
size.width -= overflowAdjust.width;
size.height -= overflowAdjust.height;
}
return size;
},
getRenderData: function () {
var me = this,
data = me.callParent();
data.innerCtCls = me.innerCtCls;
data.outerCtCls = me.outerCtCls;
return data;
},
// Overridden method from Ext.layout.container.Container.
// Used in the beforeLayout method to render all items into.
getRenderTarget: function() {
return this.innerCt;
},
// Overridden method from Ext.layout.container.Container.
// Used by Container classes to insert special DOM elements which must exist in addition to the child components
getElementTarget: function() {
return this.innerCt;
},
/**
* Returns the overflow-x style of the render target.
* Note: If overflow is configured on a container using style or css class this method
* will read the dom the first time it is called. It is therefore preferable for
* performance reasons to use the {@link Ext.Component#scrollable scrollable config when
* horizontal overflow is desired.
* @protected
* @param {Ext.layout.ContextItem} ownerContext
* @return {String}
*/
getOverflowXStyle: function(ownerContext) {
return ownerContext.overflowXStyle ||
(ownerContext.overflowXStyle = this.owner.scrollFlags.overflowX || ownerContext.overflowContext.getStyle('overflow-x'));
},
/**
* Returns the overflow-y style of the render target.
* Note: If overflow is configured on a container using style or css class this method
* will read the dom the first time it is called. It is therefore preferable for
* performance reasons to use the {@link Ext.Component#scrollable scrollable config when
* vertical overflow is desired.
* @protected
* @param {Ext.layout.ContextItem} ownerContext
* @return {String}
*/
getOverflowYStyle: function(ownerContext) {
return ownerContext.overflowYStyle ||
(ownerContext.overflowYStyle = this.owner.scrollFlags.overflowY || ownerContext.overflowContext.getStyle('overflow-y'));
},
initContextItems: function(ownerContext) {
var me = this,
target = ownerContext.target,
overflowEl = me.owner.getOverflowEl();
ownerContext.outerCtContext = ownerContext.getEl('outerCt', me);
ownerContext.innerCtContext = ownerContext.getEl('innerCt', me);
ownerContext.overflowContext = (overflowEl === ownerContext.el) ? ownerContext :
ownerContext.getEl(overflowEl);
if (target[target.contentPaddingProperty] !== undefined) {
// If padding was defined using the contentPaddingProperty, we render the
// the padding to the innerCt or outerCt (depending on the template that is
// being used), so we need to set the paddingContext accordingly.
// Otherwise we leave paddingContext as set by Container layout (defaults to
// the targetContext)
ownerContext.paddingContext = ownerContext.innerCtContext;
}
},
initLayout: function() {
var me = this,
scrollbarWidth = Ext.getScrollbarSize().width,
owner = me.owner;
me.callParent();
// Create a default lastOverflowAdjust based upon scrolling configuration.
// If the Container is to overflow, or we *always* reserve space for a scrollbar
// then reserve space for a vertical scrollbar
if (scrollbarWidth && me.manageOverflow && !me.hasOwnProperty('lastOverflowAdjust')) {
if (owner.scrollable || me.reserveScrollbar) {
me.lastOverflowAdjust = {
width: scrollbarWidth,
height: 0
};
}
}
},
measureContentHeight: function (ownerContext) {
// contentHeight includes padding, but not border, framing or margins
var contentHeight = this.outerCt.getHeight(),
target = ownerContext.target;
if (this.managePadding && (target[target.contentPaddingProperty] === undefined)) {
// if padding was not configured using the appropriate contentPaddingProperty
// then the padding will not be on the paddingContext, and therfore not included
// in the outerCt measurement, so we need to read the padding from the
// targetContext
contentHeight += ownerContext.targetContext.getPaddingInfo().height;
}
return contentHeight;
},
measureContentWidth: function (ownerContext) {
var dom, style, old, contentWidth, target;
// In the newer Chrome versions, it won't measure the
// width correctly without repainting the inner
// cell in some circumstances.
if (this.chromeCellMeasureBug) {
dom = this.innerCt.dom;
style = dom.style;
old = style.display;
if (old === 'table-cell') {
style.display = '';
dom.offsetWidth; // jshint ignore:line
style.display = old;
}
}
if (Ext.isSafari) {
// EXTJS-12041: Safari needs a reflow of the outerCt to measure content width
// correctly in some cases. The circumstances which make this happen are
// very difficult to isolate, so we have to resort to always triggering a
// reflow before measuring. We switch between table-cell and table in hopes
// of minimizing the impact of the reflow on surrounding elements
dom = this.outerCt.dom;
style = dom.style;
style.display = 'table-cell';
dom.offsetWidth; // jshint ignore:line
dom.style.display = '';
}
// contentWidth includes padding, but not border, framing or margins
contentWidth = this.outerCt.getWidth();
target = ownerContext.target;
if (this.managePadding && (target[target.contentPaddingProperty] === undefined)) {
// if padding was not configured using the appropriate contentPaddingProperty
// then the padding will not be on the paddingContext, and therfore not included
// in the outerCt measurement, so we need to read the padding from the
// targetContext
contentWidth += ownerContext.targetContext.getPaddingInfo().width;
}
return contentWidth;
},
/**
* This method sets the height and/or width of the outerCt/innerCt to adjust for the
* following browser-specific issues:
*
* 1. In some browsers a percentage-height element ignores the horizontal scrollbar
* of its parent (see Ext.supports.PercentageHeightOverflowBug). If the browser is
* affected by this bug the outerCt needs a pixel height in order to support
* percentage-height children when not shrink-wrapping height. If the browser is not
* affected by this bug, a height of 100% is assigned to the outerCt (see
* beginLayoutCycle).
*
* 2. IE8 mode has a bug with percentage height children. if the innerCt has
* a height of 100%, has padding, and has a child item with a percentage height, that
* child item will be sized as a percentage of the parent's height plus padding height.
* In other words, a child with height:50% would have its height caclulated thusly:
* (parentHeight + parentPaddingHeight) * 0.5
* To fix this, we have to give the innerCt a pixel height.
*
* @protected
* @param {Ext.layout.ContextItem} ownerContext
* @param {Object} containerSize
*/
setCtSizeIfNeeded: function(ownerContext, containerSize) {
var me = this,
height = containerSize.height,
padding = ownerContext.paddingContext.getPaddingInfo(),
targetEl = me.getTarget(),
overflowXStyle = me.getOverflowXStyle(ownerContext),
canOverflowX = (overflowXStyle === 'auto' || overflowXStyle === 'scroll'),
scrollbarSize = Ext.getScrollbarSize(),
needsOuterHeight, needsInnerHeight;
if (height && !ownerContext.heightModel.shrinkWrap) {
if (Ext.supports.PercentageHeightOverflowBug) {
// set a pixel height on the outerCt if the browser ignores horizontal
// scrollbar when rendering percentage-height elements
needsOuterHeight = true;
}
if (Ext.isIE8) {
// When not shrink wrapping, we set a pixel height on the innerCt to
// support percentage height children in IE8.
needsInnerHeight = true;
}
if ((needsOuterHeight || needsInnerHeight) && canOverflowX &&
(targetEl.dom.scrollWidth > targetEl.dom.clientWidth)) {
// adjust the height for scrollbar size since it's not accounted for
// in the containerSize.
// IE8 does not tolerate negative sizes
height = Math.max(height - scrollbarSize.height, 0);
}
if (needsOuterHeight) {
ownerContext.outerCtContext.setProp('height', height + padding.height);
me.hasOuterCtPxHeight = true;
}
if (needsInnerHeight) {
ownerContext.innerCtContext.setProp('height', height);
me.hasInnerCtPxHeight = true;
}
}
},
setupRenderTpl: function (renderTpl) {
this.callParent(arguments);
renderTpl.renderPadding = this.doRenderPadding;
},
getContentTarget: function(){
return this.innerCt;
},
getScrollerEl: function() {
return this.outerCt;
}
}, function(){
this.prototype.chromeCellMeasureBug = Ext.isChrome && Ext.chromeVersion >= 26;
});