Box.html 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-layout-container-Box'>/**
  19. </span> * Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.
  20. */
  21. Ext.define('Ext.layout.container.Box', {
  22. /* Begin Definitions */
  23. alias: ['layout.box'],
  24. extend: 'Ext.layout.container.Container',
  25. alternateClassName: 'Ext.layout.BoxLayout',
  26. requires: [
  27. 'Ext.layout.container.boxOverflow.None',
  28. 'Ext.layout.container.boxOverflow.Menu',
  29. 'Ext.layout.container.boxOverflow.Scroller',
  30. 'Ext.util.Format',
  31. 'Ext.dd.DragDropManager'
  32. ],
  33. /* End Definitions */
  34. <span id='Ext-layout-container-Box-cfg-defaultMargins'> /**
  35. </span> * @cfg {Object} defaultMargins
  36. * If the individual contained items do not have a margins property specified or margin specified via CSS, the
  37. * default margins from this property will be applied to each item.
  38. *
  39. * This property may be specified as an object containing margins to apply in the format:
  40. *
  41. * {
  42. * top: (top margin),
  43. * right: (right margin),
  44. * bottom: (bottom margin),
  45. * left: (left margin)
  46. * }
  47. *
  48. * This property may also be specified as a string containing space-separated, numeric margin values. The order of
  49. * the sides associated with each value matches the way CSS processes margin values:
  50. *
  51. * - If there is only one value, it applies to all sides.
  52. * - If there are two values, the top and bottom borders are set to the first value and the right and left are
  53. * set to the second.
  54. * - If there are three values, the top is set to the first value, the left and right are set to the second,
  55. * and the bottom is set to the third.
  56. * - If there are four values, they apply to the top, right, bottom, and left, respectively.
  57. */
  58. defaultMargins: {
  59. top: 0,
  60. right: 0,
  61. bottom: 0,
  62. left: 0
  63. },
  64. <span id='Ext-layout-container-Box-cfg-padding'> /**
  65. </span> * @cfg {String} padding
  66. * Sets the padding to be applied to all child items managed by this layout.
  67. *
  68. * This property must be specified as a string containing space-separated, numeric padding values. The order of the
  69. * sides associated with each value matches the way CSS processes padding values:
  70. *
  71. * - If there is only one value, it applies to all sides.
  72. * - If there are two values, the top and bottom borders are set to the first value and the right and left are
  73. * set to the second.
  74. * - If there are three values, the top is set to the first value, the left and right are set to the second,
  75. * and the bottom is set to the third.
  76. * - If there are four values, they apply to the top, right, bottom, and left, respectively.
  77. */
  78. padding: 0,
  79. <span id='Ext-layout-container-Box-cfg-pack'> /**
  80. </span> * @cfg {String} pack
  81. * Controls how the child items of the container are packed together. Acceptable configuration values for this
  82. * property are:
  83. *
  84. * - **start** - child items are packed together at **left** (HBox) or **top** (VBox) side of container (*default**)
  85. * - **center** - child items are packed together at **mid-width** (HBox) or **mid-height** (VBox) of container
  86. * - **end** - child items are packed together at **right** (HBox) or **bottom** (VBox) side of container
  87. */
  88. pack: 'start',
  89. <span id='Ext-layout-container-Box-cfg-flex'> /**
  90. </span> * @cfg {Number} flex
  91. * This configuration option is to be applied to **child items** of the container managed by this layout. Each child
  92. * item with a flex property will be flexed (horizontally in `hbox`, vertically in `vbox`) according to each item's
  93. * **relative** flex value compared to the sum of all items with a flex value specified. Any child items that have
  94. * either a `flex = 0` or `flex = undefined` will not be 'flexed' (the initial size will not be changed).
  95. */
  96. flex: undefined,
  97. <span id='Ext-layout-container-Box-cfg-stretchMaxPartner'> /**
  98. </span> * @cfg {String/Ext.Component} stretchMaxPartner
  99. * Allows stretchMax calculation to take into account the max perpendicular size (height for HBox layout and width
  100. * for VBox layout) of another Box layout when calculating its maximum perpendicular child size.
  101. *
  102. * If specified as a string, this may be either a known Container ID, or a ComponentQuery selector which is rooted
  103. * at this layout's Container (ie, to find a sibling, use `&quot;^&gt;#siblingItemId`).
  104. */
  105. stretchMaxPartner: undefined,
  106. type: 'box',
  107. scrollOffset: 0,
  108. itemCls: Ext.baseCSSPrefix + 'box-item',
  109. targetCls: Ext.baseCSSPrefix + 'box-layout-ct',
  110. innerCls: Ext.baseCSSPrefix + 'box-inner',
  111. // availableSpaceOffset is used to adjust the availableWidth, typically used
  112. // to reserve space for a scrollbar
  113. availableSpaceOffset: 0,
  114. // whether or not to reserve the availableSpaceOffset in layout calculations
  115. reserveOffset: true,
  116. manageMargins: true,
  117. childEls: [
  118. 'innerCt',
  119. 'targetEl'
  120. ],
  121. renderTpl: [
  122. '{%var oc,l=values.$comp.layout,oh=l.overflowHandler;',
  123. 'if (oh.getPrefixConfig!==Ext.emptyFn) {',
  124. 'if(oc=oh.getPrefixConfig())dh.generateMarkup(oc, out)',
  125. '}%}',
  126. '&lt;div id=&quot;{ownerId}-innerCt&quot; class=&quot;{[l.innerCls]} {[oh.getOverflowCls()]}&quot; role=&quot;presentation&quot;&gt;',
  127. '&lt;div id=&quot;{ownerId}-targetEl&quot; style=&quot;position:absolute;',
  128. // This width for the &quot;CSS container box&quot; of the box child items gives
  129. // them the room they need to avoid being &quot;crushed&quot; (aka, &quot;wrapped&quot;).
  130. // On Opera, elements cannot be wider than 32767px or else they break
  131. // the scrollWidth (it becomes == offsetWidth) and you cannot scroll
  132. // the content.
  133. 'width:20000px;',
  134. // On IE quirks and IE6/7 strict, a text-align:center style trickles
  135. // down to this el at times and will cause it to move off the left edge.
  136. // The easy fix is to just always set left:0px here. The top:0px part
  137. // is just being paranoid. The requirement for targetEl is that its
  138. // origin align with innerCt... this ensures that it does!
  139. 'left:0px;top:0px;',
  140. // If we don't give the element a height, it does not always participate
  141. // in the scrollWidth.
  142. 'height:1px&quot;&gt;',
  143. '{%this.renderBody(out, values)%}',
  144. '&lt;/div&gt;',
  145. '&lt;/div&gt;',
  146. '{%if (oh.getSuffixConfig!==Ext.emptyFn) {',
  147. 'if(oc=oh.getSuffixConfig())dh.generateMarkup(oc, out)',
  148. '}%}',
  149. {
  150. disableFormats: true,
  151. definitions: 'var dh=Ext.DomHelper;'
  152. }
  153. ],
  154. constructor: function(config) {
  155. var me = this,
  156. type;
  157. me.callParent(arguments);
  158. // The sort function needs access to properties in this, so must be bound.
  159. me.flexSortFn = Ext.Function.bind(me.flexSort, me);
  160. me.initOverflowHandler();
  161. type = typeof me.padding;
  162. if (type == 'string' || type == 'number') {
  163. me.padding = Ext.util.Format.parseBox(me.padding);
  164. me.padding.height = me.padding.top + me.padding.bottom;
  165. me.padding.width = me.padding.left + me.padding.right;
  166. }
  167. },
  168. getNames: function () {
  169. return this.names;
  170. },
  171. // Matches: &lt;spaces&gt;digits[.digits]&lt;spaces&gt;%&lt;spaces&gt;
  172. // Captures: digits[.digits]
  173. _percentageRe: /^\s*(\d+(?:\.\d*)?)\s*[%]\s*$/,
  174. getItemSizePolicy: function (item, ownerSizeModel) {
  175. var me = this,
  176. policy = me.sizePolicy,
  177. align = me.align,
  178. flex = item.flex,
  179. key = align,
  180. names = me.names,
  181. width = item[names.width],
  182. height = item[names.height],
  183. percentageRe = me._percentageRe,
  184. percentageWidth = percentageRe.test(width),
  185. isStretch = (align == 'stretch');
  186. if ((isStretch || flex || percentageWidth) &amp;&amp; !ownerSizeModel) {
  187. ownerSizeModel = me.owner.getSizeModel();
  188. }
  189. if (isStretch) {
  190. // If we are height.shrinkWrap, we behave as if we were stretchmax (for more
  191. // details, see beginLayoutCycle)...
  192. if (!percentageRe.test(height) &amp;&amp; ownerSizeModel[names.height].shrinkWrap) {
  193. key = 'stretchmax';
  194. // We leave %age height as stretch since it will not participate in the
  195. // stretchmax size calculation. This avoid running such a child in its
  196. // shrinkWrap mode prior to supplying the calculated size.
  197. }
  198. } else if (align != 'stretchmax') {
  199. if (percentageRe.test(height)) {
  200. // Height %ages are calculated based on container size, so they are the
  201. // same as align=stretch for this purpose...
  202. key = 'stretch';
  203. } else {
  204. key = '';
  205. }
  206. }
  207. if (flex || percentageWidth) {
  208. // If we are width.shrinkWrap, we won't be flexing since that requires a
  209. // container width...
  210. if (!ownerSizeModel[names.width].shrinkWrap) {
  211. policy = policy.flex; // both flex and %age width are calculated
  212. }
  213. }
  214. return policy[key];
  215. },
  216. flexSort: function (a, b) {
  217. var maxWidthName = this.getNames().maxWidth,
  218. infiniteValue = Infinity;
  219. a = a.target[maxWidthName] || infiniteValue;
  220. b = b.target[maxWidthName] || infiniteValue;
  221. // IE 6/7 Don't like Infinity - Infinity...
  222. if (!isFinite(a) &amp;&amp; !isFinite(b)) {
  223. return 0;
  224. }
  225. return a - b;
  226. },
  227. isItemBoxParent: function (itemContext) {
  228. return true;
  229. },
  230. isItemShrinkWrap: function (item) {
  231. return true;
  232. },
  233. // Sort into *descending* order.
  234. minSizeSortFn: function(a, b) {
  235. return b.available - a.available;
  236. },
  237. roundFlex: function(width) {
  238. return Math.ceil(width);
  239. },
  240. <span id='Ext-layout-container-Box-method-beginCollapse'> /**
  241. </span> * @private
  242. * Called by an owning Panel before the Panel begins its collapse process.
  243. * Most layouts will not need to override the default Ext.emptyFn implementation.
  244. */
  245. beginCollapse: function(child) {
  246. var me = this;
  247. if (me.direction === 'vertical' &amp;&amp; child.collapsedVertical()) {
  248. child.collapseMemento.capture(['flex']);
  249. delete child.flex;
  250. } else if (me.direction === 'horizontal' &amp;&amp; child.collapsedHorizontal()) {
  251. child.collapseMemento.capture(['flex']);
  252. delete child.flex;
  253. }
  254. },
  255. <span id='Ext-layout-container-Box-method-beginExpand'> /**
  256. </span> * @private
  257. * Called by an owning Panel before the Panel begins its expand process.
  258. * Most layouts will not need to override the default Ext.emptyFn implementation.
  259. */
  260. beginExpand: function(child) {
  261. // Restores the flex if we used to be flexed before
  262. child.collapseMemento.restore(['flex']);
  263. },
  264. beginLayout: function (ownerContext) {
  265. var me = this,
  266. smp = me.owner.stretchMaxPartner,
  267. style = me.innerCt.dom.style,
  268. names = me.getNames();
  269. ownerContext.boxNames = names;
  270. // this must happen before callParent to allow the overflow handler to do its work
  271. // that can effect the childItems collection...
  272. me.overflowHandler.beginLayout(ownerContext);
  273. // get the contextItem for our stretchMax buddy:
  274. if (typeof smp === 'string') {
  275. smp = Ext.getCmp(smp) || me.owner.query(smp)[0];
  276. }
  277. ownerContext.stretchMaxPartner = smp &amp;&amp; ownerContext.context.getCmp(smp);
  278. me.callParent(arguments);
  279. ownerContext.innerCtContext = ownerContext.getEl('innerCt', me);
  280. // Capture whether the owning Container is scrolling in the parallel direction
  281. me.scrollParallel = !!(me.owner.autoScroll || me.owner[names.overflowX]);
  282. // Capture whether the owning Container is scrolling in the perpendicular direction
  283. me.scrollPerpendicular = !!(me.owner.autoScroll || me.owner[names.overflowY]);
  284. // If we *are* scrolling parallel, capture the scroll position of the encapsulating element
  285. if (me.scrollParallel) {
  286. me.scrollPos = me.owner.getTargetEl().dom[names.scrollLeft];
  287. }
  288. // Don't allow sizes burned on to the innerCt to influence measurements.
  289. style.width = '';
  290. style.height = '';
  291. },
  292. beginLayoutCycle: function (ownerContext, firstCycle) {
  293. var me = this,
  294. align = me.align,
  295. names = ownerContext.boxNames,
  296. pack = me.pack,
  297. heightModelName = names.heightModel;
  298. // this must happen before callParent to allow the overflow handler to do its work
  299. // that can effect the childItems collection...
  300. me.overflowHandler.beginLayoutCycle(ownerContext, firstCycle);
  301. me.callParent(arguments);
  302. // Cache several of our string concat/compare results (since width/heightModel can
  303. // change if we are invalidated, we cannot do this in beginLayout)
  304. ownerContext.parallelSizeModel = ownerContext[names.widthModel];
  305. ownerContext.perpendicularSizeModel = ownerContext[heightModelName];
  306. ownerContext.boxOptions = {
  307. align: align = {
  308. stretch: align == 'stretch',
  309. stretchmax: align == 'stretchmax',
  310. center: align == names.center
  311. },
  312. pack: pack = {
  313. center: pack == 'center',
  314. end: pack == 'end'
  315. }
  316. };
  317. // Consider an hbox w/stretch which means &quot;assign all items the container's height&quot;.
  318. // The spirit of this request is make all items the same height, but when shrinkWrap
  319. // height is also requested, the height of the tallest item determines the height.
  320. // This is exactly what the stretchmax option does, so we jiggle the flags here to
  321. // act as if stretchmax were requested.
  322. if (align.stretch &amp;&amp; ownerContext.perpendicularSizeModel.shrinkWrap) {
  323. align.stretchmax = true;
  324. align.stretch = false;
  325. }
  326. // This is handy for knowing that we might need to apply height %ages
  327. align.nostretch = !(align.stretch || align.stretchmax);
  328. // In our example hbox, packing items to the right (end) or center can only work if
  329. // there is a container width. So, if we are shrinkWrap, we just turn off the pack
  330. // options for the run.
  331. if (ownerContext.parallelSizeModel.shrinkWrap) {
  332. pack.center = pack.end = false;
  333. }
  334. me.cacheFlexes(ownerContext);
  335. // In webkit we set the width of the target el equal to the width of the innerCt
  336. // when the layout cycle is finished, so we need to set it back to 20000px here
  337. // to prevent the children from being crushed.
  338. if (Ext.isWebKit) {
  339. me.targetEl.setWidth(20000);
  340. }
  341. },
  342. <span id='Ext-layout-container-Box-method-cacheFlexes'> /**
  343. </span> * This method is called to (re)cache our understanding of flexes. This happens during beginLayout and may need to
  344. * be called again if the flexes are changed during the layout (e.g., like ColumnLayout).
  345. * @param {Object} ownerContext
  346. * @protected
  347. */
  348. cacheFlexes: function (ownerContext) {
  349. var me = this,
  350. names = ownerContext.boxNames,
  351. widthModelName = names.widthModel,
  352. heightModelName = names.heightModel,
  353. nostretch = ownerContext.boxOptions.align.nostretch,
  354. totalFlex = 0,
  355. childItems = ownerContext.childItems,
  356. i = childItems.length,
  357. flexedItems = [],
  358. minWidth = 0,
  359. minWidthName = names.minWidth,
  360. percentageRe = me._percentageRe,
  361. percentageWidths = 0,
  362. percentageHeights = 0,
  363. child, childContext, flex, match;
  364. while (i--) {
  365. childContext = childItems[i];
  366. child = childContext.target;
  367. // check widthModel to see if we are the sizing layout. If so, copy the flex
  368. // from the item to the contextItem and add it to totalFlex
  369. //
  370. if (childContext[widthModelName].calculated) {
  371. childContext.flex = flex = child.flex;
  372. if (flex) {
  373. totalFlex += flex;
  374. flexedItems.push(childContext);
  375. minWidth += child[minWidthName] || 0;
  376. } else { // a %age width...
  377. match = percentageRe.exec(child[names.width]);
  378. childContext.percentageParallel = parseFloat(match[1]) / 100;
  379. ++percentageWidths;
  380. }
  381. }
  382. // the above means that &quot;childContext.flex&quot; is properly truthy/falsy, which is
  383. // often times quite convenient...
  384. if (nostretch &amp;&amp; childContext[heightModelName].calculated) {
  385. // the only reason we would be calculated height in this case is due to a
  386. // height %age...
  387. match = percentageRe.exec(child[names.height]);
  388. childContext.percentagePerpendicular = parseFloat(match[1]) / 100;
  389. ++percentageHeights;
  390. }
  391. }
  392. ownerContext.flexedItems = flexedItems;
  393. ownerContext.flexedMinSize = minWidth;
  394. ownerContext.totalFlex = totalFlex;
  395. ownerContext.percentageWidths = percentageWidths;
  396. ownerContext.percentageHeights = percentageHeights;
  397. // The flexed boxes need to be sorted in ascending order of maxSize to work properly
  398. // so that unallocated space caused by maxWidth being less than flexed width can be
  399. // reallocated to subsequent flexed boxes.
  400. Ext.Array.sort(flexedItems, me.flexSortFn);
  401. },
  402. calculate: function(ownerContext) {
  403. var me = this,
  404. targetSize = me.getContainerSize(ownerContext),
  405. names = ownerContext.boxNames,
  406. state = ownerContext.state,
  407. plan = state.boxPlan || (state.boxPlan = {});
  408. plan.targetSize = targetSize;
  409. // If we are not widthModel.shrinkWrap, we need the width before we can lay out boxes:
  410. if (!ownerContext.parallelSizeModel.shrinkWrap &amp;&amp; !targetSize[names.gotWidth]) {
  411. me.done = false;
  412. return;
  413. }
  414. if (!state.parallelDone) {
  415. state.parallelDone = me.calculateParallel(ownerContext, names, plan);
  416. }
  417. if (!state.perpendicularDone) {
  418. state.perpendicularDone = me.calculatePerpendicular(ownerContext, names, plan);
  419. }
  420. if (state.parallelDone &amp;&amp; state.perpendicularDone) {
  421. // Fix for left and right docked Components in a dock component layout. This is for docked Headers and docked Toolbars.
  422. // Older Microsoft browsers do not size a position:absolute element's width to match its content.
  423. // So in this case, in the publishInnerCtSize method we may need to adjust the size of the owning Container's element explicitly based upon
  424. // the discovered max width. So here we put a calculatedWidth property in the metadata to facilitate this.
  425. if (me.owner.dock &amp;&amp; (Ext.isIE6 || Ext.isIE7 || Ext.isIEQuirks) &amp;&amp; !me.owner.width &amp;&amp; !me.horizontal) {
  426. plan.isIEVerticalDock = true;
  427. plan.calculatedWidth = plan.maxSize + ownerContext.getPaddingInfo().width + ownerContext.getFrameInfo().width;
  428. }
  429. me.publishInnerCtSize(ownerContext, me.reserveOffset ? me.availableSpaceOffset : 0);
  430. // Calculate stretchmax only if there is &gt;1 child item
  431. if (me.done &amp;&amp; ownerContext.childItems.length &gt; 1 &amp;&amp; ownerContext.boxOptions.align.stretchmax &amp;&amp; !state.stretchMaxDone) {
  432. me.calculateStretchMax(ownerContext, names, plan);
  433. state.stretchMaxDone = true;
  434. }
  435. } else {
  436. me.done = false;
  437. }
  438. },
  439. calculateParallel: function(ownerContext, names, plan) {
  440. var me = this,
  441. widthName = names.width,
  442. childItems = ownerContext.childItems,
  443. leftName = names.left,
  444. rightName = names.right,
  445. setWidthName = names.setWidth,
  446. childItemsLength = childItems.length,
  447. flexedItems = ownerContext.flexedItems,
  448. flexedItemsLength = flexedItems.length,
  449. pack = ownerContext.boxOptions.pack,
  450. padding = me.padding,
  451. containerWidth = plan.targetSize[widthName],
  452. totalMargin = 0,
  453. left = padding[leftName],
  454. nonFlexWidth = left + padding[rightName] + me.scrollOffset +
  455. (me.reserveOffset ? me.availableSpaceOffset : 0),
  456. scrollbarWidth = Ext.getScrollbarSize()[names.width],
  457. i, childMargins, remainingWidth, remainingFlex, childContext, flex, flexedWidth,
  458. contentWidth, mayNeedScrollbarAdjust, childWidth, percentageSpace;
  459. // We may need to add scrollbar size to parallel size if
  460. // Scrollbars take up space
  461. // and we are scrolling in the perpendicular direction
  462. // and shrinkWrapping in the parallel direction,
  463. // and NOT stretching perpendicular dimensions to fit
  464. // and NOT shrinkWrapping in the perpendicular direction
  465. if (scrollbarWidth &amp;&amp;
  466. me.scrollPerpendicular &amp;&amp;
  467. ownerContext.parallelSizeModel.shrinkWrap &amp;&amp;
  468. !ownerContext.boxOptions.align.stretch &amp;&amp;
  469. !ownerContext.perpendicularSizeModel.shrinkWrap) {
  470. // If its possible that we may need to add scrollbar size to the parallel size
  471. // then we need to wait until the perpendicular size has been determined,
  472. // so that we know if there is a scrollbar.
  473. if (!ownerContext.state.perpendicularDone) {
  474. return false;
  475. }
  476. mayNeedScrollbarAdjust = true;
  477. }
  478. // Gather the total size taken up by non-flexed items:
  479. for (i = 0; i &lt; childItemsLength; ++i) {
  480. childContext = childItems[i];
  481. childMargins = childContext.marginInfo || childContext.getMarginInfo();
  482. totalMargin += childMargins[widthName];
  483. if (!childContext[names.widthModel].calculated) {
  484. childWidth = childContext.getProp(widthName);
  485. nonFlexWidth += childWidth; // min/maxWidth safe
  486. if (isNaN(nonFlexWidth)) {
  487. return false;
  488. }
  489. }
  490. }
  491. nonFlexWidth += totalMargin;
  492. if (ownerContext.percentageWidths) {
  493. percentageSpace = containerWidth - totalMargin;
  494. if (isNaN(percentageSpace)) {
  495. return false;
  496. }
  497. for (i = 0; i &lt; childItemsLength; ++i) {
  498. childContext = childItems[i];
  499. if (childContext.percentageParallel) {
  500. childWidth = Math.ceil(percentageSpace * childContext.percentageParallel);
  501. childWidth = childContext.setWidth(childWidth);
  502. nonFlexWidth += childWidth;
  503. }
  504. }
  505. }
  506. // if we get here, we have all the childWidths for non-flexed items...
  507. if (ownerContext.parallelSizeModel.shrinkWrap) {
  508. plan.availableSpace = 0;
  509. plan.tooNarrow = false;
  510. } else {
  511. plan.availableSpace = containerWidth - nonFlexWidth;
  512. // If we're going to need space for a parallel scrollbar, then we need to redo the perpendicular measurements
  513. plan.tooNarrow = plan.availableSpace &lt; ownerContext.flexedMinSize;
  514. if (plan.tooNarrow &amp;&amp; Ext.getScrollbarSize()[names.height] &amp;&amp; me.scrollParallel &amp;&amp; ownerContext.state.perpendicularDone) {
  515. ownerContext.state.perpendicularDone = false;
  516. for (i = 0; i &lt; childItemsLength; ++i) {
  517. childItems[i].invalidate();
  518. }
  519. }
  520. }
  521. contentWidth = nonFlexWidth;
  522. remainingWidth = plan.availableSpace;
  523. remainingFlex = ownerContext.totalFlex;
  524. // Calculate flexed item sizes:
  525. for (i = 0; i &lt; flexedItemsLength; i++) {
  526. childContext = flexedItems[i];
  527. flex = childContext.flex;
  528. flexedWidth = me.roundFlex((flex / remainingFlex) * remainingWidth);
  529. flexedWidth = childContext[setWidthName](flexedWidth); // constrained
  530. // due to minWidth constraints, it may be that flexedWidth &gt; remainingWidth
  531. contentWidth += flexedWidth;
  532. // Remaining space has already had margins subtracted, so just subtract size
  533. remainingWidth = Math.max(0, remainingWidth - flexedWidth); // no negatives!
  534. remainingFlex -= flex;
  535. }
  536. if (pack.center) {
  537. left += remainingWidth / 2;
  538. // If content is too wide to pack to center, do not allow the centering calculation to place it off the left edge.
  539. if (left &lt; 0) {
  540. left = 0;
  541. }
  542. } else if (pack.end) {
  543. left += remainingWidth;
  544. }
  545. // Assign parallel position for the boxes:
  546. for (i = 0; i &lt; childItemsLength; ++i) {
  547. childContext = childItems[i];
  548. childMargins = childContext.marginInfo; // already cached by first loop
  549. left += childMargins[leftName];
  550. childContext.setProp(names.x, left);
  551. // We can read directly from &quot;props.width&quot; because we have already properly
  552. // requested it in the calculation of nonFlexedWidths or we calculated it.
  553. // We cannot call getProp because that would be inappropriate for flexed items
  554. // and we don't need any extra function call overhead:
  555. left += childMargins[rightName] + childContext.props[widthName];
  556. }
  557. contentWidth += ownerContext.targetContext.getPaddingInfo()[widthName];
  558. // Stash the contentWidth on the state so that it can always be accessed later in the calculation
  559. ownerContext.state.contentWidth = contentWidth;
  560. // if there is perpendicular overflow, the published parallel content size includes
  561. // the size of the perpendicular scrollbar.
  562. if (mayNeedScrollbarAdjust &amp;&amp;
  563. (ownerContext.peek(names.contentHeight) &gt; plan.targetSize[names.height])) {
  564. contentWidth += scrollbarWidth;
  565. ownerContext[names.hasOverflowY] = true;
  566. // tell the component layout to set the parallel size in the dom
  567. ownerContext.target.componentLayout[names.setWidthInDom] = true;
  568. // IE8 in what passes for &quot;strict&quot; mode will not create a scrollbar if
  569. // there is just the *exactly correct* spare space created for it. We
  570. // have to force that to happen once all the styles have been flushed
  571. // to the DOM (see completeLayout):
  572. ownerContext[names.invalidateScrollY] = (Ext.isStrict &amp;&amp; Ext.isIE8);
  573. }
  574. ownerContext[names.setContentWidth](contentWidth);
  575. return true;
  576. },
  577. calculatePerpendicular: function(ownerContext, names, plan) {
  578. var me = this,
  579. heightShrinkWrap = ownerContext.perpendicularSizeModel.shrinkWrap,
  580. targetSize = plan.targetSize,
  581. childItems = ownerContext.childItems,
  582. childItemsLength = childItems.length,
  583. mmax = Math.max,
  584. heightName = names.height,
  585. setHeightName = names.setHeight,
  586. topName = names.top,
  587. topPositionName = names.y,
  588. padding = me.padding,
  589. top = padding[topName],
  590. availHeight = targetSize[heightName] - top - padding[names.bottom],
  591. align = ownerContext.boxOptions.align,
  592. isStretch = align.stretch, // never true if heightShrinkWrap (see beginLayoutCycle)
  593. isStretchMax = align.stretchmax,
  594. isCenter = align.center,
  595. maxHeight = 0,
  596. hasPercentageSizes = 0,
  597. scrollbarHeight = Ext.getScrollbarSize().height,
  598. childTop, i, childHeight, childMargins, diff, height, childContext,
  599. stretchMaxPartner, stretchMaxChildren, shrinkWrapParallelOverflow,
  600. percentagePerpendicular;
  601. if (isStretch || (isCenter &amp;&amp; !heightShrinkWrap)) {
  602. if (isNaN(availHeight)) {
  603. return false;
  604. }
  605. }
  606. // If the intention is to horizontally scroll child components, but the container is too narrow,
  607. // then:
  608. // if we are shrinkwrapping height:
  609. // Set a flag because we are going to expand the height taken by the perpendicular dimension to accommodate the scrollbar
  610. // else
  611. // We must allow for the parallel scrollbar to intrude into the height
  612. if (me.scrollParallel &amp;&amp; plan.tooNarrow) {
  613. if (heightShrinkWrap) {
  614. shrinkWrapParallelOverflow = true;
  615. } else {
  616. availHeight -= scrollbarHeight;
  617. plan.targetSize[heightName] -= scrollbarHeight;
  618. }
  619. }
  620. if (isStretch) {
  621. height = availHeight; // never heightShrinkWrap...
  622. } else {
  623. for (i = 0; i &lt; childItemsLength; i++) {
  624. childContext = childItems[i];
  625. childMargins = (childContext.marginInfo || childContext.getMarginInfo())[heightName];
  626. if (!(percentagePerpendicular = childContext.percentagePerpendicular)) {
  627. childHeight = childContext.getProp(heightName);
  628. } else {
  629. ++hasPercentageSizes;
  630. if (heightShrinkWrap) {
  631. // height %age items cannot contribute to maxHeight... they are going
  632. // to be a %age of that maxHeight!
  633. continue;
  634. } else {
  635. childHeight = percentagePerpendicular * availHeight - childMargins;
  636. childHeight = childContext[names.setHeight](childHeight);
  637. }
  638. }
  639. // Max perpendicular measurement (used for stretchmax) must take the min perpendicular size of each child into account in case any fall short.
  640. if (isNaN(maxHeight = mmax(maxHeight, childHeight + childMargins,
  641. childContext.target[names.minHeight] || 0))) {
  642. return false; // heightShrinkWrap || isCenter || isStretchMax ??
  643. }
  644. }
  645. // If there is going to be a parallel scrollbar maxHeight must include it to the outside world.
  646. // ie: a stretchmaxPartner, and the setContentHeight
  647. if (shrinkWrapParallelOverflow) {
  648. maxHeight += scrollbarHeight;
  649. ownerContext[names.hasOverflowX] = true;
  650. // tell the component layout to set the perpendicular size in the dom
  651. ownerContext.target.componentLayout[names.setHeightInDom] = true;
  652. // IE8 in what passes for &quot;strict&quot; mode will not create a scrollbar if
  653. // there is just the *exactly correct* spare space created for it. We
  654. // have to force that to happen once all the styles have been flushed
  655. // to the DOM (see completeLayout):
  656. ownerContext[names.invalidateScrollX] = (Ext.isStrict &amp;&amp; Ext.isIE8);
  657. }
  658. // If we are associated with another box layout, grab its maxChildHeight
  659. // This must happen before we calculate and publish our contentHeight
  660. stretchMaxPartner = ownerContext.stretchMaxPartner;
  661. if (stretchMaxPartner) {
  662. // Publish maxChildHeight as soon as it has been calculated for our partner:
  663. ownerContext.setProp('maxChildHeight', maxHeight);
  664. stretchMaxChildren = stretchMaxPartner.childItems;
  665. // Only wait for maxChildHeight if our partner has visible items:
  666. if (stretchMaxChildren &amp;&amp; stretchMaxChildren.length) {
  667. maxHeight = mmax(maxHeight, stretchMaxPartner.getProp('maxChildHeight'));
  668. if (isNaN(maxHeight)) {
  669. return false;
  670. }
  671. }
  672. }
  673. ownerContext[names.setContentHeight](maxHeight + me.padding[heightName] +
  674. ownerContext.targetContext.getPaddingInfo()[heightName]);
  675. // We have to publish the contentHeight with the additional scrollbarHeight
  676. // to encourage our container to accomodate it, but we must remove the height
  677. // of the scrollbar as we go to sizing or centering the children.
  678. if (shrinkWrapParallelOverflow) {
  679. maxHeight -= scrollbarHeight;
  680. }
  681. plan.maxSize = maxHeight;
  682. if (isStretchMax) {
  683. height = maxHeight;
  684. } else if (isCenter || hasPercentageSizes) {
  685. height = heightShrinkWrap ? maxHeight : mmax(availHeight, maxHeight);
  686. // When calculating a centered position within the content box of the innerCt,
  687. // the width of the borders must be subtracted from the size to yield the
  688. // space available to center within. The publishInnerCtSize method explicitly
  689. // adds the border widths to the set size of the innerCt.
  690. height -= ownerContext.innerCtContext.getBorderInfo()[heightName];
  691. }
  692. }
  693. for (i = 0; i &lt; childItemsLength; i++) {
  694. childContext = childItems[i];
  695. childMargins = childContext.marginInfo || childContext.getMarginInfo();
  696. childTop = top + childMargins[topName];
  697. if (isStretch) {
  698. childContext[setHeightName](height - childMargins[heightName]);
  699. } else {
  700. percentagePerpendicular = childContext.percentagePerpendicular;
  701. if (heightShrinkWrap &amp;&amp; percentagePerpendicular) {
  702. childMargins = childContext.marginInfo || childContext.getMarginInfo();
  703. childHeight = percentagePerpendicular * height - childMargins[heightName];
  704. childHeight = childContext.setHeight(childHeight);
  705. }
  706. if (isCenter) {
  707. diff = height - childContext.props[heightName];
  708. if (diff &gt; 0) {
  709. childTop = top + Math.round(diff / 2);
  710. }
  711. }
  712. }
  713. childContext.setProp(topPositionName, childTop);
  714. }
  715. return true;
  716. },
  717. calculateStretchMax: function (ownerContext, names, plan) {
  718. var me = this,
  719. heightName = names.height,
  720. widthName = names.width,
  721. childItems = ownerContext.childItems,
  722. length = childItems.length,
  723. height = plan.maxSize,
  724. onBeforeInvalidateChild = me.onBeforeInvalidateChild,
  725. onAfterInvalidateChild = me.onAfterInvalidateChild,
  726. childContext, props, i, childHeight;
  727. for (i = 0; i &lt; length; ++i) {
  728. childContext = childItems[i];
  729. props = childContext.props;
  730. childHeight = height - childContext.getMarginInfo()[heightName];
  731. if (childHeight != props[heightName] || // if (wrong height ...
  732. childContext[names.heightModel].constrained) { // ...or needs invalidation)
  733. // When we invalidate a child, since we won't be around to size or position
  734. // it, we include an after callback that will be run after the invalidate
  735. // that will (re)do that work. The good news here is that we can read the
  736. // results of all that from the childContext props.
  737. //
  738. // We also include a before callback to change the sizeModel to calculated
  739. // prior to the layout being invoked.
  740. childContext.invalidate({
  741. before: onBeforeInvalidateChild,
  742. after: onAfterInvalidateChild,
  743. layout: me,
  744. // passing this data avoids a 'scope' and its Function.bind
  745. childWidth: props[widthName],
  746. // subtract margins from the maximum value
  747. childHeight: childHeight,
  748. childX: props.x,
  749. childY: props.y,
  750. names: names
  751. });
  752. }
  753. }
  754. },
  755. completeLayout: function(ownerContext) {
  756. var me = this,
  757. names = ownerContext.boxNames,
  758. invalidateScrollX = ownerContext.invalidateScrollX,
  759. invalidateScrollY = ownerContext.invalidateScrollY,
  760. dom, el, overflowX, overflowY, styles;
  761. me.overflowHandler.completeLayout(ownerContext);
  762. if (invalidateScrollX || invalidateScrollY) {
  763. el = me.getTarget();
  764. dom = el.dom;
  765. styles = dom.style;
  766. if (invalidateScrollX) {
  767. // get computed style to see if we are 'auto'
  768. overflowX = el.getStyle('overflowX');
  769. if (overflowX == 'auto') {
  770. // capture the inline style (if any) so we can restore it later:
  771. overflowX = styles.overflowX;
  772. styles.overflowX = 'scroll'; // force the scrollbar to appear
  773. } else {
  774. invalidateScrollX = false; // no work really since not 'auto'
  775. }
  776. }
  777. if (invalidateScrollY) {
  778. // get computed style to see if we are 'auto'
  779. overflowY = el.getStyle('overflowY');
  780. if (overflowY == 'auto') {
  781. // capture the inline style (if any) so we can restore it later:
  782. overflowY = styles.overflowY;
  783. styles.overflowY = 'scroll'; // force the scrollbar to appear
  784. } else {
  785. invalidateScrollY = false; // no work really since not 'auto'
  786. }
  787. }
  788. if (invalidateScrollX || invalidateScrollY) { // if (some form of 'auto' in play)
  789. // force a reflow...
  790. dom.scrollWidth;
  791. if (invalidateScrollX) {
  792. styles.overflowX = overflowX; // restore inline style
  793. }
  794. if (invalidateScrollY) {
  795. styles.overflowY = overflowY; // restore inline style
  796. }
  797. }
  798. }
  799. // If we are scrolling parallel, restore the saved scroll position
  800. if (me.scrollParallel) {
  801. me.owner.getTargetEl().dom[names.scrollLeft] = me.scrollPos;
  802. }
  803. },
  804. finishedLayout: function(ownerContext) {
  805. this.overflowHandler.finishedLayout(ownerContext);
  806. this.callParent(arguments);
  807. // Fix for an obscure webkit bug (EXTJSIV-5962) caused by the targetEl's 20000px
  808. // width. We set a very large width on the targetEl at the beginning of the
  809. // layout cycle to prevent any &quot;crushing&quot; effect on the child items, however
  810. // in some cases the very large width makes it possible to scroll the innerCt
  811. // by dragging on certain child elements. To prevent this from happening we ensure
  812. // that the targetEl's width is the same as the innerCt.
  813. if (Ext.isWebKit) {
  814. this.targetEl.setWidth(ownerContext.innerCtContext.props.width);
  815. }
  816. },
  817. onBeforeInvalidateChild: function (childContext, options) {
  818. // NOTE: No &quot;this&quot; pointer in here...
  819. var heightModelName = options.names.heightModel;
  820. // Change the childItem to calculated (i.e., &quot;set by ownerCt&quot;). The component layout
  821. // of the child can course-correct (like dock layout does for a collapsed panel),
  822. // so we must make these changes here before that layout's beginLayoutCycle is
  823. // called.
  824. if (!childContext[heightModelName].constrainedMax) {
  825. // if the child hit a max constraint, it needs to be at its configured size, so
  826. // we leave the sizeModel alone...
  827. childContext[heightModelName] = Ext.layout.SizeModel.calculated;
  828. }
  829. },
  830. onAfterInvalidateChild: function (childContext, options) {
  831. // NOTE: No &quot;this&quot; pointer in here...
  832. var names = options.names,
  833. scrollbarSize = Ext.getScrollbarSize(),
  834. childHeight = options.childHeight,
  835. childWidth = options.childWidth;
  836. childContext.setProp('x', options.childX);
  837. childContext.setProp('y', options.childY);
  838. if (childContext[names.heightModel].calculated) {
  839. // We need to respect a child that is still not calculated (such as a collapsed
  840. // panel)...
  841. childContext[names.setHeight](childHeight);
  842. }
  843. if (childContext[names.widthModel].calculated) {
  844. childContext[names.setWidth](childWidth);
  845. }
  846. },
  847. publishInnerCtSize: function(ownerContext, reservedSpace) {
  848. var me = this,
  849. names = ownerContext.boxNames,
  850. heightName = names.height,
  851. widthName = names.width,
  852. align = ownerContext.boxOptions.align,
  853. dock = me.owner.dock,
  854. padding = me.padding,
  855. plan = ownerContext.state.boxPlan,
  856. targetSize = plan.targetSize,
  857. height = targetSize[heightName],
  858. innerCtContext = ownerContext.innerCtContext,
  859. innerCtWidth = (ownerContext.parallelSizeModel.shrinkWrap || (plan.tooNarrow &amp;&amp; me.scrollParallel)
  860. ? ownerContext.state.contentWidth
  861. : targetSize[widthName]) - (reservedSpace || 0),
  862. innerCtHeight;
  863. if (align.stretch) {
  864. innerCtHeight = height;
  865. } else {
  866. innerCtHeight = plan.maxSize + padding[names.top] + padding[names.bottom] + innerCtContext.getBorderInfo()[heightName];
  867. if (!ownerContext.perpendicularSizeModel.shrinkWrap &amp;&amp; align.center) {
  868. innerCtHeight = Math.max(height, innerCtHeight);
  869. }
  870. }
  871. innerCtContext[names.setWidth](innerCtWidth);
  872. innerCtContext[names.setHeight](innerCtHeight);
  873. // If unable to publish both dimensions, this layout needs to run again
  874. if (isNaN(innerCtWidth + innerCtHeight)) {
  875. me.done = false;
  876. }
  877. // If a calculated width has been found (this only happens for widthModel.shrinkWrap
  878. // vertical docked Components in old Microsoft browsers) then, if the Component has
  879. // not assumed the size of its content, set it to do so.
  880. //
  881. // We MUST pass the dirty flag to get that into the DOM, and because we are a Container
  882. // layout, and not really supposed to perform sizing, we must also use the force flag.
  883. if (plan.calculatedWidth &amp;&amp; (dock == 'left' || dock == 'right')) {
  884. // TODO: setting the owner size should be the job of the component layout.
  885. ownerContext.setWidth(plan.calculatedWidth, true, true);
  886. }
  887. },
  888. onRemove: function(comp){
  889. var me = this;
  890. me.callParent(arguments);
  891. if (me.overflowHandler) {
  892. me.overflowHandler.onRemove(comp);
  893. }
  894. if (comp.layoutMarginCap == me.id) {
  895. delete comp.layoutMarginCap;
  896. }
  897. },
  898. <span id='Ext-layout-container-Box-method-initOverflowHandler'> /**
  899. </span> * @private
  900. */
  901. initOverflowHandler: function() {
  902. var me = this,
  903. handler = me.overflowHandler,
  904. handlerType,
  905. constructor;
  906. if (typeof handler == 'string') {
  907. handler = {
  908. type: handler
  909. };
  910. }
  911. handlerType = 'None';
  912. if (handler &amp;&amp; handler.type !== undefined) {
  913. handlerType = handler.type;
  914. }
  915. constructor = Ext.layout.container.boxOverflow[handlerType];
  916. if (constructor[me.type]) {
  917. constructor = constructor[me.type];
  918. }
  919. me.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.' + handlerType, me, handler);
  920. },
  921. // Overridden method from Ext.layout.container.Container.
  922. // Used in the beforeLayout method to render all items into.
  923. getRenderTarget: function() {
  924. return this.targetEl;
  925. },
  926. // Overridden method from Ext.layout.container.Container.
  927. // Used by Container classes to insert special DOM elements which must exist in addition to the child components
  928. getElementTarget: function() {
  929. return this.innerCt;
  930. },
  931. //&lt;debug&gt;
  932. calculateChildBox: Ext.deprecated(),
  933. calculateChildBoxes: Ext.deprecated(),
  934. updateChildBoxes: Ext.deprecated(),
  935. //&lt;/debug&gt;
  936. <span id='Ext-layout-container-Box-method-destroy'> /**
  937. </span> * @private
  938. */
  939. destroy: function() {
  940. Ext.destroy(this.innerCt, this.overflowHandler);
  941. this.callParent(arguments);
  942. }
  943. });
  944. </pre>
  945. </body>
  946. </html>