Element.alignment.html 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  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-dom-Element'>/**
  19. </span> * @class Ext.dom.Element
  20. */
  21. Ext.dom.Element.override((function() {
  22. var doc = document,
  23. win = window,
  24. alignRe = /^([a-z]+)-([a-z]+)(\?)?$/,
  25. round = Math.round;
  26. return {
  27. <span id='Ext-dom-Element-method-getAnchorXY'> /**
  28. </span> * Gets the x,y coordinates specified by the anchor position on the element.
  29. * @param {String} [anchor='c'] The specified anchor position. See {@link #alignTo}
  30. * for details on supported anchor positions.
  31. * @param {Boolean} [local] True to get the local (element top/left-relative) anchor position instead
  32. * of page coordinates
  33. * @param {Object} [size] An object containing the size to use for calculating anchor position
  34. * {width: (target width), height: (target height)} (defaults to the element's current size)
  35. * @return {Number[]} [x, y] An array containing the element's x and y coordinates
  36. */
  37. getAnchorXY: function(anchor, local, mySize) {
  38. //Passing a different size is useful for pre-calculating anchors,
  39. //especially for anchored animations that change the el size.
  40. anchor = (anchor || &quot;tl&quot;).toLowerCase();
  41. mySize = mySize || {};
  42. var me = this,
  43. isViewport = me.dom == doc.body || me.dom == doc,
  44. myWidth = mySize.width || isViewport ? Ext.dom.Element.getViewWidth() : me.getWidth(),
  45. myHeight = mySize.height || isViewport ? Ext.dom.Element.getViewHeight() : me.getHeight(),
  46. xy,
  47. myPos = me.getXY(),
  48. scroll = me.getScroll(),
  49. extraX = isViewport ? scroll.left : !local ? myPos[0] : 0,
  50. extraY = isViewport ? scroll.top : !local ? myPos[1] : 0;
  51. // Calculate anchor position.
  52. // Test most common cases for picker alignment first.
  53. switch (anchor) {
  54. case 'tl' : xy = [ 0, 0];
  55. break;
  56. case 'bl' : xy = [ 0, myHeight];
  57. break;
  58. case 'tr' : xy = [ myWidth, 0];
  59. break;
  60. case 'c' : xy = [ round(myWidth * 0.5), round(myHeight * 0.5)];
  61. break;
  62. case 't' : xy = [ round(myWidth * 0.5), 0];
  63. break;
  64. case 'l' : xy = [ 0, round(myHeight * 0.5)];
  65. break;
  66. case 'r' : xy = [ myWidth, round(myHeight * 0.5)];
  67. break;
  68. case 'b' : xy = [ round(myWidth * 0.5), myHeight];
  69. break;
  70. case 'br' : xy = [ myWidth, myHeight];
  71. }
  72. return [xy[0] + extraX, xy[1] + extraY];
  73. },
  74. <span id='Ext-dom-Element-method-getAlignToXY'> /**
  75. </span> * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
  76. * supported position values.
  77. * @param {String/HTMLElement/Ext.Element} element The element to align to.
  78. * @param {String} [position=&quot;tl-bl?&quot;] The position to align to (defaults to )
  79. * @param {Number[]} [offsets] Offset the positioning by [x, y]
  80. * @return {Number[]} [x, y]
  81. */
  82. getAlignToXY : function(alignToEl, posSpec, offset) {
  83. alignToEl = Ext.get(alignToEl);
  84. if (!alignToEl || !alignToEl.dom) {
  85. //&lt;debug&gt;
  86. Ext.Error.raise({
  87. sourceClass: 'Ext.dom.Element',
  88. sourceMethod: 'getAlignToXY',
  89. msg: 'Attempted to align an element that doesn\'t exist'
  90. });
  91. //&lt;/debug&gt;
  92. }
  93. offset = offset || [0,0];
  94. posSpec = (!posSpec || posSpec == &quot;?&quot; ? &quot;tl-bl?&quot; : (!(/-/).test(posSpec) &amp;&amp; posSpec !== &quot;&quot; ? &quot;tl-&quot; + posSpec : posSpec || &quot;tl-bl&quot;)).toLowerCase();
  95. var me = this,
  96. myPosition,
  97. alignToElPosition,
  98. x,
  99. y,
  100. myWidth,
  101. myHeight,
  102. alignToElRegion,
  103. viewportWidth = Ext.dom.Element.getViewWidth() - 10, // 10px of margin for ie
  104. viewportHeight = Ext.dom.Element.getViewHeight() - 10, // 10px of margin for ie
  105. p1y,
  106. p1x,
  107. p2y,
  108. p2x,
  109. swapY,
  110. swapX,
  111. docElement = doc.documentElement,
  112. docBody = doc.body,
  113. scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0),// + 5, WHY was 5 ever added?
  114. scrollY = (docElement.scrollTop || docBody.scrollTop || 0),// + 5, It means align will fail if the alignTo el was at less than 5,5
  115. constrain, //constrain to viewport
  116. align1,
  117. align2,
  118. alignMatch = posSpec.match(alignRe);
  119. //&lt;debug&gt;
  120. if (!alignMatch) {
  121. Ext.Error.raise({
  122. sourceClass: 'Ext.dom.Element',
  123. sourceMethod: 'getAlignToXY',
  124. el: alignToEl,
  125. position: posSpec,
  126. offset: offset,
  127. msg: 'Attemmpted to align an element with an invalid position: &quot;' + posSpec + '&quot;'
  128. });
  129. }
  130. //&lt;/debug&gt;
  131. align1 = alignMatch[1];
  132. align2 = alignMatch[2];
  133. constrain = !!alignMatch[3];
  134. //Subtract the aligned el's internal xy from the target's offset xy
  135. //plus custom offset to get this Element's new offset xy
  136. myPosition = me.getAnchorXY(align1, true);
  137. alignToElPosition = alignToEl.getAnchorXY(align2, false);
  138. x = alignToElPosition[0] - myPosition[0] + offset[0];
  139. y = alignToElPosition[1] - myPosition[1] + offset[1];
  140. // If position spec ended with a &quot;?&quot;, then constrain to viewport is necessary
  141. if (constrain) {
  142. myWidth = me.getWidth();
  143. myHeight = me.getHeight();
  144. alignToElRegion = alignToEl.getRegion();
  145. //If we are at a viewport boundary and the aligned el is anchored on a target border that is
  146. //perpendicular to the vp border, allow the aligned el to slide on that border,
  147. //otherwise swap the aligned el to the opposite border of the target.
  148. p1y = align1.charAt(0);
  149. p1x = align1.charAt(align1.length - 1);
  150. p2y = align2.charAt(0);
  151. p2x = align2.charAt(align2.length - 1);
  152. swapY = ((p1y == &quot;t&quot; &amp;&amp; p2y == &quot;b&quot;) || (p1y == &quot;b&quot; &amp;&amp; p2y == &quot;t&quot;));
  153. swapX = ((p1x == &quot;r&quot; &amp;&amp; p2x == &quot;l&quot;) || (p1x == &quot;l&quot; &amp;&amp; p2x == &quot;r&quot;));
  154. if (x + myWidth &gt; viewportWidth + scrollX) {
  155. x = swapX ? alignToElRegion.left - myWidth : viewportWidth + scrollX - myWidth;
  156. }
  157. if (x &lt; scrollX) {
  158. x = swapX ? alignToElRegion.right : scrollX;
  159. }
  160. if (y + myHeight &gt; viewportHeight + scrollY) {
  161. y = swapY ? alignToElRegion.top - myHeight : viewportHeight + scrollY - myHeight;
  162. }
  163. if (y &lt; scrollY) {
  164. y = swapY ? alignToElRegion.bottom : scrollY;
  165. }
  166. }
  167. return [x,y];
  168. },
  169. <span id='Ext-dom-Element-method-anchorTo'> /**
  170. </span> * Anchors an element to another element and realigns it when the window is resized.
  171. * @param {String/HTMLElement/Ext.Element} element The element to align to.
  172. * @param {String} position The position to align to.
  173. * @param {Number[]} [offsets] Offset the positioning by [x, y]
  174. * @param {Boolean/Object} [animate] True for the default animation or a standard Element animation config object
  175. * @param {Boolean/Number} [monitorScroll] True to monitor body scroll and reposition. If this parameter
  176. * is a number, it is used as the buffer delay (defaults to 50ms).
  177. * @param {Function} [callback] The function to call after the animation finishes
  178. * @return {Ext.Element} this
  179. */
  180. anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback) {
  181. var me = this,
  182. dom = me.dom,
  183. scroll = !Ext.isEmpty(monitorScroll),
  184. action = function() {
  185. Ext.fly(dom).alignTo(el, alignment, offsets, animate);
  186. Ext.callback(callback, Ext.fly(dom));
  187. },
  188. anchor = this.getAnchor();
  189. // previous listener anchor, remove it
  190. this.removeAnchor();
  191. Ext.apply(anchor, {
  192. fn: action,
  193. scroll: scroll
  194. });
  195. Ext.EventManager.onWindowResize(action, null);
  196. if (scroll) {
  197. Ext.EventManager.on(win, 'scroll', action, null,
  198. {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
  199. }
  200. action.call(me); // align immediately
  201. return me;
  202. },
  203. <span id='Ext-dom-Element-method-removeAnchor'> /**
  204. </span> * Remove any anchor to this element. See {@link #anchorTo}.
  205. * @return {Ext.dom.Element} this
  206. */
  207. removeAnchor : function() {
  208. var me = this,
  209. anchor = this.getAnchor();
  210. if (anchor &amp;&amp; anchor.fn) {
  211. Ext.EventManager.removeResizeListener(anchor.fn);
  212. if (anchor.scroll) {
  213. Ext.EventManager.un(win, 'scroll', anchor.fn);
  214. }
  215. delete anchor.fn;
  216. }
  217. return me;
  218. },
  219. getAlignVector: function(el, spec, offset) {
  220. var me = this,
  221. myPos = me.getXY(),
  222. alignedPos = me.getAlignToXY(el, spec, offset);
  223. el = Ext.get(el);
  224. //&lt;debug&gt;
  225. if (!el || !el.dom) {
  226. Ext.Error.raise({
  227. sourceClass: 'Ext.dom.Element',
  228. sourceMethod: 'getAlignVector',
  229. msg: 'Attempted to align an element that doesn\'t exist'
  230. });
  231. }
  232. //&lt;/debug&gt;
  233. alignedPos[0] -= myPos[0];
  234. alignedPos[1] -= myPos[1];
  235. return alignedPos;
  236. },
  237. <span id='Ext-dom-Element-method-alignTo'> /**
  238. </span> * Aligns this element with another element relative to the specified anchor points. If the other element is the
  239. * document it aligns it to the viewport. The position parameter is optional, and can be specified in any one of
  240. * the following formats:
  241. *
  242. * - **Blank**: Defaults to aligning the element's top-left corner to the target's bottom-left corner (&quot;tl-bl&quot;).
  243. * - **One anchor (deprecated)**: The passed anchor position is used as the target element's anchor point.
  244. * The element being aligned will position its top-left corner (tl) to that point. *This method has been
  245. * deprecated in favor of the newer two anchor syntax below*.
  246. * - **Two anchors**: If two values from the table below are passed separated by a dash, the first value is used as the
  247. * element's anchor point, and the second value is used as the target's anchor point.
  248. *
  249. * In addition to the anchor points, the position parameter also supports the &quot;?&quot; character. If &quot;?&quot; is passed at the end of
  250. * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
  251. * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
  252. * that specified in order to enforce the viewport constraints.
  253. * Following are all of the supported anchor positions:
  254. *
  255. * &lt;pre&gt;
  256. * Value Description
  257. * ----- -----------------------------
  258. * tl The top left corner (default)
  259. * t The center of the top edge
  260. * tr The top right corner
  261. * l The center of the left edge
  262. * c In the center of the element
  263. * r The center of the right edge
  264. * bl The bottom left corner
  265. * b The center of the bottom edge
  266. * br The bottom right corner
  267. * &lt;/pre&gt;
  268. *
  269. * Example Usage:
  270. *
  271. * // align el to other-el using the default positioning (&quot;tl-bl&quot;, non-constrained)
  272. * el.alignTo(&quot;other-el&quot;);
  273. *
  274. * // align the top left corner of el with the top right corner of other-el (constrained to viewport)
  275. * el.alignTo(&quot;other-el&quot;, &quot;tr?&quot;);
  276. *
  277. * // align the bottom right corner of el with the center left edge of other-el
  278. * el.alignTo(&quot;other-el&quot;, &quot;br-l?&quot;);
  279. *
  280. * // align the center of el with the bottom left corner of other-el and
  281. * // adjust the x position by -6 pixels (and the y position by 0)
  282. * el.alignTo(&quot;other-el&quot;, &quot;c-bl&quot;, [-6, 0]);
  283. *
  284. * @param {String/HTMLElement/Ext.Element} element The element to align to.
  285. * @param {String} [position=&quot;tl-bl?&quot;] The position to align to
  286. * @param {Number[]} [offsets] Offset the positioning by [x, y]
  287. * @param {Boolean/Object} [animate] true for the default animation or a standard Element animation config object
  288. * @return {Ext.Element} this
  289. */
  290. alignTo: function(element, position, offsets, animate) {
  291. var me = this;
  292. return me.setXY(me.getAlignToXY(element, position, offsets),
  293. me.anim &amp;&amp; !!animate ? me.anim(animate) : false);
  294. },
  295. <span id='Ext-dom-Element-method-getConstrainVector'> /**
  296. </span> * Returns the `[X, Y]` vector by which this element must be translated to make a best attempt
  297. * to constrain within the passed constraint. Returns `false` is this element does not need to be moved.
  298. *
  299. * Priority is given to constraining the top and left within the constraint.
  300. *
  301. * The constraint may either be an existing element into which this element is to be constrained, or
  302. * an {@link Ext.util.Region Region} into which this element is to be constrained.
  303. *
  304. * @param {Ext.Element/Ext.util.Region} constrainTo The Element or Region into which this element is to be constrained.
  305. * @param {Number[]} proposedPosition A proposed `[X, Y]` position to test for validity and to produce a vector for instead
  306. * of using this Element's current position;
  307. * @returns {Number[]/Boolean} **If** this element *needs* to be translated, an `[X, Y]`
  308. * vector by which this element must be translated. Otherwise, `false`.
  309. */
  310. getConstrainVector: function(constrainTo, proposedPosition) {
  311. if (!(constrainTo instanceof Ext.util.Region)) {
  312. constrainTo = Ext.get(constrainTo).getViewRegion();
  313. }
  314. var thisRegion = this.getRegion(),
  315. vector = [0, 0],
  316. shadowSize = (this.shadow &amp;&amp; !this.shadowDisabled) ? this.shadow.getShadowSize() : undefined,
  317. overflowed = false;
  318. // Shift this region to occupy the proposed position
  319. if (proposedPosition) {
  320. thisRegion.translateBy(proposedPosition[0] - thisRegion.x, proposedPosition[1] - thisRegion.y);
  321. }
  322. // Reduce the constrain region to allow for shadow
  323. if (shadowSize) {
  324. constrainTo.adjust(shadowSize[0], -shadowSize[1], -shadowSize[2], shadowSize[3]);
  325. }
  326. // Constrain the X coordinate by however much this Element overflows
  327. if (thisRegion.right &gt; constrainTo.right) {
  328. overflowed = true;
  329. vector[0] = (constrainTo.right - thisRegion.right); // overflowed the right
  330. }
  331. if (thisRegion.left + vector[0] &lt; constrainTo.left) {
  332. overflowed = true;
  333. vector[0] = (constrainTo.left - thisRegion.left); // overflowed the left
  334. }
  335. // Constrain the Y coordinate by however much this Element overflows
  336. if (thisRegion.bottom &gt; constrainTo.bottom) {
  337. overflowed = true;
  338. vector[1] = (constrainTo.bottom - thisRegion.bottom); // overflowed the bottom
  339. }
  340. if (thisRegion.top + vector[1] &lt; constrainTo.top) {
  341. overflowed = true;
  342. vector[1] = (constrainTo.top - thisRegion.top); // overflowed the top
  343. }
  344. return overflowed ? vector : false;
  345. },
  346. <span id='Ext-dom-Element-method-getCenterXY'> /**
  347. </span> * Calculates the x, y to center this element on the screen
  348. * @return {Number[]} The x, y values [x, y]
  349. */
  350. getCenterXY : function(){
  351. return this.getAlignToXY(doc, 'c-c');
  352. },
  353. <span id='Ext-dom-Element-method-center'> /**
  354. </span> * Centers the Element in either the viewport, or another Element.
  355. * @param {String/HTMLElement/Ext.Element} [centerIn] The element in which to center the element.
  356. */
  357. center : function(centerIn){
  358. return this.alignTo(centerIn || doc, 'c-c');
  359. }
  360. };
  361. }()));</pre>
  362. </body>
  363. </html>