/**
* @class Ext.Element
*/
Ext.Element.addMethods(function(){
// local style camelizing for speed
var propCache = {},
camelRe = /(-[a-z])/gi,
classReCache = {},
view = document.defaultView,
EL = Ext.Element,
PADDING = "padding",
MARGIN = "margin",
BORDER = "border",
LEFT = "-left",
RIGHT = "-right",
TOP = "-top",
BOTTOM = "-bottom",
WIDTH = "-width",
// special markup used throughout Ext when box wrapping elements
borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM};
// private
function camelFn(m, a) {
return a.charAt(1).toUpperCase();
}
// private (needs to be called => addStyles.call(this, sides, styles))
function addStyles(sides, styles){
var val = 0;
Ext.each(sides.match(/\w/g), function(s) {
if (s = parseInt(this.getStyle(styles[s]), 10)) {
val += Math.abs(s);
}
},
this);
return val;
}
function chkCache(prop) {
return propCache[prop] || (propCache[prop] = prop.replace(camelRe, camelFn))
}
return {
// private ==> used by Fx
adjustWidth : function(width) {
var me = this;
if(typeof width == "number" && me.autoBoxAdjust && !me.isBorderBox()){
width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
width = width < 0 ? 0 : width;
}
return width;
},
// private ==> used by Fx
adjustHeight : function(height) {
var me = this;
if(typeof height == "number" && me.autoBoxAdjust && !me.isBorderBox()){
height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
height = height < 0 ? 0 : height;
}
return height;
},
/**
* Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
* @param {String/Array} className The CSS class to add, or an array of classes
* @return {Ext.Element} this
*/
addClass : function(className){
var me = this;
Ext.each(className, function(v) {
me.dom.className += (!me.hasClass(v) && v ? " " + v : "");
});
return me;
},
/**
* Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
* @param {String/Array} className The CSS class to add, or an array of classes
* @return {Ext.Element} this
*/
radioClass : function(className){
Ext.each(this.dom.parentNode.childNodes, function(v) {
if(v.nodeType == 1) {
Ext.get(v).removeClass(className);
}
});
return this.addClass(className);
},
/**
* Removes one or more CSS classes from the element.
* @param {String/Array} className The CSS class to remove, or an array of classes
* @return {Ext.Element} this
*/
removeClass : function(className){
var me = this;
if (me.dom.className) {
Ext.each(className, function(v) {
me.dom.className = me.dom.className.replace(
classReCache[v] = classReCache[v] || new RegExp('(?:^|\\s+)' + v + '(?:\\s+|$)', "g"),
" ");
});
}
return me;
},
/**
* Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
* @param {String} className The CSS class to toggle
* @return {Ext.Element} this
*/
toggleClass : function(className){
return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
},
/**
* Checks if the specified CSS class exists on this element's DOM node.
* @param {String} className The CSS class to check for
* @return {Boolean} True if the class exists, else false
*/
hasClass : function(className){
return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
},
/**
* Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
* @param {String} oldClassName The CSS class to replace
* @param {String} newClassName The replacement CSS class
* @return {Ext.Element} this
*/
replaceClass : function(oldClassName, newClassName){
return this.removeClass(oldClassName).addClass(newClassName);
},
isStyle : function(style, val) {
// var ret = false;
// style = this.getStyle(style);
// Ext.each(Ext.toArray(arguments,1),function(s){
// if(style == s) return false; // stop iterating.
// });
// return ret;
return this.getStyle(style) == val;
},
/**
* Normalizes currentStyle and computedStyle.
* @param {String} property The style property whose value is returned.
* @return {String} The current value of the style property for this element.
*/
getStyle : function(){
return view && view.getComputedStyle ?
function(prop){
var el = this.dom,
v,
cs;
if(el == document) return null;
prop = prop == 'float' ? 'cssFloat' : prop;
return (v = el.style[prop]) ? v :
(cs = view.getComputedStyle(el, "")) ? cs[chkCache(prop)] : null;
} :
function(prop){
var el = this.dom,
m,
cs;
if(el == document) return null;
if (prop == 'opacity') {
if (el.style.filter.match) {
if(m = el.style.filter.match(/alpha\(opacity=(.*)\)/i)){
var fv = parseFloat(m[1]);
if(!isNaN(fv)){
return fv ? fv / 100 : 0;
}
}
}
return 1;
}
prop = prop == 'float' ? 'styleFloat' : prop;
return el.style[prop] || ((cs = el.currentStyle) ? cs[chkCache(prop)] : null);
};
}(),
/**
* Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
* are convert to standard 6 digit hex color.
* @param {String} attr The css attribute
* @param {String} defaultValue The default value to use when a valid color isn't found
* @param {String} prefix (optional) defaults to #. Use an empty string when working with
* color anims.
*/
getColor : function(attr, defaultValue, prefix){
var v = this.getStyle(attr),
color = prefix || "#";
if(!v || v == "transparent" || v == "inherit") {
return defaultValue;
}
if (/^r/.test(v)) {
Ext.each(v.slice(4, v.length -1).split(","), function(s) {
h = (s * 1).toString(16);
color += h < 16 ? "0" + h : h;
});
} else {
color += v.replace("#","").replace(/^(\w)(\w)(\w)$/, "$1$1$2$2$3$3");
}
return color.length > 5 ? color.toLowerCase() : defaultValue;
},
/**
* Wrapper for setting style properties, also takes single object parameter of multiple styles.
* @param {String/Object} property The style property to be set, or an object of multiple styles.
* @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
* @return {Ext.Element} this
*/
setStyle : function(prop, value){
var tmp,
style,
camel;
if (!Ext.isObject(prop)) {
tmp = {};
tmp[prop] = value;
prop = tmp;
}
for (style in prop) {
value = prop[style];
camel = chkCache(style);
camel == 'opacity' ?
this.setOpacity(value) :
this.dom.style[camel] = value;
}
return this;
},
/**
* Set the opacity of the element
* @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
* @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
* @return {Ext.Element} this
*/
setOpacity : function(opacity, animate){
var me = this,
s = me.dom.style;
if(!animate || !me.anim){
if (Ext.isIE) {
s.zoom = 1;
s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
(opacity == 1 ? "" : " alpha(opacity=" + opacity * 100 + ")");
} else {
s.opacity = opacity;
}
}else{
me.anim({opacity: {to: opacity}}, me.preanim(arguments, 1), null, .35, 'easeIn');
}
return me;
},
/**
* Clears any opacity settings from this element. Required in some cases for IE.
* @return {Ext.Element} this
*/
clearOpacity : function(){
var style = this.dom.style;
if (window.ActiveXObject) {
if(typeof style.filter == 'string' && (/alpha/i).test(style.filter)){
style.filter = "";
}
} else {
style.opacity = "";
style["-moz-opacity"] = "";
style["-khtml-opacity"] = "";
}
return this;
},
/**
* Returns the offset height of the element
* @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
* @return {Number} The element's height
*/
getHeight : function(contentHeight){
var h = this.dom.offsetHeight || 0;
h = !contentHeight ? h : h - this.getBorderWidth("tb") - this.getPadding("tb");
return h < 0 ? 0 : h;
},
/**
* Returns the offset width of the element
* @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
* @return {Number} The element's width
*/
getWidth : function(contentWidth){
var w = this.dom.offsetWidth || 0;
w = !contentWidth ? w : w - this.getBorderWidth("lr") - this.getPadding("lr");
return w < 0 ? 0 : w;
},
/**
* Set the width of this Element.
* @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 {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
* @return {Ext.Element} this
*/
setWidth : function(width, animate){
var me = this;
width = me.adjustWidth(width);
!animate || !me.anim ?
me.dom.style.width = me.addUnits(width) :
me.anim({width : {to : width}}, me.preanim(arguments, 1));
return me;
},
/**
* Set the height of this Element.
* @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.Element} this
*/
setHeight : function(height, animate){
var me = this;
height = me.adjustHeight(height);
!animate || !me.anim ?
me.dom.style.height = me.addUnits(height) :
me.anim({height : {to : height}}, me.preanim(arguments, 1));
return me;
},
/**
* Gets the width of the border(s) for the specified side(s)
* @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
* passing lr would get the border (l)eft width + the border (r)ight width.
* @return {Number} The width of the sides passed added together
*/
getBorderWidth : function(side){
return addStyles.call(this, side, borders);
},
/**
* Gets the width of the padding(s) for the specified side(s)
* @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
* passing lr would get the padding (l)eft + the padding (r)ight.
* @return {Number} The padding of the sides passed added together
*/
getPadding : function(side){
return addStyles.call(this, side, paddings);
},
/**
* Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
* @return {Ext.Element} this
*/
clip : function(){
var me = this;
if(!me.isClipped){
me.isClipped = true;
me.originalClip = {
o: me.getStyle("overflow"),
x: me.getStyle("overflow-x"),
y: me.getStyle("overflow-y")
};
me.setStyle("overflow", "hidden");
me.setStyle("overflow-x", "hidden");
me.setStyle("overflow-y", "hidden");
}
return me;
},
/**
* Return clipping (overflow) to original clipping before clip() was called
* @return {Ext.Element} this
*/
unclip : function(){
var me = this;
if(me.isClipped){
me.isClipped = false;
var o = me.originalClip;
if(o.o){me.setStyle("overflow", o.o);}
if(o.x){me.setStyle("overflow-x", o.x);}
if(o.y){me.setStyle("overflow-y", o.y);}
}
return me;
},
addStyles : addStyles,
margins : margins
}
}()
);