ContextItem.html 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708
  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-ContextItem'>/**
  19. </span> * This class manages state information for a component or element during a layout.
  20. *
  21. * # Blocks
  22. *
  23. * A &quot;block&quot; is a required value that is preventing further calculation. When a layout has
  24. * encountered a situation where it cannot possibly calculate results, it can associate
  25. * itself with the context item and missing property so that it will not be rescheduled
  26. * until that property is set.
  27. *
  28. * Blocks are a one-shot registration. Once the property changes, the block is removed.
  29. *
  30. * Be careful with blocks. If *any* further calculations can be made, a block is not the
  31. * right choice.
  32. *
  33. * # Triggers
  34. *
  35. * Whenever any call to {@link #getProp}, {@link #getDomProp}, {@link #hasProp} or
  36. * {@link #hasDomProp} is made, the current layout is automatically registered as being
  37. * dependent on that property in the appropriate state. Any changes to the property will
  38. * trigger the layout and it will be queued in the {@link Ext.layout.Context}.
  39. *
  40. * Triggers, once added, remain for the entire layout. Any changes to the property will
  41. * reschedule all unfinished layouts in their trigger set.
  42. *
  43. * @private
  44. */
  45. Ext.define('Ext.layout.ContextItem', {
  46. requires: ['Ext.layout.ClassList'],
  47. heightModel: null,
  48. widthModel: null,
  49. sizeModel: null,
  50. boxChildren: null,
  51. boxParent: null,
  52. children: [],
  53. dirty: null,
  54. // The number of dirty properties
  55. dirtyCount: 0,
  56. hasRawContent: true,
  57. isContextItem: true,
  58. isTopLevel: false,
  59. consumersContentHeight: 0,
  60. consumersContentWidth: 0,
  61. consumersContainerHeight: 0,
  62. consumersContainerWidth: 0,
  63. consumersHeight: 0,
  64. consumersWidth: 0,
  65. ownerCtContext: null,
  66. remainingChildLayouts: 0,
  67. remainingComponentChildLayouts: 0,
  68. remainingContainerChildLayouts: 0,
  69. // the current set of property values:
  70. props: null,
  71. <span id='Ext-layout-ContextItem-property-state'> /**
  72. </span> * @property {Object} state
  73. * State variables that are cleared when invalidated. Only applies to component items.
  74. */
  75. state: null,
  76. <span id='Ext-layout-ContextItem-property-wrapsComponent'> /**
  77. </span> * @property {Boolean} wrapsComponent
  78. * True if this item wraps a Component (rather than an Element).
  79. * @readonly
  80. */
  81. wrapsComponent: false,
  82. constructor: function (config) {
  83. var me = this,
  84. el, ownerCt, ownerCtContext, sizeModel, target;
  85. Ext.apply(me, config);
  86. el = me.el;
  87. me.id = el.id;
  88. me.lastBox = el.lastBox;
  89. // These hold collections of layouts that are either blocked or triggered by sets
  90. // to our properties (either ASAP or after flushing to the DOM). All of them have
  91. // the same structure:
  92. //
  93. // me.blocks = {
  94. // width: {
  95. // 'layout-1001': layout1001
  96. // }
  97. // }
  98. //
  99. // The property name is the primary key which yields an object keyed by layout id
  100. // with the layout instance as the value. This prevents duplicate entries for one
  101. // layout and gives O(1) access to the layout instance when we need to iterate and
  102. // process them.
  103. //
  104. // me.blocks = {};
  105. // me.domBlocks = {};
  106. // me.domTriggers = {};
  107. // me.triggers = {};
  108. me.flushedProps = {};
  109. me.props = {};
  110. // the set of cached styles for the element:
  111. me.styles = {};
  112. target = me.target;
  113. if (target.isComponent) {
  114. me.wrapsComponent = true;
  115. // These items are created top-down, so the ContextItem of our ownerCt should
  116. // be available (if it is part of this layout run).
  117. ownerCt = target.ownerCt;
  118. if (ownerCt &amp;&amp; (ownerCtContext = me.context.items[ownerCt.el.id])) {
  119. me.ownerCtContext = ownerCtContext;
  120. }
  121. // If our ownerCtContext is in the run, it will have a SizeModel that we use to
  122. // optimize the determination of our sizeModel.
  123. me.sizeModel = sizeModel = target.getSizeModel(ownerCtContext &amp;&amp;
  124. ownerCtContext.widthModel.pairsByHeightOrdinal[ownerCtContext.heightModel.ordinal]);
  125. me.widthModel = sizeModel.width;
  126. me.heightModel = sizeModel.height;
  127. // NOTE: The initial determination of sizeModel is valid (thankfully) and is
  128. // needed to cope with adding components to a layout run on-the-fly (e.g., in
  129. // the menu overflow handler of a box layout). Since this is the case, we do
  130. // not need to recompute the sizeModel in init unless it is a &quot;full&quot; init (as
  131. // our ownerCt's sizeModel could have changed in that case).
  132. }
  133. },
  134. <span id='Ext-layout-ContextItem-method-init'> /**
  135. </span> * Clears all properties on this object except (perhaps) those not calculated by this
  136. * component. This is more complex than it would seem because a layout can decide to
  137. * invalidate its results and run the component's layouts again, but since some of the
  138. * values may be calculated by the container, care must be taken to preserve those
  139. * values.
  140. *
  141. * @param {Boolean} full True if all properties are to be invalidated, false to keep
  142. * those calculated by the ownerCt.
  143. * @return {Mixed} A value to pass as the first argument to {@link #initContinue}.
  144. * @private
  145. */
  146. init: function (full, options) {
  147. var me = this,
  148. oldProps = me.props,
  149. oldDirty = me.dirty,
  150. ownerCtContext = me.ownerCtContext,
  151. ownerLayout = me.target.ownerLayout,
  152. firstTime = !me.state,
  153. ret = full || firstTime,
  154. children, i, n, ownerCt, sizeModel, target,
  155. oldHeightModel = me.heightModel,
  156. oldWidthModel = me.widthModel,
  157. newHeightModel, newWidthModel;
  158. me.dirty = me.invalid = false;
  159. me.props = {};
  160. if (me.boxChildren) {
  161. me.boxChildren.length = 0; // keep array (more GC friendly)
  162. }
  163. if (!firstTime) {
  164. me.clearAllBlocks('blocks');
  165. me.clearAllBlocks('domBlocks');
  166. }
  167. // For Element wrappers, we are done...
  168. if (!me.wrapsComponent) {
  169. return ret;
  170. }
  171. // From here on, we are only concerned with Component wrappers...
  172. target = me.target;
  173. me.state = {}; // only Component wrappers need a &quot;state&quot;
  174. if (firstTime) {
  175. // This must occur before we proceed since it can do many things (like add
  176. // child items perhaps):
  177. if (target.beforeLayout) {
  178. target.beforeLayout();
  179. }
  180. // Determine the ownerCtContext if we aren't given one. Normally the firstTime
  181. // we meet a component is before the context is run, but it is possible for
  182. // components to be added to a run that is already in progress. If so, we have
  183. // to lookup the ownerCtContext since the odds are very high that the new
  184. // component is a child of something already in the run. It is currently
  185. // unsupported to drag in the owner of a running component (needs testing).
  186. if (!ownerCtContext &amp;&amp; (ownerCt = target.ownerCt)) {
  187. ownerCtContext = me.context.items[ownerCt.el.id];
  188. }
  189. if (ownerCtContext) {
  190. me.ownerCtContext = ownerCtContext;
  191. me.isBoxParent = target.ownerLayout.isItemBoxParent(me);
  192. } else {
  193. me.isTopLevel = true; // this is used by initAnimation...
  194. }
  195. me.frameBodyContext = me.getEl('frameBody');
  196. } else {
  197. ownerCtContext = me.ownerCtContext;
  198. // In theory (though untested), this flag can change on-the-fly...
  199. me.isTopLevel = !ownerCtContext;
  200. // Init the children element items since they may have dirty state (no need to
  201. // do this the firstTime).
  202. children = me.children;
  203. for (i = 0, n = children.length; i &lt; n; ++i) {
  204. children[i].init(true);
  205. }
  206. }
  207. // We need to know how we will determine content size: containers can look at the
  208. // results of their items but non-containers or item-less containers with just raw
  209. // markup need to be measured in the DOM:
  210. me.hasRawContent = !(target.isContainer &amp;&amp; target.items.items.length &gt; 0);
  211. if (full) {
  212. // We must null these out or getSizeModel will assume they are the correct,
  213. // dynamic size model and return them (the previous dynamic sizeModel).
  214. me.widthModel = me.heightModel = null;
  215. sizeModel = target.getSizeModel(ownerCtContext &amp;&amp;
  216. ownerCtContext.widthModel.pairsByHeightOrdinal[ownerCtContext.heightModel.ordinal]);
  217. if (firstTime) {
  218. me.sizeModel = sizeModel;
  219. }
  220. me.widthModel = sizeModel.width;
  221. me.heightModel = sizeModel.height;
  222. } else if (oldProps) {
  223. // these are almost always calculated by the ownerCt (we might need to track
  224. // this at some point more carefully):
  225. me.recoverProp('x', oldProps, oldDirty);
  226. me.recoverProp('y', oldProps, oldDirty);
  227. // if these are calculated by the ownerCt, don't trash them:
  228. if (me.widthModel.calculated) {
  229. me.recoverProp('width', oldProps, oldDirty);
  230. }
  231. if (me.heightModel.calculated) {
  232. me.recoverProp('height', oldProps, oldDirty);
  233. }
  234. }
  235. if (oldProps &amp;&amp; ownerLayout &amp;&amp; ownerLayout.manageMargins) {
  236. me.recoverProp('margin-top', oldProps, oldDirty);
  237. me.recoverProp('margin-right', oldProps, oldDirty);
  238. me.recoverProp('margin-bottom', oldProps, oldDirty);
  239. me.recoverProp('margin-left', oldProps, oldDirty);
  240. }
  241. // Process any invalidate options present. These can only come from explicit calls
  242. // to the invalidate() method.
  243. if (options) {
  244. // Consider a container box with wrapping text. If the box is made wider, the
  245. // text will take up less height (until there is no more wrapping). Conversely,
  246. // if the box is made narrower, the height starts to increase due to wrapping.
  247. //
  248. // Imposing a minWidth constraint would increase the width. This may decrease
  249. // the height. If the box is shrinkWrap, however, the width will already be
  250. // such that there is no wrapping, so the height will not further decrease.
  251. // Since the height will also not increase if we widen the box, there is no
  252. // problem simultaneously imposing a minHeight or maxHeight constraint.
  253. //
  254. // When we impose as maxWidth constraint, however, we are shrinking the box
  255. // which may increase the height. If we are imposing a maxHeight constraint,
  256. // that is fine because a further increased height will still need to be
  257. // constrained. But if we are imposing a minHeight constraint, we cannot know
  258. // whether the increase in height due to wrapping will be greater than the
  259. // minHeight. If we impose a minHeight constraint at the same time, then, we
  260. // could easily be locking in the wrong height.
  261. //
  262. // It is important to note that this logic applies to simultaneously *adding*
  263. // both a maxWidth and a minHeight constraint. It is perfectly fine to have
  264. // a state with both constraints, but we cannot add them both at once.
  265. newHeightModel = options.heightModel;
  266. newWidthModel = options.widthModel;
  267. if (newWidthModel &amp;&amp; newHeightModel &amp;&amp; oldWidthModel &amp;&amp; oldHeightModel) {
  268. if (oldWidthModel.shrinkWrap &amp;&amp; oldHeightModel.shrinkWrap) {
  269. if (newWidthModel.constrainedMax &amp;&amp; newHeightModel.constrainedMin) {
  270. newHeightModel = null;
  271. }
  272. }
  273. }
  274. // Apply size model updates (if any) and state updates (if any).
  275. if (newWidthModel) {
  276. me.widthModel = newWidthModel;
  277. }
  278. if (newHeightModel) {
  279. me.heightModel = newHeightModel;
  280. }
  281. if (options.state) {
  282. Ext.apply(me.state, options.state);
  283. }
  284. }
  285. return ret;
  286. },
  287. <span id='Ext-layout-ContextItem-method-initContinue'> /**
  288. </span> * @private
  289. */
  290. initContinue: function (full) {
  291. var me = this,
  292. ownerCtContext = me.ownerCtContext,
  293. widthModel = me.widthModel,
  294. boxParent;
  295. if (full) {
  296. if (ownerCtContext &amp;&amp; widthModel.shrinkWrap) {
  297. boxParent = ownerCtContext.isBoxParent ? ownerCtContext : ownerCtContext.boxParent;
  298. if (boxParent) {
  299. boxParent.addBoxChild(me);
  300. }
  301. } else if (widthModel.natural) {
  302. me.boxParent = ownerCtContext;
  303. }
  304. }
  305. return full;
  306. },
  307. <span id='Ext-layout-ContextItem-method-initDone'> /**
  308. </span> * @private
  309. */
  310. initDone: function (full, componentChildrenDone, containerChildrenDone, containerLayoutDone) {
  311. var me = this,
  312. props = me.props,
  313. state = me.state;
  314. // These properties are only set when they are true:
  315. if (componentChildrenDone) {
  316. props.componentChildrenDone = true;
  317. }
  318. if (containerChildrenDone) {
  319. props.containerChildrenDone = true;
  320. }
  321. if (containerLayoutDone) {
  322. props.containerLayoutDone = true;
  323. }
  324. if (me.boxChildren &amp;&amp; me.boxChildren.length &amp;&amp; me.widthModel.shrinkWrap) {
  325. // set a very large width to allow the children to measure their natural
  326. // widths (this is cleared once all children have been measured):
  327. me.el.setWidth(10000);
  328. // don't run layouts for this component until we clear this width...
  329. state.blocks = (state.blocks || 0) + 1;
  330. }
  331. },
  332. <span id='Ext-layout-ContextItem-method-initAnimation'> /**
  333. </span> * @private
  334. */
  335. initAnimation: function() {
  336. var me = this,
  337. target = me.target,
  338. ownerCtContext = me.ownerCtContext;
  339. if (ownerCtContext &amp;&amp; ownerCtContext.isTopLevel) {
  340. // See which properties we are supposed to animate to their new state.
  341. // If there are any, queue ourself to be animated by the owning Context
  342. me.animatePolicy = target.ownerLayout.getAnimatePolicy(me);
  343. } else if (!ownerCtContext &amp;&amp; target.isCollapsingOrExpanding &amp;&amp; target.animCollapse) {
  344. // Collapsing/expnding a top level Panel with animation. We need to fabricate
  345. // an animatePolicy depending on which dimension the collapse is using,
  346. // isCollapsingOrExpanding is set during the collapse/expand process.
  347. me.animatePolicy = target.componentLayout.getAnimatePolicy(me);
  348. }
  349. if (me.animatePolicy) {
  350. me.context.queueAnimation(me);
  351. }
  352. },
  353. noFraming: { left: 0, top: 0, right: 0, bottom: 0, width: 0, height: 0 },
  354. <span id='Ext-layout-ContextItem-method-addCls'> /**
  355. </span> * Queue the addition of a class name (or array of class names) to this ContextItem's target when next flushed.
  356. */
  357. addCls: function(newCls) {
  358. this.getClassList().addMany(newCls);
  359. },
  360. <span id='Ext-layout-ContextItem-method-removeCls'> /**
  361. </span> * Queue the removal of a class name (or array of class names) from this ContextItem's target when next flushed.
  362. */
  363. removeCls: function(removeCls) {
  364. this.getClassList().removeMany(removeCls);
  365. },
  366. <span id='Ext-layout-ContextItem-method-addBlock'> /**
  367. </span> * Adds a block.
  368. *
  369. * @param {String} name The name of the block list ('blocks' or 'domBlocks').
  370. * @param {Ext.layout.Layout} layout The layout that is blocked.
  371. * @param {String} propName The property name that blocked the layout (e.g., 'width').
  372. * @private
  373. */
  374. addBlock: function (name, layout, propName) {
  375. var me = this,
  376. collection = me[name] || (me[name] = {}),
  377. blockedLayouts = collection[propName] || (collection[propName] = {});
  378. if (!blockedLayouts[layout.id]) {
  379. blockedLayouts[layout.id] = layout;
  380. ++layout.blockCount;
  381. ++me.context.blockCount;
  382. }
  383. },
  384. addBoxChild: function (boxChildItem) {
  385. var me = this,
  386. children,
  387. widthModel = boxChildItem.widthModel;
  388. boxChildItem.boxParent = this;
  389. // Children that are widthModel.auto (regardless of heightModel) that measure the
  390. // DOM (by virtue of hasRawContent), need to wait for their &quot;box parent&quot; to be sized.
  391. // If they measure too early, they will be wrong results. In the widthModel.shrinkWrap
  392. // case, the boxParent &quot;crushes&quot; the child. In the case of widthModel.natural, the
  393. // boxParent's width is likely a key part of the child's width (e.g., &quot;50%&quot; or just
  394. // normal block-level behavior of 100% width)
  395. boxChildItem.measuresBox = widthModel.shrinkWrap ? boxChildItem.hasRawContent : widthModel.natural;
  396. if (boxChildItem.measuresBox) {
  397. children = me.boxChildren;
  398. if (children) {
  399. children.push(boxChildItem);
  400. } else {
  401. me.boxChildren = [ boxChildItem ];
  402. }
  403. }
  404. },
  405. <span id='Ext-layout-ContextItem-method-addTrigger'> /**
  406. </span> * Adds a trigger.
  407. *
  408. * @param {String} propName The property name that triggers the layout (e.g., 'width').
  409. * @param {Boolean} inDom True if the trigger list is `domTriggers`, false if `triggers`.
  410. * @private
  411. */
  412. addTrigger: function (propName, inDom) {
  413. var me = this,
  414. name = inDom ? 'domTriggers' : 'triggers',
  415. collection = me[name] || (me[name] = {}),
  416. context = me.context,
  417. layout = context.currentLayout,
  418. triggers = collection[propName] || (collection[propName] = {});
  419. if (!triggers[layout.id]) {
  420. triggers[layout.id] = layout;
  421. ++layout.triggerCount;
  422. triggers = context.triggers[inDom ? 'dom' : 'data'];
  423. (triggers[layout.id] || (triggers[layout.id] = [])).push({
  424. item: this,
  425. prop: propName
  426. });
  427. if (me.props[propName] !== undefined) {
  428. if (!inDom || !(me.dirty &amp;&amp; (propName in me.dirty))) {
  429. ++layout.firedTriggers;
  430. }
  431. }
  432. }
  433. },
  434. boxChildMeasured: function () {
  435. var me = this,
  436. state = me.state,
  437. count = (state.boxesMeasured = (state.boxesMeasured || 0) + 1);
  438. if (count == me.boxChildren.length) {
  439. // all of our children have measured themselves, so we can clear the width
  440. // and resume layouts for this component...
  441. state.clearBoxWidth = 1;
  442. ++me.context.progressCount;
  443. me.markDirty();
  444. }
  445. },
  446. borderNames: [ 'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width'],
  447. marginNames: [ 'margin-top', 'margin-right', 'margin-bottom', 'margin-left' ],
  448. paddingNames: [ 'padding-top', 'padding-right', 'padding-bottom', 'padding-left' ],
  449. trblNames: [ 'top', 'right', 'bottom', 'left' ],
  450. cacheMissHandlers: {
  451. borderInfo: function (me) {
  452. var info = me.getStyles(me.borderNames, me.trblNames);
  453. info.width = info.left + info.right;
  454. info.height = info.top + info.bottom;
  455. return info;
  456. },
  457. marginInfo: function (me) {
  458. var info = me.getStyles(me.marginNames, me.trblNames);
  459. info.width = info.left + info.right;
  460. info.height = info.top + info.bottom;
  461. return info;
  462. },
  463. paddingInfo: function (me) {
  464. // if this context item's target is a framed component the padding is on the frameBody, not on the main el
  465. var item = me.frameBodyContext || me,
  466. info = item.getStyles(me.paddingNames, me.trblNames);
  467. info.width = info.left + info.right;
  468. info.height = info.top + info.bottom;
  469. return info;
  470. }
  471. },
  472. checkCache: function (entry) {
  473. return this.cacheMissHandlers[entry](this);
  474. },
  475. clearAllBlocks: function (name) {
  476. var collection = this[name],
  477. propName;
  478. if (collection) {
  479. for (propName in collection) {
  480. this.clearBlocks(name, propName);
  481. }
  482. }
  483. },
  484. <span id='Ext-layout-ContextItem-method-clearBlocks'> /**
  485. </span> * Removes any blocks on a property in the specified set. Any layouts that were blocked
  486. * by this property and are not still blocked (by other properties) will be rescheduled.
  487. *
  488. * @param {String} name The name of the block list ('blocks' or 'domBlocks').
  489. * @param {String} propName The property name that blocked the layout (e.g., 'width').
  490. * @private
  491. */
  492. clearBlocks: function (name, propName) {
  493. var collection = this[name],
  494. blockedLayouts = collection &amp;&amp; collection[propName],
  495. context, layout, layoutId;
  496. if (blockedLayouts) {
  497. delete collection[propName];
  498. context = this.context;
  499. for (layoutId in blockedLayouts) {
  500. layout = blockedLayouts[layoutId];
  501. --context.blockCount;
  502. if (! --layout.blockCount &amp;&amp; !layout.pending &amp;&amp; !layout.done) {
  503. context.queueLayout(layout);
  504. }
  505. }
  506. }
  507. },
  508. <span id='Ext-layout-ContextItem-method-block'> /**
  509. </span> * Registers a layout in the block list for the given property. Once the property is
  510. * set in the {@link Ext.layout.Context}, the layout is unblocked.
  511. *
  512. * @param {Ext.layout.Layout} layout
  513. * @param {String} propName The property name that blocked the layout (e.g., 'width').
  514. */
  515. block: function (layout, propName) {
  516. this.addBlock('blocks', layout, propName);
  517. },
  518. <span id='Ext-layout-ContextItem-method-domBlock'> /**
  519. </span> * Registers a layout in the DOM block list for the given property. Once the property
  520. * flushed to the DOM by the {@link Ext.layout.Context}, the layout is unblocked.
  521. *
  522. * @param {Ext.layout.Layout} layout
  523. * @param {String} propName The property name that blocked the layout (e.g., 'width').
  524. */
  525. domBlock: function (layout, propName) {
  526. this.addBlock('domBlocks', layout, propName);
  527. },
  528. <span id='Ext-layout-ContextItem-method-fireTriggers'> /**
  529. </span> * Reschedules any layouts associated with a given trigger.
  530. *
  531. * @param {String} name The name of the trigger list ('triggers' or 'domTriggers').
  532. * @param {String} propName The property name that triggers the layout (e.g., 'width').
  533. * @private
  534. */
  535. fireTriggers: function (name, propName) {
  536. var collection = this[name],
  537. triggers = collection &amp;&amp; collection[propName],
  538. context = this.context,
  539. layout, layoutId;
  540. if (triggers) {
  541. for (layoutId in triggers) {
  542. layout = triggers[layoutId];
  543. ++layout.firedTriggers;
  544. if (!layout.done &amp;&amp; !layout.blockCount &amp;&amp; !layout.pending) {
  545. context.queueLayout(layout);
  546. }
  547. }
  548. }
  549. },
  550. <span id='Ext-layout-ContextItem-method-flush'> /**
  551. </span> * Flushes any updates in the dirty collection to the DOM. This is only called if there
  552. * are dirty entries because this object is only added to the flushQueue of the
  553. * {@link Ext.layout.Context} when entries become dirty.
  554. */
  555. flush: function () {
  556. var me = this,
  557. dirty = me.dirty,
  558. state = me.state,
  559. targetEl = me.el;
  560. me.dirtyCount = 0;
  561. // Flush added/removed classes
  562. if (me.classList &amp;&amp; me.classList.dirty) {
  563. me.classList.flush();
  564. }
  565. // Set any queued DOM attributes
  566. if ('attributes' in me) {
  567. targetEl.set(me.attributes);
  568. delete me.attributes;
  569. }
  570. // Set any queued DOM HTML content
  571. if ('innerHTML' in me) {
  572. targetEl.innerHTML = me.innerHTML;
  573. delete me.innerHTML;
  574. }
  575. if (state &amp;&amp; state.clearBoxWidth) {
  576. state.clearBoxWidth = 0;
  577. me.el.setStyle('width', null);
  578. if (! --state.blocks) {
  579. me.context.queueItemLayouts(me);
  580. }
  581. }
  582. if (dirty) {
  583. delete me.dirty;
  584. me.writeProps(dirty, true);
  585. }
  586. },
  587. <span id='Ext-layout-ContextItem-method-flushAnimations'> /**
  588. </span> * @private
  589. */
  590. flushAnimations: function() {
  591. var me = this,
  592. animateFrom = me.lastBox,
  593. target, targetAnim, duration, animateProps, anim,
  594. changeCount, j, propsLen, propName, oldValue, newValue;
  595. // Only animate if the Component has been previously layed out: first layout should not animate
  596. if (animateFrom) {
  597. target = me.target;
  598. targetAnim = target.layout &amp;&amp; target.layout.animate;
  599. if (targetAnim) {
  600. duration = Ext.isNumber(targetAnim) ? targetAnim : targetAnim.duration;
  601. }
  602. animateProps = Ext.Object.getKeys(me.animatePolicy);
  603. // Create an animation block using the targetAnim configuration to provide defaults.
  604. // They may want custom duration, or easing, or listeners.
  605. anim = Ext.apply({}, {
  606. from: {},
  607. to: {},
  608. duration: duration || Ext.fx.Anim.prototype.duration
  609. }, targetAnim);
  610. for (changeCount = 0, j = 0, propsLen = animateProps.length; j &lt; propsLen; j++) {
  611. propName = animateProps[j];
  612. oldValue = animateFrom[propName];
  613. newValue = me.peek(propName);
  614. if (oldValue != newValue) {
  615. propName = me.translateProps[propName]||propName;
  616. anim.from[propName] = oldValue;
  617. anim.to[propName] = newValue;
  618. ++changeCount;
  619. }
  620. }
  621. // If any values have changed, kick off animation from the cached old values to the new values
  622. if (changeCount) {
  623. // It'a Panel being collapsed. rollback, and then fix the class name string
  624. if (me.isCollapsingOrExpanding === 1) {
  625. target.componentLayout.undoLayout(me);
  626. }
  627. // Otherwise, undo just the animated properties so the animation can proceed from the old layout.
  628. else {
  629. me.writeProps(anim.from);
  630. }
  631. me.el.animate(anim);
  632. Ext.fx.Manager.getFxQueue(me.el.id)[0].on({
  633. afteranimate: function() {
  634. if (me.isCollapsingOrExpanding === 1) {
  635. target.componentLayout.redoLayout(me);
  636. target.afterCollapse(true);
  637. } else if (me.isCollapsingOrExpanding === 2) {
  638. target.afterExpand(true);
  639. }
  640. }
  641. });
  642. }
  643. }
  644. },
  645. <span id='Ext-layout-ContextItem-method-getBorderInfo'> /**
  646. </span> * Gets the border information for the element as an object with left, top, right and
  647. * bottom properties holding border size in pixels. This object is only read from the
  648. * DOM on first request and is cached.
  649. * @return {Object}
  650. */
  651. getBorderInfo: function () {
  652. var me = this,
  653. info = me.borderInfo;
  654. if (!info) {
  655. me.borderInfo = info = me.checkCache('borderInfo');
  656. }
  657. return info;
  658. },
  659. <span id='Ext-layout-ContextItem-method-getClassList'> /**
  660. </span> * Returns a ClassList-like object to buffer access to this item's element's classes.
  661. */
  662. getClassList: function () {
  663. return this.classList || (this.classList = new Ext.layout.ClassList(this));
  664. },
  665. <span id='Ext-layout-ContextItem-method-getEl'> /**
  666. </span> * Returns the context item for an owned element. This should only be called on a
  667. * component's item. The list of child items is used to manage invalidating calculated
  668. * results.
  669. */
  670. getEl: function (nameOrEl, owner) {
  671. var me = this,
  672. src, el, elContext;
  673. if (nameOrEl) {
  674. if (nameOrEl.dom) {
  675. el = nameOrEl;
  676. } else {
  677. src = me.target;
  678. if (owner) {
  679. src = owner;
  680. }
  681. el = src[nameOrEl];
  682. if (typeof el == 'function') { // ex 'getTarget'
  683. el = el.call(src);
  684. if (el === me.el) {
  685. return this; // comp.getTarget() often returns comp.el
  686. }
  687. }
  688. }
  689. if (el) {
  690. elContext = me.context.getEl(me, el);
  691. }
  692. }
  693. return elContext || null;
  694. },
  695. getFraming: function () {
  696. var me = this;
  697. if (!me.framingInfo) {
  698. me.framingInfo = me.target.frameSize || me.noFraming;
  699. }
  700. return me.framingInfo;
  701. },
  702. <span id='Ext-layout-ContextItem-method-getFrameInfo'> /**
  703. </span> * Gets the &quot;frame&quot; information for the element as an object with left, top, right and
  704. * bottom properties holding border+framing size in pixels. This object is calculated
  705. * on first request and is cached.
  706. * @return {Object}
  707. */
  708. getFrameInfo: function () {
  709. var me = this,
  710. info = me.frameInfo,
  711. frame, border;
  712. if (!info) {
  713. frame = me.getFraming();
  714. border = me.getBorderInfo();
  715. me.frameInfo = info = {
  716. top : frame.top + border.top,
  717. right : frame.right + border.right,
  718. bottom: frame.bottom + border.bottom,
  719. left : frame.left + border.left,
  720. width : frame.width + border.width,
  721. height: frame.height + border.height
  722. };
  723. }
  724. return info;
  725. },
  726. <span id='Ext-layout-ContextItem-method-getMarginInfo'> /**
  727. </span> * Gets the margin information for the element as an object with left, top, right and
  728. * bottom properties holding margin size in pixels. This object is only read from the
  729. * DOM on first request and is cached.
  730. * @return {Object}
  731. */
  732. getMarginInfo: function () {
  733. var me = this,
  734. info = me.marginInfo,
  735. comp, manageMargins, margins, ownerLayout, ownerLayoutId;
  736. if (!info) {
  737. if (!me.wrapsComponent) {
  738. info = me.checkCache('marginInfo');
  739. } else {
  740. comp = me.target;
  741. ownerLayout = comp.ownerLayout;
  742. ownerLayoutId = ownerLayout ? ownerLayout.id : null;
  743. manageMargins = ownerLayout &amp;&amp; ownerLayout.manageMargins;
  744. // Option #1 for configuring margins on components is the &quot;margin&quot; config
  745. // property. When supplied, this config is written to the DOM during the
  746. // render process (see AbstractComponent#initStyles).
  747. //
  748. // Option #2 is available to some layouts (e.g., Box, Border, Fit) that
  749. // handle margin calculations themselves. These layouts support a &quot;margins&quot;
  750. // config property on their items and they have a &quot;defaultMargins&quot; config
  751. // property. These margin values are added to the &quot;natural&quot; margins read
  752. // from the DOM and 0's are written to the DOM after they are added.
  753. // To avoid having to do all this on every layout, we cache the results on
  754. // the component in the (private) &quot;margin$&quot; property. We identify the cache
  755. // results as belonging to the appropriate ownerLayout in case items are
  756. // moved around.
  757. info = comp.margin$;
  758. if (info &amp;&amp; info.ownerId !== ownerLayoutId) {
  759. // got one but from the wrong owner
  760. info = null;
  761. // if (manageMargins) {
  762. // TODO: clear inline margins (the 0's we wrote last time)???
  763. // }
  764. }
  765. if (!info) { // if (no cache)
  766. // CSS margins are only checked if there isn't a margin property on the component
  767. info = me.parseMargins(comp.margin) || me.checkCache('marginInfo');
  768. // Some layouts also support margins and defaultMargins, e.g. Fit, Border, Box
  769. if (manageMargins) {
  770. margins = me.parseMargins(comp.margins, ownerLayout.defaultMargins);
  771. if (margins) { // if (using 'margins' and/or 'defaultMargins')
  772. // margin and margins can both be present at the same time and must be combined
  773. info = {
  774. top: info.top + margins.top,
  775. right: info.right + margins.right,
  776. bottom: info.bottom + margins.bottom,
  777. left: info.left + margins.left
  778. };
  779. }
  780. me.setProp('margin-top', 0);
  781. me.setProp('margin-right', 0);
  782. me.setProp('margin-bottom', 0);
  783. me.setProp('margin-left', 0);
  784. }
  785. // cache the layout margins and tag them with the layout id:
  786. info.ownerId = ownerLayoutId;
  787. comp.margin$ = info;
  788. }
  789. info.width = info.left + info.right;
  790. info.height = info.top + info.bottom;
  791. }
  792. me.marginInfo = info;
  793. }
  794. return info;
  795. },
  796. <span id='Ext-layout-ContextItem-method-clearMarginCache'> /**
  797. </span> * clears the margin cache so that marginInfo get re-read from the dom on the next call to getMarginInfo()
  798. * This is needed in some special cases where the margins have changed since the last layout, making the cached
  799. * values invalid. For example collapsed window headers have different margin than expanded ones.
  800. */
  801. clearMarginCache: function() {
  802. delete this.marginInfo;
  803. delete this.target.margin$;
  804. },
  805. <span id='Ext-layout-ContextItem-method-getPaddingInfo'> /**
  806. </span> * Gets the padding information for the element as an object with left, top, right and
  807. * bottom properties holding padding size in pixels. This object is only read from the
  808. * DOM on first request and is cached.
  809. * @return {Object}
  810. */
  811. getPaddingInfo: function () {
  812. var me = this,
  813. info = me.paddingInfo;
  814. if (!info) {
  815. me.paddingInfo = info = me.checkCache('paddingInfo');
  816. }
  817. return info;
  818. },
  819. <span id='Ext-layout-ContextItem-method-getProp'> /**
  820. </span> * Gets a property of this object. Also tracks the current layout as dependent on this
  821. * property so that changes to it will trigger the layout to be recalculated.
  822. * @param {String} propName The property name that blocked the layout (e.g., 'width').
  823. * @return {Object} The property value or undefined if not yet set.
  824. */
  825. getProp: function (propName) {
  826. var me = this,
  827. result = me.props[propName];
  828. me.addTrigger(propName);
  829. return result;
  830. },
  831. <span id='Ext-layout-ContextItem-method-getDomProp'> /**
  832. </span> * Gets a property of this object if it is correct in the DOM. Also tracks the current
  833. * layout as dependent on this property so that DOM writes of it will trigger the
  834. * layout to be recalculated.
  835. * @param {String} propName The property name (e.g., 'width').
  836. * @return {Object} The property value or undefined if not yet set or is dirty.
  837. */
  838. getDomProp: function (propName) {
  839. var me = this,
  840. result = (me.dirty &amp;&amp; (propName in me.dirty)) ? undefined : me.props[propName];
  841. me.addTrigger(propName, true);
  842. return result;
  843. },
  844. <span id='Ext-layout-ContextItem-method-getStyle'> /**
  845. </span> * Returns a style for this item. Each style is read from the DOM only once on first
  846. * request and is then cached. If the value is an integer, it is parsed automatically
  847. * (so '5px' is not returned, but rather 5).
  848. *
  849. * @param {String} styleName The CSS style name.
  850. * @return {Object} The value of the DOM style (parsed as necessary).
  851. */
  852. getStyle: function (styleName) {
  853. var me = this,
  854. styles = me.styles,
  855. info, value;
  856. if (styleName in styles) {
  857. value = styles[styleName];
  858. } else {
  859. info = me.styleInfo[styleName];
  860. value = me.el.getStyle(styleName);
  861. if (info &amp;&amp; info.parseInt) {
  862. value = parseInt(value, 10) || 0;
  863. }
  864. styles[styleName] = value;
  865. }
  866. return value;
  867. },
  868. <span id='Ext-layout-ContextItem-method-getStyles'> /**
  869. </span> * Returns styles for this item. Each style is read from the DOM only once on first
  870. * request and is then cached. If the value is an integer, it is parsed automatically
  871. * (so '5px' is not returned, but rather 5).
  872. *
  873. * @param {String[]} styleNames The CSS style names.
  874. * @param {String[]} [altNames] The alternate names for the returned styles. If given,
  875. * these names must correspond one-for-one to the `styleNames`.
  876. * @return {Object} The values of the DOM styles (parsed as necessary).
  877. */
  878. getStyles: function (styleNames, altNames) {
  879. var me = this,
  880. styleCache = me.styles,
  881. values = {},
  882. hits = 0,
  883. n = styleNames.length,
  884. i, missing, missingAltNames, name, info, styleInfo, styles, value;
  885. altNames = altNames || styleNames;
  886. // We are optimizing this for all hits or all misses. If we hit on all styles, we
  887. // don't create a missing[]. If we miss on all styles, we also don't create one.
  888. for (i = 0; i &lt; n; ++i) {
  889. name = styleNames[i];
  890. if (name in styleCache) {
  891. values[altNames[i]] = styleCache[name];
  892. ++hits;
  893. if (i &amp;&amp; hits==1) { // if (first hit was after some misses)
  894. missing = styleNames.slice(0, i);
  895. missingAltNames = altNames.slice(0, i);
  896. }
  897. } else if (hits) {
  898. (missing || (missing = [])).push(name);
  899. (missingAltNames || (missingAltNames = [])).push(altNames[i]);
  900. }
  901. }
  902. if (hits &lt; n) {
  903. missing = missing || styleNames;
  904. missingAltNames = missingAltNames || altNames;
  905. styleInfo = me.styleInfo;
  906. styles = me.el.getStyle(missing);
  907. for (i = missing.length; i--; ) {
  908. name = missing[i];
  909. info = styleInfo[name];
  910. value = styles[name];
  911. if (info &amp;&amp; info.parseInt) {
  912. value = parseInt(value, 10) || 0;
  913. }
  914. values[missingAltNames[i]] = value;
  915. styleCache[name] = value;
  916. }
  917. }
  918. return values;
  919. },
  920. <span id='Ext-layout-ContextItem-method-hasProp'> /**
  921. </span> * Returns true if the given property has been set. This is equivalent to calling
  922. * {@link #getProp} and not getting an undefined result. In particular, this call
  923. * registers the current layout to be triggered by changes to this property.
  924. *
  925. * @param {String} propName The property name (e.g., 'width').
  926. * @return {Boolean}
  927. */
  928. hasProp: function (propName) {
  929. var value = this.getProp(propName);
  930. return typeof value != 'undefined';
  931. },
  932. <span id='Ext-layout-ContextItem-method-hasDomProp'> /**
  933. </span> * Returns true if the given property is correct in the DOM. This is equivalent to
  934. * calling {@link #getDomProp} and not getting an undefined result. In particular,
  935. * this call registers the current layout to be triggered by flushes of this property.
  936. *
  937. * @param {String} propName The property name (e.g., 'width').
  938. * @return {Boolean}
  939. */
  940. hasDomProp: function (propName) {
  941. var value = this.getDomProp(propName);
  942. return typeof value != 'undefined';
  943. },
  944. <span id='Ext-layout-ContextItem-method-invalidate'> /**
  945. </span> * Invalidates the component associated with this item. The layouts for this component
  946. * and all of its contained items will be re-run after first clearing any computed
  947. * values.
  948. *
  949. * If state needs to be carried forward beyond the invalidation, the `options` parameter
  950. * can be used.
  951. *
  952. * @param {Object} options An object describing how to handle the invalidation.
  953. * @param {Object} options.state An object to {@link Ext#apply} to the {@link #state}
  954. * of this item after invalidation clears all other properties.
  955. * @param {Function} options.before A function to call after the context data is cleared
  956. * and before the {@link Ext.layout.Layout#beginLayoutCycle} methods are called.
  957. * @param {Ext.layout.ContextItem} options.before.item This ContextItem.
  958. * @param {Object} options.before.options The options object passed to {@link #invalidate}.
  959. * @param {Function} options.after A function to call after the context data is cleared
  960. * and after the {@link Ext.layout.Layout#beginLayoutCycle} methods are called.
  961. * @param {Ext.layout.ContextItem} options.after.item This ContextItem.
  962. * @param {Object} options.after.options The options object passed to {@link #invalidate}.
  963. * @param {Object} options.scope The scope to use when calling the callback functions.
  964. */
  965. invalidate: function (options) {
  966. this.context.queueInvalidate(this, options);
  967. },
  968. markDirty: function () {
  969. if (++this.dirtyCount == 1) {
  970. // our first dirty property... queue us for flush
  971. this.context.queueFlush(this);
  972. }
  973. },
  974. onBoxMeasured: function () {
  975. var boxParent = this.boxParent,
  976. state = this.state;
  977. if (boxParent &amp;&amp; boxParent.widthModel.shrinkWrap &amp;&amp; !state.boxMeasured &amp;&amp; this.measuresBox) {
  978. // since an autoWidth boxParent is holding a width on itself to allow each
  979. // child to measure
  980. state.boxMeasured = 1; // best to only call once per child
  981. boxParent.boxChildMeasured();
  982. }
  983. },
  984. parseMargins: function (margins, defaultMargins) {
  985. if (margins === true) {
  986. margins = 5;
  987. }
  988. var type = typeof margins,
  989. ret;
  990. if (type == 'string' || type == 'number') {
  991. ret = Ext.util.Format.parseBox(margins);
  992. } else if (margins || defaultMargins) {
  993. ret = { top: 0, right: 0, bottom: 0, left: 0 }; // base defaults
  994. if (defaultMargins) {
  995. Ext.apply(ret, this.parseMargins(defaultMargins)); // + layout defaults
  996. }
  997. Ext.apply(ret, margins); // + config
  998. }
  999. return ret;
  1000. },
  1001. peek: function (propName) {
  1002. return this.props[propName];
  1003. },
  1004. <span id='Ext-layout-ContextItem-method-recoverProp'> /**
  1005. </span> * Recovers a property value from the last computation and restores its value and
  1006. * dirty state.
  1007. *
  1008. * @param {String} propName The name of the property to recover.
  1009. * @param {Object} oldProps The old &quot;props&quot; object from which to recover values.
  1010. * @param {Object} oldDirty The old &quot;dirty&quot; object from which to recover state.
  1011. */
  1012. recoverProp: function (propName, oldProps, oldDirty) {
  1013. var me = this,
  1014. props = me.props,
  1015. dirty;
  1016. if (propName in oldProps) {
  1017. props[propName] = oldProps[propName];
  1018. if (oldDirty &amp;&amp; propName in oldDirty) {
  1019. dirty = me.dirty || (me.dirty = {});
  1020. dirty[propName] = oldDirty[propName];
  1021. }
  1022. }
  1023. },
  1024. redo: function(deep) {
  1025. var me = this,
  1026. items, len, i;
  1027. me.revertProps(me.props);
  1028. if (deep &amp;&amp; me.wrapsComponent) {
  1029. // Rollback the state of child Components
  1030. if (me.childItems) {
  1031. for (i = 0, items = me.childItems, len = items.length; i &lt; len; i++) {
  1032. items[i].redo(deep);
  1033. }
  1034. }
  1035. // Rollback the state of child Elements
  1036. for (i = 0, items = me.children, len = items.length; i &lt; len; i++) {
  1037. items[i].redo();
  1038. }
  1039. }
  1040. },
  1041. revertProps: function (props) {
  1042. var name,
  1043. flushed = this.flushedProps,
  1044. reverted = {};
  1045. for (name in props) {
  1046. if (flushed.hasOwnProperty(name)) {
  1047. reverted[name] = props[name];
  1048. }
  1049. }
  1050. this.writeProps(reverted);
  1051. },
  1052. <span id='Ext-layout-ContextItem-method-setAttribute'> /**
  1053. </span> * Queue the setting of a DOM attribute on this ContextItem's target when next flushed.
  1054. */
  1055. setAttribute: function(name, value) {
  1056. var me = this;
  1057. if (!me.attributes) {
  1058. me.attributes = {};
  1059. }
  1060. me.attributes[name] = value;
  1061. me.markDirty();
  1062. },
  1063. setBox: function (box) {
  1064. var me = this;
  1065. if ('left' in box) {
  1066. me.setProp('x', box.left);
  1067. }
  1068. if ('top' in box) {
  1069. me.setProp('y', box.top);
  1070. }
  1071. // if sizeModel says we should not be setting these, the appropriate calls will be
  1072. // null operations... otherwise, we must set these values, so what we have in box
  1073. // is what we go with (undefined, NaN and no change are handled at a lower level):
  1074. me.setSize(box.width, box.height);
  1075. },
  1076. <span id='Ext-layout-ContextItem-method-setContentHeight'> /**
  1077. </span> * Sets the contentHeight property. If the component uses raw content, then only the
  1078. * measured height is acceptable.
  1079. *
  1080. * Calculated values can sometimes be NaN or undefined, which generally mean the
  1081. * calculation is not done. To indicate that such as value was passed, 0 is returned.
  1082. * Otherwise, 1 is returned.
  1083. *
  1084. * If the caller is not measuring (i.e., they are calculating) and the component has raw
  1085. * content, 1 is returned indicating that the caller is done.
  1086. */
  1087. setContentHeight: function (height, measured) {
  1088. if (!measured &amp;&amp; this.hasRawContent) {
  1089. return 1;
  1090. }
  1091. return this.setProp('contentHeight', height);
  1092. },
  1093. <span id='Ext-layout-ContextItem-method-setContentWidth'> /**
  1094. </span> * Sets the contentWidth property. If the component uses raw content, then only the
  1095. * measured width is acceptable.
  1096. *
  1097. * Calculated values can sometimes be NaN or undefined, which generally means that the
  1098. * calculation is not done. To indicate that such as value was passed, 0 is returned.
  1099. * Otherwise, 1 is returned.
  1100. *
  1101. * If the caller is not measuring (i.e., they are calculating) and the component has raw
  1102. * content, 1 is returned indicating that the caller is done.
  1103. */
  1104. setContentWidth: function (width, measured) {
  1105. if (!measured &amp;&amp; this.hasRawContent) {
  1106. return 1;
  1107. }
  1108. return this.setProp('contentWidth', width);
  1109. },
  1110. <span id='Ext-layout-ContextItem-method-setContentSize'> /**
  1111. </span> * Sets the contentWidth and contentHeight properties. If the component uses raw content,
  1112. * then only the measured values are acceptable.
  1113. *
  1114. * Calculated values can sometimes be NaN or undefined, which generally means that the
  1115. * calculation is not done. To indicate that either passed value was such a value, false
  1116. * returned. Otherwise, true is returned.
  1117. *
  1118. * If the caller is not measuring (i.e., they are calculating) and the component has raw
  1119. * content, true is returned indicating that the caller is done.
  1120. */
  1121. setContentSize: function (width, height, measured) {
  1122. return this.setContentWidth(width, measured) +
  1123. this.setContentHeight(height, measured) == 2;
  1124. },
  1125. <span id='Ext-layout-ContextItem-method-setProp'> /**
  1126. </span> * Sets a property value. This will unblock and/or trigger dependent layouts if the
  1127. * property value is being changed. Values of NaN and undefined are not accepted by
  1128. * this method.
  1129. *
  1130. * @param {String} propName The property name (e.g., 'width').
  1131. * @param {Object} value The new value of the property.
  1132. * @param {Boolean} dirty Optionally specifies if the value is currently in the DOM
  1133. * (default is `true` which indicates the value is not in the DOM and must be flushed
  1134. * at some point).
  1135. * @return {Number} 1 if this call specified the property value, 0 if not.
  1136. */
  1137. setProp: function (propName, value, dirty) {
  1138. var me = this,
  1139. valueType = typeof value,
  1140. borderBox, info;
  1141. if (valueType == 'undefined' || (valueType === 'number' &amp;&amp; isNaN(value))) {
  1142. return 0;
  1143. }
  1144. if (me.props[propName] === value) {
  1145. return 1;
  1146. }
  1147. me.props[propName] = value;
  1148. ++me.context.progressCount;
  1149. if (dirty === false) {
  1150. // if the prop is equivalent to what is in the DOM (we won't be writing it),
  1151. // we need to clear hard blocks (domBlocks) on that property.
  1152. me.fireTriggers('domTriggers', propName);
  1153. me.clearBlocks('domBlocks', propName);
  1154. } else {
  1155. info = me.styleInfo[propName];
  1156. if (info) {
  1157. if (!me.dirty) {
  1158. me.dirty = {};
  1159. }
  1160. if (propName == 'width' || propName == 'height') {
  1161. borderBox = me.isBorderBoxValue;
  1162. if (borderBox == null) {
  1163. me.isBorderBoxValue = borderBox = !!me.el.isBorderBox();
  1164. }
  1165. if (!borderBox) {
  1166. me.borderInfo || me.getBorderInfo();
  1167. me.paddingInfo || me.getPaddingInfo();
  1168. }
  1169. }
  1170. me.dirty[propName] = value;
  1171. me.markDirty();
  1172. }
  1173. }
  1174. // we always clear soft blocks on set
  1175. me.fireTriggers('triggers', propName);
  1176. me.clearBlocks('blocks', propName);
  1177. return 1;
  1178. },
  1179. <span id='Ext-layout-ContextItem-method-setHeight'> /**
  1180. </span> * Sets the height and constrains the height to min/maxHeight range.
  1181. *
  1182. * @param {Number} height The height.
  1183. * @param {Boolean} [dirty=true] Specifies if the value is currently in the DOM. A
  1184. * value of `false` indicates that the value is already in the DOM.
  1185. * @return {Number} The actual height after constraining.
  1186. */
  1187. setHeight: function (height, dirty /*, private {Boolean} force */) {
  1188. var me = this,
  1189. comp = me.target,
  1190. frameBody, frameInfo, padding;
  1191. if (height &lt; 0) {
  1192. height = 0;
  1193. }
  1194. if (!me.wrapsComponent) {
  1195. if (!me.setProp('height', height, dirty)) {
  1196. return NaN;
  1197. }
  1198. } else {
  1199. height = Ext.Number.constrain(height, comp.minHeight || 0, comp.maxHeight);
  1200. if (!me.setProp('height', height, dirty)) {
  1201. return NaN;
  1202. }
  1203. frameBody = me.frameBodyContext;
  1204. if (frameBody){
  1205. frameInfo = me.getFrameInfo();
  1206. frameBody.setHeight(height - frameInfo.height, dirty);
  1207. }
  1208. }
  1209. return height;
  1210. },
  1211. <span id='Ext-layout-ContextItem-method-setWidth'> /**
  1212. </span> * Sets the height and constrains the width to min/maxWidth range.
  1213. *
  1214. * @param {Number} width The width.
  1215. * @param {Boolean} [dirty=true] Specifies if the value is currently in the DOM. A
  1216. * value of `false` indicates that the value is already in the DOM.
  1217. * @return {Number} The actual width after constraining.
  1218. */
  1219. setWidth: function (width, dirty /*, private {Boolean} force */) {
  1220. var me = this,
  1221. comp = me.target,
  1222. frameBody, frameInfo, padding;
  1223. if (width &lt; 0) {
  1224. width = 0;
  1225. }
  1226. if (!me.wrapsComponent) {
  1227. if (!me.setProp('width', width, dirty)) {
  1228. return NaN;
  1229. }
  1230. } else {
  1231. width = Ext.Number.constrain(width, comp.minWidth || 0, comp.maxWidth);
  1232. if (!me.setProp('width', width, dirty)) {
  1233. return NaN;
  1234. }
  1235. //if ((frameBody = me.target.frameBody) &amp;&amp; (frameBody = me.getEl(frameBody))){
  1236. frameBody = me.frameBodyContext;
  1237. if (frameBody) {
  1238. frameInfo = me.getFrameInfo();
  1239. frameBody.setWidth(width - frameInfo.width, dirty);
  1240. }
  1241. /*if (owner.frameMC) {
  1242. frameContext = ownerContext.frameContext ||
  1243. (ownerContext.frameContext = ownerContext.getEl('frameMC'));
  1244. width += (frameContext.paddingInfo || frameContext.getPaddingInfo()).width;
  1245. }*/
  1246. }
  1247. return width;
  1248. },
  1249. setSize: function (width, height, dirty) {
  1250. this.setWidth(width, dirty);
  1251. this.setHeight(height, dirty);
  1252. },
  1253. translateProps: {
  1254. x: 'left',
  1255. y: 'top'
  1256. },
  1257. undo: function(deep) {
  1258. var me = this,
  1259. items, len, i;
  1260. me.revertProps(me.lastBox);
  1261. if (deep &amp;&amp; me.wrapsComponent) {
  1262. // Rollback the state of child Components
  1263. if (me.childItems) {
  1264. for (i = 0, items = me.childItems, len = items.length; i &lt; len; i++) {
  1265. items[i].undo(deep);
  1266. }
  1267. }
  1268. // Rollback the state of child Elements
  1269. for (i = 0, items = me.children, len = items.length; i &lt; len; i++) {
  1270. items[i].undo();
  1271. }
  1272. }
  1273. },
  1274. unsetProp: function (propName) {
  1275. var dirty = this.dirty;
  1276. delete this.props[propName];
  1277. if (dirty) {
  1278. delete dirty[propName];
  1279. }
  1280. },
  1281. writeProps: function(dirtyProps, flushing) {
  1282. if (!(dirtyProps &amp;&amp; typeof dirtyProps == 'object')) {
  1283. //&lt;debug warn&gt;
  1284. Ext.Logger.warn('writeProps expected dirtyProps to be an object');
  1285. //&lt;/debug&gt;
  1286. return;
  1287. }
  1288. var me = this,
  1289. el = me.el,
  1290. styles = {},
  1291. styleCount = 0, // used as a boolean, the exact count doesn't matter
  1292. styleInfo = me.styleInfo,
  1293. info,
  1294. propName,
  1295. numericValue,
  1296. dirtyX = 'x' in dirtyProps,
  1297. dirtyY = 'y' in dirtyProps,
  1298. x = dirtyProps.x,
  1299. y = dirtyProps.y,
  1300. width = dirtyProps.width,
  1301. height = dirtyProps.height,
  1302. isBorderBox = me.isBorderBoxValue,
  1303. target = me.target,
  1304. max = Math.max,
  1305. paddingWidth = 0,
  1306. paddingHeight = 0,
  1307. hasWidth, hasHeight, isAbsolute, scrollbarSize, style, targetEl;
  1308. // Process non-style properties:
  1309. if ('displayed' in dirtyProps) {
  1310. el.setDisplayed(dirtyProps.displayed);
  1311. }
  1312. // Unblock any hard blocks (domBlocks) and copy dom styles into 'styles'
  1313. for (propName in dirtyProps) {
  1314. if (flushing) {
  1315. me.fireTriggers('domTriggers', propName);
  1316. me.clearBlocks('domBlocks', propName);
  1317. me.flushedProps[propName] = 1;
  1318. }
  1319. info = styleInfo[propName];
  1320. if (info &amp;&amp; info.dom) {
  1321. // Numeric dirty values should have their associated suffix added
  1322. if (info.suffix &amp;&amp; (numericValue = parseInt(dirtyProps[propName], 10))) {
  1323. styles[propName] = numericValue + info.suffix;
  1324. }
  1325. // Non-numeric (eg &quot;auto&quot;) go in unchanged.
  1326. else {
  1327. styles[propName] = dirtyProps[propName];
  1328. }
  1329. ++styleCount;
  1330. }
  1331. }
  1332. // convert x/y into setPosition (for a component) or left/top styles (for an el)
  1333. if (dirtyX || dirtyY) {
  1334. if (target.isComponent) {
  1335. // Ensure we always pass the current coordinate in if one coordinate has not been dirtied by a calculation cycle.
  1336. target.setPosition(x||me.props.x, y||me.props.y);
  1337. } else {
  1338. // we wrap an element, so convert x/y to styles:
  1339. if (dirtyX) {
  1340. styles.left = x + 'px';
  1341. ++styleCount;
  1342. }
  1343. if (dirtyY) {
  1344. styles.top = y + 'px';
  1345. ++styleCount;
  1346. }
  1347. }
  1348. }
  1349. // Support for the content-box box model...
  1350. if (!isBorderBox &amp;&amp; (width &gt; 0 || height &gt; 0)) { // no need to subtract from 0
  1351. // The width and height values assume the border-box box model,
  1352. // so we must remove the padding &amp; border to calculate the content-box.
  1353. //&lt;debug&gt;
  1354. if (!(me.borderInfo &amp;&amp; me.paddingInfo)) {
  1355. throw Error(&quot;Needed to have gotten the borderInfo and paddingInfo when the width or height was setProp'd&quot;);
  1356. }
  1357. //&lt;/debug&gt;
  1358. if(!me.frameBodyContext) {
  1359. // Padding needs to be removed only if the element is not framed.
  1360. paddingWidth = me.paddingInfo.width;
  1361. paddingHeight = me.paddingInfo.height;
  1362. }
  1363. if (width) {
  1364. width = max(parseInt(width, 10) - (me.borderInfo.width + paddingWidth), 0);
  1365. styles.width = width + 'px';
  1366. ++styleCount;
  1367. }
  1368. if (height) {
  1369. height = max(parseInt(height, 10) - (me.borderInfo.height + paddingHeight), 0);
  1370. styles.height = height + 'px';
  1371. ++styleCount;
  1372. }
  1373. }
  1374. // IE9 strict subtracts the scrollbar size from the element size when the element
  1375. // is absolutely positioned and uses box-sizing: border-box. To workaround this
  1376. // issue we have to add the the scrollbar size.
  1377. //
  1378. // See http://social.msdn.microsoft.com/Forums/da-DK/iewebdevelopment/thread/47c5148f-a142-4a99-9542-5f230c78cb3b
  1379. //
  1380. if (me.wrapsComponent &amp;&amp; Ext.isIE9 &amp;&amp; Ext.isStrict) {
  1381. // when we set a width and we have a vertical scrollbar (overflowY), we need
  1382. // to add the scrollbar width... conversely for the height and overflowX
  1383. if ((hasWidth = width !== undefined &amp;&amp; me.hasOverflowY) ||
  1384. (hasHeight = height !== undefined &amp;&amp; me.hasOverflowX)) {
  1385. // check that the component is absolute positioned and border-box:
  1386. isAbsolute = me.isAbsolute;
  1387. if (isAbsolute === undefined) {
  1388. isAbsolute = false;
  1389. targetEl = me.target.getTargetEl();
  1390. style = targetEl.getStyle('position');
  1391. if (style == 'absolute') {
  1392. style = targetEl.getStyle('box-sizing');
  1393. isAbsolute = (style == 'border-box');
  1394. }
  1395. me.isAbsolute = isAbsolute; // cache it
  1396. }
  1397. if (isAbsolute) {
  1398. scrollbarSize = Ext.getScrollbarSize();
  1399. if (hasWidth) {
  1400. width = parseInt(width, 10) + scrollbarSize.width;
  1401. styles.width = width + 'px';
  1402. ++styleCount;
  1403. }
  1404. if (hasHeight) {
  1405. height = parseInt(height, 10) + scrollbarSize.height;
  1406. styles.height = height + 'px';
  1407. ++styleCount;
  1408. }
  1409. }
  1410. }
  1411. }
  1412. // we make only one call to setStyle to allow it to optimize itself:
  1413. if (styleCount) {
  1414. el.setStyle(styles);
  1415. }
  1416. }
  1417. }, function () {
  1418. var px = { dom: true, parseInt: true, suffix: 'px' },
  1419. isDom = { dom: true },
  1420. faux = { dom: false };
  1421. // If a property exists in styleInfo, it participates in some way with the DOM. It may
  1422. // be virtualized (like 'x' and y') and be indirect, but still requires a flush cycle
  1423. // to reach the DOM. Properties (like 'contentWidth' and 'contentHeight') have no real
  1424. // presence in the DOM and hence have no flush intanglements.
  1425. //
  1426. // For simple styles, the object value on the right contains properties that help in
  1427. // decoding values read by getStyle and preparing values to pass to setStyle.
  1428. //
  1429. this.prototype.styleInfo = {
  1430. childrenDone: faux,
  1431. componentChildrenDone: faux,
  1432. containerChildrenDone: faux,
  1433. containerLayoutDone: faux,
  1434. displayed: faux,
  1435. done: faux,
  1436. x: faux,
  1437. y: faux,
  1438. // For Ext.grid.ColumnLayout
  1439. columnWidthsDone: faux,
  1440. left: px,
  1441. top: px,
  1442. right: px,
  1443. bottom: px,
  1444. width: px,
  1445. height: px,
  1446. 'border-top-width': px,
  1447. 'border-right-width': px,
  1448. 'border-bottom-width': px,
  1449. 'border-left-width': px,
  1450. 'margin-top': px,
  1451. 'margin-right': px,
  1452. 'margin-bottom': px,
  1453. 'margin-left': px,
  1454. 'padding-top': px,
  1455. 'padding-right': px,
  1456. 'padding-bottom': px,
  1457. 'padding-left': px,
  1458. 'line-height': isDom,
  1459. display: isDom
  1460. };
  1461. });
  1462. </pre>
  1463. </body>
  1464. </html>