/**
* @class Ext.core.Element
*/
(function(){
var ELEMENT = Ext.core.Element,
LEFT = "left",
RIGHT = "right",
TOP = "top",
BOTTOM = "bottom",
POSITION = "position",
STATIC = "static",
RELATIVE = "relative",
AUTO = "auto",
ZINDEX = "z-index";
Ext.override(Ext.core.Element, {
/**
* Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
* @return {Number} The X position of the element
*/
getX : function(){
return ELEMENT.getX(this.dom);
},
/**
* Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
* @return {Number} The Y position of the element
*/
getY : function(){
return ELEMENT.getY(this.dom);
},
/**
* Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
* @return {Array} The XY position of the element
*/
getXY : function(){
return ELEMENT.getXY(this.dom);
},
/**
* Returns the offsets of this element from the passed element. Both element must be part of the DOM tree and not have display:none to have page coordinates.
* @param {Mixed} element The element to get the offsets from.
* @return {Array} The XY page offsets (e.g. [100, -200])
*/
getOffsetsTo : function(el){
var o = this.getXY(),
e = Ext.fly(el, '_internal').getXY();
return [o[0]-e[0],o[1]-e[1]];
},
/**
* Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
* @param {Number} The X position of the element
* @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
* @return {Ext.core.Element} this
*/
setX : function(x, animate){
return this.setXY([x, this.getY()], animate);
},
/**
* Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
* @param {Number} The Y position of the element
* @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
* @return {Ext.core.Element} this
*/
setY : function(y, animate){
return this.setXY([this.getX(), y], animate);
},
/**
* Sets the element's left position directly using CSS style (instead of {@link #setX}).
* @param {String} left The left CSS property value
* @return {Ext.core.Element} this
*/
setLeft : function(left){
this.setStyle(LEFT, this.addUnits(left));
return this;
},
/**
* Sets the element's top position directly using CSS style (instead of {@link #setY}).
* @param {String} top The top CSS property value
* @return {Ext.core.Element} this
*/
setTop : function(top){
this.setStyle(TOP, this.addUnits(top));
return this;
},
/**
* Sets the element's CSS right style.
* @param {String} right The right CSS property value
* @return {Ext.core.Element} this
*/
setRight : function(right){
this.setStyle(RIGHT, this.addUnits(right));
return this;
},
/**
* Sets the element's CSS bottom style.
* @param {String} bottom The bottom CSS property value
* @return {Ext.core.Element} this
*/
setBottom : function(bottom){
this.setStyle(BOTTOM, this.addUnits(bottom));
return this;
},
/**
* Sets the position of the element in page coordinates, regardless of how the element is positioned.
* The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
* @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
* @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
* @return {Ext.core.Element} this
*/
setXY: function(pos, animate) {
var me = this;
if (!animate || !me.anim) {
ELEMENT.setXY(me.dom, pos);
}
else {
if (!Ext.isObject(animate)) {
animate = {};
}
me.animate(Ext.applyIf({ to: { x: pos[0], y: pos[1] } }, animate));
}
return me;
},
/**
* Sets the position of the element in page coordinates, regardless of how the element is positioned.
* The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
* @param {Number} x X value for new position (coordinates are page-based)
* @param {Number} y Y value for new position (coordinates are page-based)
* @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
* @return {Ext.core.Element} this
*/
setLocation : function(x, y, animate){
return this.setXY([x, y], animate);
},
/**
* Sets the position of the element in page coordinates, regardless of how the element is positioned.
* The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
* @param {Number} x X value for new position (coordinates are page-based)
* @param {Number} y Y value for new position (coordinates are page-based)
* @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
* @return {Ext.core.Element} this
*/
moveTo : function(x, y, animate){
return this.setXY([x, y], animate);
},
/**
* Gets the left X coordinate
* @param {Boolean} local True to get the local css position instead of page coordinate
* @return {Number}
*/
getLeft : function(local){
return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;
},
/**
* Gets the right X coordinate of the element (element X position + element width)
* @param {Boolean} local True to get the local css position instead of page coordinate
* @return {Number}
*/
getRight : function(local){
var me = this;
return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;
},
/**
* Gets the top Y coordinate
* @param {Boolean} local True to get the local css position instead of page coordinate
* @return {Number}
*/
getTop : function(local) {
return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;
},
/**
* Gets the bottom Y coordinate of the element (element Y position + element height)
* @param {Boolean} local True to get the local css position instead of page coordinate
* @return {Number}
*/
getBottom : function(local){
var me = this;
return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;
},
/**
* Initializes positioning on this element. If a desired position is not passed, it will make the
* the element positioned relative IF it is not already positioned.
* @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
* @param {Number} zIndex (optional) The zIndex to apply
* @param {Number} x (optional) Set the page X position
* @param {Number} y (optional) Set the page Y position
*/
position : function(pos, zIndex, x, y) {
var me = this;
if (!pos && me.isStyle(POSITION, STATIC)){
me.setStyle(POSITION, RELATIVE);
} else if(pos) {
me.setStyle(POSITION, pos);
}
if (zIndex){
me.setStyle(ZINDEX, zIndex);
}
if (x || y) {
me.setXY([x || false, y || false]);
}
},
/**
* Clear positioning back to the default when the document was loaded
* @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
* @return {Ext.core.Element} this
*/
clearPositioning : function(value){
value = value || '';
this.setStyle({
left : value,
right : value,
top : value,
bottom : value,
"z-index" : "",
position : STATIC
});
return this;
},
/**
* Gets an object with all CSS positioning properties. Useful along with setPostioning to get
* snapshot before performing an update and then restoring the element.
* @return {Object}
*/
getPositioning : function(){
var l = this.getStyle(LEFT);
var t = this.getStyle(TOP);
return {
"position" : this.getStyle(POSITION),
"left" : l,
"right" : l ? "" : this.getStyle(RIGHT),
"top" : t,
"bottom" : t ? "" : this.getStyle(BOTTOM),
"z-index" : this.getStyle(ZINDEX)
};
},
/**
* Set positioning with an object returned by getPositioning().
* @param {Object} posCfg
* @return {Ext.core.Element} this
*/
setPositioning : function(pc){
var me = this,
style = me.dom.style;
me.setStyle(pc);
if(pc.right == AUTO){
style.right = "";
}
if(pc.bottom == AUTO){
style.bottom = "";
}
return me;
},
/**
* Translates the passed page coordinates into left/top css values for this element
* @param {Number/Array} x The page x or an array containing [x, y]
* @param {Number} y (optional) The page y, required if x is not an array
* @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
*/
translatePoints : function(x, y){
y = isNaN(x[1]) ? y : x[1];
x = isNaN(x[0]) ? x : x[0];
var me = this,
relative = me.isStyle(POSITION, RELATIVE),
o = me.getXY(),
l = parseInt(me.getStyle(LEFT), 10),
t = parseInt(me.getStyle(TOP), 10);
l = !isNaN(l) ? l : (relative ? 0 : me.dom.offsetLeft);
t = !isNaN(t) ? t : (relative ? 0 : me.dom.offsetTop);
return {left: (x - o[0] + l), top: (y - o[1] + t)};
},
/**
* Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
* @param {Object} box The box to fill {x, y, width, height}
* @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
* @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
* @return {Ext.core.Element} this
*/
setBox: function(box, adjust, animate) {
var me = this,
w = box.width,
h = box.height;
if ((adjust && !me.autoBoxAdjust) && !me.isBorderBox()) {
w -= (me.getBorderWidth("lr") + me.getPadding("lr"));
h -= (me.getBorderWidth("tb") + me.getPadding("tb"));
}
me.setBounds(box.x, box.y, w, h, animate);
return me;
},
/**
* Return an object defining the area of this Element which can be passed to {@link #setBox} to
* set another Element's size/location to match this element.
* @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
* @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
* @return {Object} box An object in the format
{
x: <Element's X position>,
y: <Element's Y position>,
width: <Element's width>,
height: <Element's height>,
bottom: <Element's lower bound>,
right: <Element's rightmost bound>
}
* The returned object may also be addressed as an Array where index 0 contains the X position
* and index 1 contains the Y position. So the result may also be used for {@link #setXY}
*/
getBox: function(contentBox, local) {
var me = this,
xy,
left,
top,
getBorderWidth = me.getBorderWidth,
getPadding = me.getPadding,
l,
r,
t,
b;
if (!local) {
xy = me.getXY();
} else {
left = parseInt(me.getStyle("left"), 10) || 0;
top = parseInt(me.getStyle("top"), 10) || 0;
xy = [left, top];
}
var el = me.dom,
w = el.offsetWidth,
h = el.offsetHeight,
bx;
if (!contentBox) {
bx = {
x: xy[0],
y: xy[1],
0: xy[0],
1: xy[1],
width: w,
height: h
};
} else {
l = getBorderWidth.call(me, "l") + getPadding.call(me, "l");
r = getBorderWidth.call(me, "r") + getPadding.call(me, "r");
t = getBorderWidth.call(me, "t") + getPadding.call(me, "t");
b = getBorderWidth.call(me, "b") + getPadding.call(me, "b");
bx = {
x: xy[0] + l,
y: xy[1] + t,
0: xy[0] + l,
1: xy[1] + t,
width: w - (l + r),
height: h - (t + b)
};
}
bx.right = bx.x + bx.width;
bx.bottom = bx.y + bx.height;
return bx;
},
/**
* Move this element relative to its current position.
* @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
* @param {Number} distance How far to move the element in pixels
* @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
* @return {Ext.core.Element} this
*/
move: function(direction, distance, animate) {
var me = this,
xy = me.getXY(),
x = xy[0],
y = xy[1],
left = [x - distance, y],
right = [x + distance, y],
top = [x, y - distance],
bottom = [x, y + distance],
hash = {
l: left,
left: left,
r: right,
right: right,
t: top,
top: top,
up: top,
b: bottom,
bottom: bottom,
down: bottom
};
direction = direction.toLowerCase();
me.moveTo(hash[direction][0], hash[direction][1], animate);
},
/**
* Quick set left and top adding default units
* @param {String} left The left CSS property value
* @param {String} top The top CSS property value
* @return {Ext.core.Element} this
*/
setLeftTop: function(left, top) {
var me = this,
style = me.dom.style;
style.left = me.addUnits(left);
style.top = me.addUnits(top);
return me;
},
/**
* Returns the region of this element.
* The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
* @return {Region} A Ext.util.Region containing "top, left, bottom, right" member data.
*/
getRegion: function() {
return this.getPageBox(true);
},
/**
* Returns the content region of this element. That is the region within the borders and padding.
* @return {Region} A Ext.util.Region containing "top, left, bottom, right" member data.
*/
getViewRegion: function() {
var pos = this.getXY(),
top = pos[1] + this.getBorderWidth('t') + this.getPadding('t'),
left = pos[0] + this.getBorderWidth('l') + this.getPadding('l'),
size = this.getViewSize();
return new Ext.util.Region(top, left + size.width - 1 - this.getPadding('lr'), top + size.height - 1 - this.getPadding('tb'), left);
},
/**
* Return an object defining the area of this Element which can be passed to {@link #setBox} to
* set another Element's size/location to match this element.
* @param {Boolean} asRegion(optional) If true an Ext.util.Region will be returned
* @return {Object} box An object in the format
{
x: <Element's X position>,
y: <Element's Y position>,
width: <Element's width>,
height: <Element's height>,
bottom: <Element's lower bound>,
right: <Element's rightmost bound>
}
* The returned object may also be addressed as an Array where index 0 contains the X position
* and index 1 contains the Y position. So the result may also be used for {@link #setXY}
*/
getPageBox : function(getRegion) {
var me = this,
el = me.dom,
isDoc = el === document.body,
w = isDoc ? Ext.core.Element.getViewWidth() : el.offsetWidth,
h = isDoc ? Ext.core.Element.getViewHeight() : el.offsetHeight,
xy = me.getXY(),
t = xy[1],
r = xy[0] + w - 1,
b = xy[1] + h - 1,
l = xy[0];
if (getRegion) {
return new Ext.util.Region(t, r, b, l);
}
else {
return {
left: l,
top: t,
width: w,
height: h,
right: r,
bottom: b
};
}
},
/**
* Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
* @param {Number} x X value for new position (coordinates are page-based)
* @param {Number} y Y value for new position (coordinates are page-based)
* @param {Mixed} width The new width. This may be one of:
* - A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels)
* - A String used to set the CSS width style. Animation may not be used.
*
* @param {Mixed} height The new height. This may be one of:
* - A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels)
* - A String used to set the CSS height style. Animation may not be used.
*
* @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
* @return {Ext.core.Element} this
*/
setBounds: function(x, y, width, height, animate) {
var me = this;
if (!animate || !me.anim) {
me.setSize(width, height);
me.setLocation(x, y);
} else {
if (!Ext.isObject(animate)) {
animate = {};
}
me.animate(Ext.applyIf({
to: {
x: x,
y: y,
width: me.adjustWidth(width),
height: me.adjustHeight(height)
}
}, animate));
}
return me;
},
/**
* Sets the element's position and size the specified region. If animation is true then width, height, x and y will be animated concurrently.
* @param {Ext.util.Region} region The region to fill
* @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
* @return {Ext.core.Element} this
*/
setRegion: function(region, animate) {
return this.setBounds(region.left, region.top, region.right - region.left, region.bottom - region.top, animate);
}
});
})();