3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
18 Ext.Element.addMethods({
20 * Gets the x,y coordinates specified by the anchor position on the element.
21 * @param {String} [anchor='c'] The specified anchor position. See {@link #alignTo}
22 * for details on supported anchor positions.
23 * @param {Boolean} [local] True to get the local (element top/left-relative) anchor position instead
25 * @param {Object} [size] An object containing the size to use for calculating anchor position
26 * {width: (target width), height: (target height)} (defaults to the element's current size)
27 * @return {Number[]} [x, y] An array containing the element's x and y coordinates
29 getAnchorXY : function(anchor, local, s){
30 //Passing a different size is useful for pre-calculating anchors,
31 //especially for anchored animations that change the el size.
32 anchor = (anchor || "tl").toLowerCase();
36 vp = me.dom == document.body || me.dom == document,
37 w = s.width || vp ? Ext.Element.getViewWidth() : me.getWidth(),
38 h = s.height || vp ? Ext.Element.getViewHeight() : me.getHeight(),
42 scroll = me.getScroll(),
43 extraX = vp ? scroll.left : !local ? o[0] : 0,
44 extraY = vp ? scroll.top : !local ? o[1] : 0,
46 c : [r(w * 0.5), r(h * 0.5)],
58 return [xy[0] + extraX, xy[1] + extraY];
62 * Anchors an element to another element and realigns it when the window is resized.
63 * @param {String/HTMLElement/Ext.Element} element The element to align to.
64 * @param {String} position The position to align to.
65 * @param {Number[]} [offsets] Offset the positioning by [x, y]
66 * @param {Boolean/Object} [animate] True for the default animation or a standard Element animation config object
67 * @param {Boolean/Number} [monitorScroll] True to monitor body scroll and reposition. If this parameter
68 * is a number, it is used as the buffer delay (defaults to 50ms).
69 * @param {Function} [callback] The function to call after the animation finishes
70 * @return {Ext.Element} this
72 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
75 scroll = !Ext.isEmpty(monitorScroll),
77 Ext.fly(dom).alignTo(el, alignment, offsets, animate);
78 Ext.callback(callback, Ext.fly(dom));
80 anchor = this.getAnchor();
82 // previous listener anchor, remove it
89 Ext.EventManager.onWindowResize(action, null);
92 Ext.EventManager.on(window, 'scroll', action, null,
93 {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
95 action.call(me); // align immediately
100 * Remove any anchor to this element. See {@link #anchorTo}.
101 * @return {Ext.Element} this
103 removeAnchor : function(){
105 anchor = this.getAnchor();
107 if(anchor && anchor.fn){
108 Ext.EventManager.removeResizeListener(anchor.fn);
110 Ext.EventManager.un(window, 'scroll', anchor.fn);
118 getAnchor : function(){
119 var data = Ext.Element.data,
124 var anchor = data(dom, '_anchor');
127 anchor = data(dom, '_anchor', {});
132 getAlignVector: function(el, spec, offset) {
134 side = {t:"top", l:"left", r:"right", b: "bottom"},
135 thisRegion = me.getRegion(),
142 sourceClass: 'Ext.Element',
143 sourceMethod: 'getAlignVector',
144 msg: 'Attempted to align an element that doesn\'t exist'
149 elRegion = el.getRegion();
153 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
154 * supported position values.
155 * @param {String/HTMLElement/Ext.Element} element The element to align to.
156 * @param {String} [position="tl-bl?"] The position to align to (defaults to )
157 * @param {Number[]} [offsets] Offset the positioning by [x, y]
158 * @return {Number[]} [x, y]
160 getAlignToXY : function(el, p, o){
166 sourceClass: 'Ext.Element',
167 sourceMethod: 'getAlignToXY',
168 msg: 'Attempted to align an element that doesn\'t exist'
174 p = (!p || p == "?" ? "tl-bl?" : (!(/-/).test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase();
182 //constrain the aligned el to viewport if necessary
186 dw = Ext.Element.getViewWidth() -10, // 10px of margin for ie
187 dh = Ext.Element.getViewHeight()-10, // 10px of margin for ie
195 docElement = doc.documentElement,
197 scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,
198 scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,
199 c = false, //constrain to viewport
202 m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
207 sourceClass: 'Ext.Element',
208 sourceMethod: 'getAlignToXY',
212 msg: 'Attemmpted to align an element with an invalid position: "' + p + '"'
221 //Subtract the aligned el's internal xy from the target's offset xy
222 //plus custom offset to get the aligned el's new offset xy
223 a1 = me.getAnchorXY(p1, true);
224 a2 = el.getAnchorXY(p2, false);
226 x = a2[0] - a1[0] + o[0];
227 y = a2[1] - a1[1] + o[1];
233 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
234 //perpendicular to the vp border, allow the aligned el to slide on that border,
235 //otherwise swap the aligned el to the opposite border of the target.
237 p1x = p1.charAt(p1.length-1);
239 p2x = p2.charAt(p2.length-1);
240 swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
241 swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
244 if (x + w > dw + scrollX) {
245 x = swapX ? r.left-w : dw+scrollX-w;
248 x = swapX ? r.right : scrollX;
250 if (y + h > dh + scrollY) {
251 y = swapY ? r.top-h : dh+scrollY-h;
254 y = swapY ? r.bottom : scrollY;
261 * Aligns this element with another element relative to the specified anchor points. If the other element is the
262 * document it aligns it to the viewport.
263 * The position parameter is optional, and can be specified in any one of the following formats:
265 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
266 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
267 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
268 * deprecated in favor of the newer two anchor syntax below</i>.</li>
269 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
270 * element's anchor point, and the second value is used as the target's anchor point.</li>
272 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
273 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
274 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
275 * that specified in order to enforce the viewport constraints.
276 * Following are all of the supported anchor positions:
279 ----- -----------------------------
280 tl The top left corner (default)
281 t The center of the top edge
282 tr The top right corner
283 l The center of the left edge
284 c In the center of the element
285 r The center of the right edge
286 bl The bottom left corner
287 b The center of the bottom edge
288 br The bottom right corner
292 // align el to other-el using the default positioning ("tl-bl", non-constrained)
293 el.alignTo("other-el");
295 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
296 el.alignTo("other-el", "tr?");
298 // align the bottom right corner of el with the center left edge of other-el
299 el.alignTo("other-el", "br-l?");
301 // align the center of el with the bottom left corner of other-el and
302 // adjust the x position by -6 pixels (and the y position by 0)
303 el.alignTo("other-el", "c-bl", [-6, 0]);
305 * @param {String/HTMLElement/Ext.Element} element The element to align to.
306 * @param {String} [position="tl-bl?"] The position to align to
307 * @param {Number[]} [offsets] Offset the positioning by [x, y]
308 * @param {Boolean/Object} [animate] true for the default animation or a standard Element animation config object
309 * @return {Ext.Element} this
311 alignTo : function(element, position, offsets, animate){
313 return me.setXY(me.getAlignToXY(element, position, offsets),
314 me.anim && !!animate ? me.anim(animate) : false);
317 // private ==> used outside of core
318 adjustForConstraints : function(xy, parent) {
319 var vector = this.getConstrainVector(parent, xy);
328 * <p>Returns the <code>[X, Y]</code> vector by which this element must be translated to make a best attempt
329 * to constrain within the passed constraint. Returns <code>false</code> is this element does not need to be moved.</p>
330 * <p>Priority is given to constraining the top and left within the constraint.</p>
331 * <p>The constraint may either be an existing element into which this element is to be constrained, or
332 * an {@link Ext.util.Region Region} into which this element is to be constrained.</p>
333 * @param constrainTo {Mixed} The Element or {@link Ext.util.Region Region} into which this element is to be constrained.
334 * @param proposedPosition {Array} A proposed <code>[X, Y]</code> position to test for validity and to produce a vector for instead
335 * of using this Element's current position;
336 * @returns {Number[]/Boolean} <b>If</b> this element <i>needs</i> to be translated, an <code>[X, Y]</code>
337 * vector by which this element must be translated. Otherwise, <code>false</code>.
339 getConstrainVector: function(constrainTo, proposedPosition) {
340 if (!(constrainTo instanceof Ext.util.Region)) {
341 constrainTo = Ext.get(constrainTo).getViewRegion();
343 var thisRegion = this.getRegion(),
345 shadowSize = this.shadow && this.shadow.offset,
348 // Shift this region to occupy the proposed position
349 if (proposedPosition) {
350 thisRegion.translateBy(proposedPosition[0] - thisRegion.x, proposedPosition[1] - thisRegion.y);
353 // Reduce the constrain region to allow for shadow
354 // TODO: Rewrite the Shadow class. When that's done, get the extra for each side from the Shadow.
356 constrainTo.adjust(0, -shadowSize, -shadowSize, shadowSize);
359 // Constrain the X coordinate by however much this Element overflows
360 if (thisRegion.right > constrainTo.right) {
362 vector[0] = (constrainTo.right - thisRegion.right); // overflowed the right
364 if (thisRegion.left + vector[0] < constrainTo.left) {
366 vector[0] = (constrainTo.left - thisRegion.left); // overflowed the left
369 // Constrain the Y coordinate by however much this Element overflows
370 if (thisRegion.bottom > constrainTo.bottom) {
372 vector[1] = (constrainTo.bottom - thisRegion.bottom); // overflowed the bottom
374 if (thisRegion.top + vector[1] < constrainTo.top) {
376 vector[1] = (constrainTo.top - thisRegion.top); // overflowed the top
378 return overflowed ? vector : false;
382 * Calculates the x, y to center this element on the screen
383 * @return {Number[]} The x, y values [x, y]
385 getCenterXY : function(){
386 return this.getAlignToXY(document, 'c-c');
390 * Centers the Element in either the viewport, or another Element.
391 * @param {String/HTMLElement/Ext.Element} centerIn (optional) The element in which to center the element.
393 center : function(centerIn){
394 return this.alignTo(centerIn || document, 'c-c');