Extends the Element native object to include methods useful in measuring dimensions.
(function(){
var getStylesList = function(styles, planes){
var list = [];
Object.each(planes, function(directions){
Object.each(directions, function(edge){
styles.each(function(style){
if (style == 'border') list.push(style + '-' + edge + '-width');
else list.push(style + '-' + edge);
});
});
});
return list;
};
var calculateEdgeSize = function(edge, styles){
var total = 0;
Object.each(styles, function(value, style){
if (style.test(edge)) total += value.toInt();
});
return total;
};
Element.implement({
measure: function(fn){
var visibility = function(el){
return !!(!el || el.offsetHeight || el.offsetWidth);
};
if (visibility(this)) return fn.apply(this);
var parent = this.getParent(),
restorers = [],
toMeasure = [];
while (!visibility(parent) && parent != document.body){
toMeasure.push(parent.expose());
parent = parent.getParent();
}
var restore = this.expose();
var result = fn.apply(this);
restore();
toMeasure.each(function(restore){
restore();
});
return result;
},
expose: function(){
if (this.getStyle('display') != 'none') return function(){};
var before = this.style.cssText;
this.setStyles({
display: 'block',
position: 'absolute',
visibility: 'hidden'
});
return function(){
this.style.cssText = before;
}.bind(this);
},
getDimensions: function(options){
options = Object.merge({computeSize: false}, options);
var dim = {};
var getSize = function(el, options){
return (options.computeSize) ? el.getComputedSize(options) : el.getSize();
};
var parent = this.getParent('body');
if (parent && this.getStyle('display') == 'none'){
dim = this.measure(function(){
return getSize(this, options);
});
} else if (parent){
try { //safari sometimes crashes here, so catch it
dim = getSize(this, options);
}catch(e){}
} else {
dim = {x: 0, y: 0};
}
return Object.append(dim, (dim.x || dim.x === 0) ? {
width: dim.x,
height: dim.y
} : {
x: dim.width,
y: dim.height
}
);
},
getComputedSize: function(options){
<1.2compat> legacy support for my stupid spelling error
if (options && options.plains) options.planes = options.plains;
</1.2compat>
options = Object.merge({
styles: ['padding','border'],
planes: {
height: ['top','bottom'],
width: ['left','right']
},
mode: 'both'
}, options);
var styles = {},
size = {width: 0, height: 0};
switch (options.mode){
case 'vertical':
delete size.width;
delete options.planes.width;
break;
case 'horizontal':
delete size.height;
delete options.planes.height;
break;
}
getStylesList(options.styles, options.planes).each(function(style){
styles[style] = this.getStyle(style).toInt();
}, this);
Object.each(options.planes, function(edges, plane){
var capitalized = plane.capitalize();
styles[plane] = this.getStyle(plane).toInt();
size['total' + capitalized] = styles[plane];
edges.each(function(edge){
var edgesize = calculateEdgeSize(edge, styles);
size['computed' + edge.capitalize()] = edgesize;
size['total' + capitalized] += edgesize;
});
}, this);
return Object.append(size, styles);
}
});
})();