Anchor.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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-Anchor'>/**
  19. </span> * This is a layout that enables anchoring of contained elements relative to the container's dimensions.
  20. * If the container is resized, all anchored items are automatically rerendered according to their
  21. * `{@link #anchor}` rules.
  22. *
  23. * This class is intended to be extended or created via the {@link Ext.container.AbstractContainer#layout layout}: 'anchor'
  24. * config, and should generally not need to be created directly via the new keyword.
  25. *
  26. * AnchorLayout does not have any direct config options (other than inherited ones). By default,
  27. * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
  28. * container using the AnchorLayout can supply an anchoring-specific config property of `anchorSize`.
  29. *
  30. * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
  31. * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
  32. * logic if necessary.
  33. *
  34. * @example
  35. * Ext.create('Ext.Panel', {
  36. * width: 500,
  37. * height: 400,
  38. * title: &quot;AnchorLayout Panel&quot;,
  39. * layout: 'anchor',
  40. * renderTo: Ext.getBody(),
  41. * items: [
  42. * {
  43. * xtype: 'panel',
  44. * title: '75% Width and 20% Height',
  45. * anchor: '75% 20%'
  46. * },
  47. * {
  48. * xtype: 'panel',
  49. * title: 'Offset -300 Width &amp; -200 Height',
  50. * anchor: '-300 -200'
  51. * },
  52. * {
  53. * xtype: 'panel',
  54. * title: 'Mixed Offset and Percent',
  55. * anchor: '-250 20%'
  56. * }
  57. * ]
  58. * });
  59. */
  60. Ext.define('Ext.layout.container.Anchor', {
  61. /* Begin Definitions */
  62. alias: 'layout.anchor',
  63. extend: 'Ext.layout.container.Container',
  64. alternateClassName: 'Ext.layout.AnchorLayout',
  65. /* End Definitions */
  66. type: 'anchor',
  67. manageOverflow: 2,
  68. renderTpl: [
  69. '{%this.renderBody(out,values);this.renderPadder(out,values)%}'
  70. ],
  71. <span id='Ext-layout-container-Anchor-cfg-anchor'> /**
  72. </span> * @cfg {String} anchor
  73. *
  74. * This configuation option is to be applied to **child `items`** of a container managed by
  75. * this layout (ie. configured with `layout:'anchor'`).
  76. *
  77. * This value is what tells the layout how an item should be anchored to the container. `items`
  78. * added to an AnchorLayout accept an anchoring-specific config property of **anchor** which is a string
  79. * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
  80. * The following types of anchor values are supported:
  81. *
  82. * - **Percentage** : Any value between 1 and 100, expressed as a percentage.
  83. *
  84. * The first anchor is the percentage width that the item should take up within the container, and the
  85. * second is the percentage height. For example:
  86. *
  87. * // two values specified
  88. * anchor: '100% 50%' // render item complete width of the container and
  89. * // 1/2 height of the container
  90. * // one value specified
  91. * anchor: '100%' // the width value; the height will default to auto
  92. *
  93. * - **Offsets** : Any positive or negative integer value.
  94. *
  95. * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
  96. * and the second is the offset from the bottom edge. For example:
  97. *
  98. * // two values specified
  99. * anchor: '-50 -100' // render item the complete width of the container
  100. * // minus 50 pixels and
  101. * // the complete height minus 100 pixels.
  102. * // one value specified
  103. * anchor: '-50' // anchor value is assumed to be the right offset value
  104. * // bottom offset will default to 0
  105. *
  106. * - **Sides** : Valid values are `right` (or `r`) and `bottom` (or `b`).
  107. *
  108. * Either the container must have a fixed size or an anchorSize config value defined at render time in
  109. * order for these to have any effect.
  110. *
  111. * - **Mixed** :
  112. *
  113. * Anchor values can also be mixed as needed. For example, to render the width offset from the container
  114. * right edge by 50 pixels and 75% of the container's height use:
  115. *
  116. * anchor: '-50 75%'
  117. */
  118. <span id='Ext-layout-container-Anchor-cfg-defaultAnchor'> /**
  119. </span> * @cfg {String} defaultAnchor
  120. * Default anchor for all child **container** items applied if no anchor or specific width is set on the child item.
  121. */
  122. defaultAnchor: '100%',
  123. parseAnchorRE: /^(r|right|b|bottom)$/i,
  124. beginLayout: function (ownerContext) {
  125. var me = this,
  126. dimensions = 0,
  127. anchorSpec, childContext, childItems, i, length, target;
  128. me.callParent(arguments);
  129. childItems = ownerContext.childItems; // populated by callParent
  130. length = childItems.length;
  131. for (i = 0; i &lt; length; ++i) {
  132. childContext = childItems[i];
  133. anchorSpec = childContext.target.anchorSpec;
  134. if (anchorSpec) {
  135. if (childContext.widthModel.calculated &amp;&amp; anchorSpec.right) {
  136. dimensions |= 1;
  137. }
  138. if (childContext.heightModel.calculated &amp;&amp; anchorSpec.bottom) {
  139. dimensions |= 2;
  140. }
  141. if (dimensions == 3) { // if (both dimensions in play)
  142. break;
  143. }
  144. }
  145. }
  146. ownerContext.anchorDimensions = dimensions;
  147. // Work around WebKit RightMargin bug. We're going to inline-block all the children
  148. // only ONCE and remove it when we're done
  149. if (!Ext.supports.RightMargin &amp;&amp; !me.rightMarginCleanerFn) {
  150. target = ownerContext.targetContext.el; // targetContext is added by superclass
  151. me.rightMarginCleanerFn = Ext.Element.getRightMarginFixCleaner(target);
  152. target.addCls(Ext.baseCSSPrefix + 'inline-children');
  153. }
  154. //&lt;debug&gt;
  155. me.sanityCheck(ownerContext);
  156. //&lt;/debug&gt;
  157. },
  158. calculate: function (ownerContext) {
  159. var me = this,
  160. containerSize = me.getContainerSize(ownerContext);
  161. if (ownerContext.anchorDimensions !== ownerContext.state.calculatedAnchors) {
  162. me.calculateAnchors(ownerContext, containerSize);
  163. }
  164. if (ownerContext.hasDomProp('containerChildrenDone')) {
  165. // Once the child layouts are done we can determine the content sizes...
  166. if (!containerSize.gotAll) {
  167. me.done = false;
  168. }
  169. me.calculateContentSize(ownerContext, ownerContext.anchorDimensions);
  170. if (me.done) {
  171. me.calculateOverflow(ownerContext, containerSize, ownerContext.anchorDimensions);
  172. return;
  173. }
  174. }
  175. me.done = false;
  176. },
  177. calculateAnchors: function (ownerContext, containerSize) {
  178. var me = this,
  179. childItems = ownerContext.childItems,
  180. length = childItems.length,
  181. gotHeight = containerSize.gotHeight,
  182. gotWidth = containerSize.gotWidth,
  183. ownerHeight = containerSize.height,
  184. ownerWidth = containerSize.width,
  185. state = ownerContext.state,
  186. calculatedAnchors = (gotWidth ? 1 : 0) | (gotHeight ? 2 : 0),
  187. anchorSpec, childContext, childMargins, height, i, width;
  188. state.calculatedAnchors = (state.calculatedAnchors || 0) | calculatedAnchors;
  189. for (i = 0; i &lt; length; i++) {
  190. childContext = childItems[i];
  191. childMargins = childContext.getMarginInfo();
  192. anchorSpec = childContext.target.anchorSpec;
  193. // Check widthModel in case &quot;defaults&quot; has applied an anchor to a component
  194. // that also has width (which must win). If we did not make this check in this
  195. // way, we would attempt to calculate a width where it had been configured.
  196. //
  197. if (gotWidth &amp;&amp; childContext.widthModel.calculated) {
  198. width = anchorSpec.right(ownerWidth) - childMargins.width;
  199. width = me.adjustWidthAnchor(width, childContext);
  200. childContext.setWidth(width);
  201. }
  202. // Repeat for height
  203. if (gotHeight &amp;&amp; childContext.heightModel.calculated) {
  204. height = anchorSpec.bottom(ownerHeight) - childMargins.height;
  205. height = me.adjustHeightAnchor(height, childContext);
  206. childContext.setHeight(height);
  207. }
  208. }
  209. },
  210. finishedLayout: function (ownerContext) {
  211. var cleanerFn = this.rightMarginCleanerFn;
  212. if (cleanerFn) {
  213. delete this.rightMarginCleanerFn;
  214. ownerContext.targetContext.el.removeCls(Ext.baseCSSPrefix + 'inline-children');
  215. cleanerFn();
  216. }
  217. },
  218. //&lt;debug&gt;
  219. sanityCheck: function (ownerContext) {
  220. var shrinkWrapWidth = ownerContext.widthModel.shrinkWrap,
  221. shrinkWrapHeight = ownerContext.heightModel.shrinkWrap,
  222. children = ownerContext.childItems,
  223. anchorSpec, comp, childContext,
  224. i, length;
  225. for (i = 0, length = children.length; i &lt; length; ++i) {
  226. childContext = children[i];
  227. comp = childContext.target;
  228. anchorSpec = comp.anchorSpec;
  229. if (anchorSpec) {
  230. if (childContext.widthModel.calculated &amp;&amp; anchorSpec.right) {
  231. if (shrinkWrapWidth) {
  232. Ext.log({
  233. level: 'warn',
  234. msg: 'Right anchor on '+comp.id+' in shrinkWrap width container'
  235. });
  236. }
  237. }
  238. if (childContext.heightModel.calculated &amp;&amp; anchorSpec.bottom) {
  239. if (shrinkWrapHeight) {
  240. Ext.log({
  241. level: 'warn',
  242. msg: 'Bottom anchor on '+comp.id+' in shrinkWrap height container'
  243. });
  244. }
  245. }
  246. }
  247. }
  248. },
  249. //&lt;/debug&gt;
  250. // private
  251. anchorFactory: {
  252. offset: function (delta) {
  253. return function(v) {
  254. return v + delta;
  255. };
  256. },
  257. ratio: function (ratio) {
  258. return function(v) {
  259. return Math.floor(v * ratio);
  260. };
  261. },
  262. standard: function (diff) {
  263. return function(v) {
  264. return v - diff;
  265. };
  266. }
  267. },
  268. parseAnchor: function(a, start, cstart) {
  269. if (a &amp;&amp; a != 'none') {
  270. var factory = this.anchorFactory,
  271. delta;
  272. if (this.parseAnchorRE.test(a)) {
  273. return factory.standard(cstart - start);
  274. }
  275. if (a.indexOf('%') != -1) {
  276. return factory.ratio(parseFloat(a.replace('%', '')) * 0.01);
  277. }
  278. delta = parseInt(a, 10);
  279. if (!isNaN(delta)) {
  280. return factory.offset(delta);
  281. }
  282. }
  283. return null;
  284. },
  285. // private
  286. adjustWidthAnchor: function(value, childContext) {
  287. return value;
  288. },
  289. // private
  290. adjustHeightAnchor: function(value, childContext) {
  291. return value;
  292. },
  293. configureItem: function(item) {
  294. var me = this,
  295. owner = me.owner,
  296. anchor= item.anchor,
  297. anchorsArray,
  298. anchorWidth,
  299. anchorHeight;
  300. me.callParent(arguments);
  301. if (!item.anchor &amp;&amp; item.items &amp;&amp; !Ext.isNumber(item.width) &amp;&amp; !(Ext.isIE6 &amp;&amp; Ext.isStrict)) {
  302. item.anchor = anchor = me.defaultAnchor;
  303. }
  304. <span id='Ext-container-Container-cfg-anchorSize'> /**
  305. </span> * @cfg {Number/Object} anchorSize
  306. * Defines the anchoring size of container.
  307. * Either a number to define the width of the container or an object with `width` and `height` fields.
  308. * @member Ext.container.Container
  309. */
  310. if (owner.anchorSize) {
  311. if (typeof owner.anchorSize == 'number') {
  312. anchorWidth = owner.anchorSize;
  313. } else {
  314. anchorWidth = owner.anchorSize.width;
  315. anchorHeight = owner.anchorSize.height;
  316. }
  317. } else {
  318. anchorWidth = owner.initialConfig.width;
  319. anchorHeight = owner.initialConfig.height;
  320. }
  321. if (anchor) {
  322. // cache all anchor values
  323. anchorsArray = anchor.split(' ');
  324. item.anchorSpec = {
  325. right: me.parseAnchor(anchorsArray[0], item.initialConfig.width, anchorWidth),
  326. bottom: me.parseAnchor(anchorsArray[1], item.initialConfig.height, anchorHeight)
  327. };
  328. }
  329. },
  330. sizePolicy: {
  331. '': {
  332. setsWidth: 0,
  333. setsHeight: 0
  334. },
  335. b: {
  336. setsWidth: 0,
  337. setsHeight: 1
  338. },
  339. r: {
  340. '': {
  341. setsWidth: 1,
  342. setsHeight: 0
  343. },
  344. b: {
  345. setsWidth: 1,
  346. setsHeight: 1
  347. }
  348. }
  349. },
  350. getItemSizePolicy: function (item) {
  351. var anchorSpec = item.anchorSpec,
  352. key = '',
  353. policy = this.sizePolicy,
  354. sizeModel;
  355. if (anchorSpec) {
  356. sizeModel = this.owner.getSizeModel();
  357. if (anchorSpec.right &amp;&amp; !sizeModel.width.shrinkWrap) {
  358. policy = policy.r;
  359. }
  360. if (anchorSpec.bottom &amp;&amp; !sizeModel.height.shrinkWrap) {
  361. key = 'b';
  362. }
  363. }
  364. return policy[key];
  365. }
  366. });
  367. </pre>
  368. </body>
  369. </html>