blob: f108b2d33e391638b36425634dee251c454015f5 [file] [log] [blame]
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.html.layout");
dojo.require("dojo.html.common");
dojo.require("dojo.html.style");
dojo.require("dojo.html.display");
dojo.html.sumAncestorProperties = function(/* HTMLElement */node, /* string */prop){
// summary
// Returns the sum of the passed property on all ancestors of node.
node = dojo.byId(node);
if(!node){ return 0; } // FIXME: throw an error?
var retVal = 0;
while(node){
if(dojo.html.getComputedStyle(node, 'position') == 'fixed'){
return 0;
}
var val = node[prop];
if(val){
retVal += val - 0;
if(node==dojo.body()){ break; }// opera and khtml #body & #html has the same values, we only need one value
}
node = node.parentNode;
}
return retVal; // integer
}
dojo.html.setStyleAttributes = function(/* HTMLElement */node, /* string */attributes) {
// summary
// allows a dev to pass a string similar to what you'd pass in style="", and apply it to a node.
node = dojo.byId(node);
var splittedAttribs=attributes.replace(/(;)?\s*$/, "").split(";");
for(var i=0; i<splittedAttribs.length; i++){
var nameValue=splittedAttribs[i].split(":");
var name=nameValue[0].replace(/\s*$/, "").replace(/^\s*/, "").toLowerCase();
var value=nameValue[1].replace(/\s*$/, "").replace(/^\s*/, "");
switch(name){
case "opacity":
dojo.html.setOpacity(node, value);
break;
case "content-height":
dojo.html.setContentBox(node, {height: value});
break;
case "content-width":
dojo.html.setContentBox(node, {width: value});
break;
case "outer-height":
dojo.html.setMarginBox(node, {height: value});
break;
case "outer-width":
dojo.html.setMarginBox(node, {width: value});
break;
default:
node.style[dojo.html.toCamelCase(name)]=value;
}
}
}
dojo.html.boxSizing = {
MARGIN_BOX: "margin-box",
BORDER_BOX: "border-box",
PADDING_BOX: "padding-box",
CONTENT_BOX: "content-box"
};
dojo.html.getAbsolutePosition = dojo.html.abs = function(/* HTMLElement */node, /* boolean? */includeScroll, /* string? */boxType){
// summary
// Gets the absolute position of the passed element based on the document itself.
node = dojo.byId(node, node.ownerDocument);
var ret = {
x: 0,
y: 0
};
var bs = dojo.html.boxSizing;
if(!boxType) { boxType = bs.CONTENT_BOX; }
var nativeBoxType = 2; //BORDER box
var targetBoxType;
switch(boxType){
case bs.MARGIN_BOX:
targetBoxType = 3;
break;
case bs.BORDER_BOX:
targetBoxType = 2;
break;
case bs.PADDING_BOX:
default:
targetBoxType = 1;
break;
case bs.CONTENT_BOX:
targetBoxType = 0;
break;
}
var h = dojo.render.html;
var db = document["body"]||document["documentElement"];
if(h.ie){
with(node.getBoundingClientRect()){
ret.x = left-2;
ret.y = top-2;
}
}else if(document.getBoxObjectFor){
// mozilla
nativeBoxType = 1; //getBoxObjectFor return padding box coordinate
try{
var bo = document.getBoxObjectFor(node);
ret.x = bo.x - dojo.html.sumAncestorProperties(node, "scrollLeft");
ret.y = bo.y - dojo.html.sumAncestorProperties(node, "scrollTop");
}catch(e){
// squelch
}
}else{
if(node["offsetParent"]){
var endNode;
// in Safari, if the node is an absolutely positioned child of
// the body and the body has a margin the offset of the child
// and the body contain the body's margins, so we need to end
// at the body
if( (h.safari)&&
(node.style.getPropertyValue("position") == "absolute")&&
(node.parentNode == db)){
endNode = db;
}else{
endNode = db.parentNode;
}
//TODO: set correct nativeBoxType for safari/konqueror
if(node.parentNode != db){
var nd = node;
if(dojo.render.html.opera){ nd = db; }
ret.x -= dojo.html.sumAncestorProperties(nd, "scrollLeft");
ret.y -= dojo.html.sumAncestorProperties(nd, "scrollTop");
}
var curnode = node;
do{
var n = curnode["offsetLeft"];
//FIXME: ugly hack to workaround the submenu in
//popupmenu2 does not shown up correctly in opera.
//Someone have a better workaround?
if(!h.opera || n>0){
ret.x += isNaN(n) ? 0 : n;
}
var m = curnode["offsetTop"];
ret.y += isNaN(m) ? 0 : m;
curnode = curnode.offsetParent;
}while((curnode != endNode)&&(curnode != null));
}else if(node["x"]&&node["y"]){
ret.x += isNaN(node.x) ? 0 : node.x;
ret.y += isNaN(node.y) ? 0 : node.y;
}
}
// account for document scrolling!
if(includeScroll){
var scroll = dojo.html.getScroll();
ret.y += scroll.top;
ret.x += scroll.left;
}
var extentFuncArray=[dojo.html.getPaddingExtent, dojo.html.getBorderExtent, dojo.html.getMarginExtent];
if(nativeBoxType > targetBoxType){
for(var i=targetBoxType;i<nativeBoxType;++i){
ret.y += extentFuncArray[i](node, 'top');
ret.x += extentFuncArray[i](node, 'left');
}
}else if(nativeBoxType < targetBoxType){
for(var i=targetBoxType;i>nativeBoxType;--i){
ret.y -= extentFuncArray[i-1](node, 'top');
ret.x -= extentFuncArray[i-1](node, 'left');
}
}
ret.top = ret.y;
ret.left = ret.x;
return ret; // object
}
dojo.html.isPositionAbsolute = function(/* HTMLElement */node){
// summary
// Returns true if the element is absolutely positioned.
return (dojo.html.getComputedStyle(node, 'position') == 'absolute'); // boolean
}
dojo.html._sumPixelValues = function(/* HTMLElement */node, selectors, autoIsZero){
var total = 0;
for(var x=0; x<selectors.length; x++){
total += dojo.html.getPixelValue(node, selectors[x], autoIsZero);
}
return total;
}
dojo.html.getMargin = function(/* HTMLElement */node){
// summary
// Returns the width and height of the passed node's margin
return {
width: dojo.html._sumPixelValues(node, ["margin-left", "margin-right"], (dojo.html.getComputedStyle(node, 'position') == 'absolute')),
height: dojo.html._sumPixelValues(node, ["margin-top", "margin-bottom"], (dojo.html.getComputedStyle(node, 'position') == 'absolute'))
}; // object
}
dojo.html.getBorder = function(/* HTMLElement */node){
// summary
// Returns the width and height of the passed node's border
return {
width: dojo.html.getBorderExtent(node, 'left') + dojo.html.getBorderExtent(node, 'right'),
height: dojo.html.getBorderExtent(node, 'top') + dojo.html.getBorderExtent(node, 'bottom')
}; // object
}
dojo.html.getBorderExtent = function(/* HTMLElement */node, /* string */side){
// summary
// returns the width of the requested border
return (dojo.html.getStyle(node, 'border-' + side + '-style') == 'none' ? 0 : dojo.html.getPixelValue(node, 'border-' + side + '-width')); // integer
}
dojo.html.getMarginExtent = function(/* HTMLElement */node, /* string */side){
// summary
// returns the width of the requested margin
return dojo.html._sumPixelValues(node, ["margin-" + side], dojo.html.isPositionAbsolute(node)); // integer
}
dojo.html.getPaddingExtent = function(/* HTMLElement */node, /* string */side){
// summary
// Returns the width of the requested padding
return dojo.html._sumPixelValues(node, ["padding-" + side], true); // integer
}
dojo.html.getPadding = function(/* HTMLElement */node){
// summary
// Returns the width and height of the passed node's padding
return {
width: dojo.html._sumPixelValues(node, ["padding-left", "padding-right"], true),
height: dojo.html._sumPixelValues(node, ["padding-top", "padding-bottom"], true)
}; // object
}
dojo.html.getPadBorder = function(/* HTMLElement */node){
// summary
// Returns the width and height of the passed node's padding and border
var pad = dojo.html.getPadding(node);
var border = dojo.html.getBorder(node);
return { width: pad.width + border.width, height: pad.height + border.height }; // object
}
dojo.html.getBoxSizing = function(/* HTMLElement */node){
// summary
// Returns which box model the passed element is working with
var h = dojo.render.html;
var bs = dojo.html.boxSizing;
if(((h.ie)||(h.opera)) && node.nodeName!="IMG"){
var cm = document["compatMode"];
if((cm == "BackCompat")||(cm == "QuirksMode")){
return bs.BORDER_BOX; // string
}else{
return bs.CONTENT_BOX; // string
}
}else{
if(arguments.length == 0){ node = document.documentElement; }
var sizing = dojo.html.getStyle(node, "-moz-box-sizing");
if(!sizing){ sizing = dojo.html.getStyle(node, "box-sizing"); }
return (sizing ? sizing : bs.CONTENT_BOX); // string
}
}
dojo.html.isBorderBox = function(/* HTMLElement */node){
// summary
// returns whether the passed element is using border box sizing or not.
return (dojo.html.getBoxSizing(node) == dojo.html.boxSizing.BORDER_BOX); // boolean
}
dojo.html.getBorderBox = function(/* HTMLElement */node){
// summary
// Returns the dimensions of the passed element based on border-box sizing.
node = dojo.byId(node);
return { width: node.offsetWidth, height: node.offsetHeight }; // object
}
dojo.html.getPaddingBox = function(/* HTMLElement */node){
// summary
// Returns the dimensions of the padding box (see http://www.w3.org/TR/CSS21/box.html)
var box = dojo.html.getBorderBox(node);
var border = dojo.html.getBorder(node);
return {
width: box.width - border.width,
height:box.height - border.height
}; // object
}
dojo.html.getContentBox = function(/* HTMLElement */node){
// summary
// Returns the dimensions of the content box (see http://www.w3.org/TR/CSS21/box.html)
node = dojo.byId(node);
var padborder = dojo.html.getPadBorder(node);
return {
width: node.offsetWidth - padborder.width,
height: node.offsetHeight - padborder.height
}; // object
}
dojo.html.setContentBox = function(/* HTMLElement */node, /* object */args){
// summary
// Sets the dimensions of the passed node according to content sizing.
node = dojo.byId(node);
var width = 0; var height = 0;
var isbb = dojo.html.isBorderBox(node);
var padborder = (isbb ? dojo.html.getPadBorder(node) : { width: 0, height: 0});
var ret = {};
if(typeof args.width != "undefined"){
width = args.width + padborder.width;
ret.width = dojo.html.setPositivePixelValue(node, "width", width);
}
if(typeof args.height != "undefined"){
height = args.height + padborder.height;
ret.height = dojo.html.setPositivePixelValue(node, "height", height);
}
return ret; // object
}
dojo.html.getMarginBox = function(/* HTMLElement */node){
// summary
// returns the dimensions of the passed node including any margins.
var borderbox = dojo.html.getBorderBox(node);
var margin = dojo.html.getMargin(node);
return { width: borderbox.width + margin.width, height: borderbox.height + margin.height }; // object
}
dojo.html.setMarginBox = function(/* HTMLElement */node, /* object */args){
// summary
// Sets the dimensions of the passed node using margin box calcs.
node = dojo.byId(node);
var width = 0; var height = 0;
var isbb = dojo.html.isBorderBox(node);
var padborder = (!isbb ? dojo.html.getPadBorder(node) : { width: 0, height: 0 });
var margin = dojo.html.getMargin(node);
var ret = {};
if(typeof args.width != "undefined"){
width = args.width - padborder.width;
width -= margin.width;
ret.width = dojo.html.setPositivePixelValue(node, "width", width);
}
if(typeof args.height != "undefined"){
height = args.height - padborder.height;
height -= margin.height;
ret.height = dojo.html.setPositivePixelValue(node, "height", height);
}
return ret; // object
}
dojo.html.getElementBox = function(/* HTMLElement */node, /* string */type){
// summary
// return dimesions of a node based on the passed box model type.
var bs = dojo.html.boxSizing;
switch(type){
case bs.MARGIN_BOX:
return dojo.html.getMarginBox(node); // object
case bs.BORDER_BOX:
return dojo.html.getBorderBox(node); // object
case bs.PADDING_BOX:
return dojo.html.getPaddingBox(node); // object
case bs.CONTENT_BOX:
default:
return dojo.html.getContentBox(node); // object
}
}
// in: coordinate array [x,y,w,h] or dom node
// return: coordinate object
dojo.html.toCoordinateObject = dojo.html.toCoordinateArray = function(/* array */coords, /* boolean? */includeScroll, /* string? */boxtype) {
// summary
// Converts an array of coordinates into an object of named arguments.
if(coords instanceof Array || typeof coords == "array"){
dojo.deprecated("dojo.html.toCoordinateArray", "use dojo.html.toCoordinateObject({left: , top: , width: , height: }) instead", "0.5");
// coords is already an array (of format [x,y,w,h]), just return it
while ( coords.length < 4 ) { coords.push(0); }
while ( coords.length > 4 ) { coords.pop(); }
var ret = {
left: coords[0],
top: coords[1],
width: coords[2],
height: coords[3]
};
}else if(!coords.nodeType && !(coords instanceof String || typeof coords == "string") &&
('width' in coords || 'height' in coords || 'left' in coords ||
'x' in coords || 'top' in coords || 'y' in coords)){
// coords is a coordinate object or at least part of one
var ret = {
left: coords.left||coords.x||0,
top: coords.top||coords.y||0,
width: coords.width||0,
height: coords.height||0
};
}else{
// coords is an dom object (or dom object id); return it's coordinates
var node = dojo.byId(coords);
var pos = dojo.html.abs(node, includeScroll, boxtype);
var marginbox = dojo.html.getMarginBox(node);
var ret = {
left: pos.left,
top: pos.top,
width: marginbox.width,
height: marginbox.height
};
}
ret.x = ret.left;
ret.y = ret.top;
return ret; // object
}
dojo.html.setMarginBoxWidth = dojo.html.setOuterWidth = function(node, width){
return dojo.html._callDeprecated("setMarginBoxWidth", "setMarginBox", arguments, "width");
}
dojo.html.setMarginBoxHeight = dojo.html.setOuterHeight = function(){
return dojo.html._callDeprecated("setMarginBoxHeight", "setMarginBox", arguments, "height");
}
dojo.html.getMarginBoxWidth = dojo.html.getOuterWidth = function(){
return dojo.html._callDeprecated("getMarginBoxWidth", "getMarginBox", arguments, null, "width");
}
dojo.html.getMarginBoxHeight = dojo.html.getOuterHeight = function(){
return dojo.html._callDeprecated("getMarginBoxHeight", "getMarginBox", arguments, null, "height");
}
dojo.html.getTotalOffset = function(node, type, includeScroll){
return dojo.html._callDeprecated("getTotalOffset", "getAbsolutePosition", arguments, null, type);
}
dojo.html.getAbsoluteX = function(node, includeScroll){
return dojo.html._callDeprecated("getAbsoluteX", "getAbsolutePosition", arguments, null, "x");
}
dojo.html.getAbsoluteY = function(node, includeScroll){
return dojo.html._callDeprecated("getAbsoluteY", "getAbsolutePosition", arguments, null, "y");
}
dojo.html.totalOffsetLeft = function(node, includeScroll){
return dojo.html._callDeprecated("totalOffsetLeft", "getAbsolutePosition", arguments, null, "left");
}
dojo.html.totalOffsetTop = function(node, includeScroll){
return dojo.html._callDeprecated("totalOffsetTop", "getAbsolutePosition", arguments, null, "top");
}
dojo.html.getMarginWidth = function(node){
return dojo.html._callDeprecated("getMarginWidth", "getMargin", arguments, null, "width");
}
dojo.html.getMarginHeight = function(node){
return dojo.html._callDeprecated("getMarginHeight", "getMargin", arguments, null, "height");
}
dojo.html.getBorderWidth = function(node){
return dojo.html._callDeprecated("getBorderWidth", "getBorder", arguments, null, "width");
}
dojo.html.getBorderHeight = function(node){
return dojo.html._callDeprecated("getBorderHeight", "getBorder", arguments, null, "height");
}
dojo.html.getPaddingWidth = function(node){
return dojo.html._callDeprecated("getPaddingWidth", "getPadding", arguments, null, "width");
}
dojo.html.getPaddingHeight = function(node){
return dojo.html._callDeprecated("getPaddingHeight", "getPadding", arguments, null, "height");
}
dojo.html.getPadBorderWidth = function(node){
return dojo.html._callDeprecated("getPadBorderWidth", "getPadBorder", arguments, null, "width");
}
dojo.html.getPadBorderHeight = function(node){
return dojo.html._callDeprecated("getPadBorderHeight", "getPadBorder", arguments, null, "height");
}
dojo.html.getBorderBoxWidth = dojo.html.getInnerWidth = function(){
return dojo.html._callDeprecated("getBorderBoxWidth", "getBorderBox", arguments, null, "width");
}
dojo.html.getBorderBoxHeight = dojo.html.getInnerHeight = function(){
return dojo.html._callDeprecated("getBorderBoxHeight", "getBorderBox", arguments, null, "height");
}
dojo.html.getContentBoxWidth = dojo.html.getContentWidth = function(){
return dojo.html._callDeprecated("getContentBoxWidth", "getContentBox", arguments, null, "width");
}
dojo.html.getContentBoxHeight = dojo.html.getContentHeight = function(){
return dojo.html._callDeprecated("getContentBoxHeight", "getContentBox", arguments, null, "height");
}
dojo.html.setContentBoxWidth = dojo.html.setContentWidth = function(node, width){
return dojo.html._callDeprecated("setContentBoxWidth", "setContentBox", arguments, "width");
}
dojo.html.setContentBoxHeight = dojo.html.setContentHeight = function(node, height){
return dojo.html._callDeprecated("setContentBoxHeight", "setContentBox", arguments, "height");
}