307 lines
9.8 KiB
JavaScript
307 lines
9.8 KiB
JavaScript
|
define("dojo/dom-style", ["./sniff", "./dom"], function(has, dom){
|
||
|
// module:
|
||
|
// dojo/dom-style
|
||
|
|
||
|
// =============================
|
||
|
// Style Functions
|
||
|
// =============================
|
||
|
|
||
|
// getComputedStyle drives most of the style code.
|
||
|
// Wherever possible, reuse the returned object.
|
||
|
//
|
||
|
// API functions below that need to access computed styles accept an
|
||
|
// optional computedStyle parameter.
|
||
|
// If this parameter is omitted, the functions will call getComputedStyle themselves.
|
||
|
// This way, calling code can access computedStyle once, and then pass the reference to
|
||
|
// multiple API functions.
|
||
|
|
||
|
// Although we normally eschew argument validation at this
|
||
|
// level, here we test argument 'node' for (duck)type,
|
||
|
// by testing nodeType, ecause 'document' is the 'parentNode' of 'body'
|
||
|
// it is frequently sent to this function even
|
||
|
// though it is not Element.
|
||
|
var getComputedStyle, style = {
|
||
|
// summary:
|
||
|
// This module defines the core dojo DOM style API.
|
||
|
};
|
||
|
if(has("webkit")){
|
||
|
getComputedStyle = function(/*DomNode*/ node){
|
||
|
var s;
|
||
|
if(node.nodeType == 1){
|
||
|
var dv = node.ownerDocument.defaultView;
|
||
|
s = dv.getComputedStyle(node, null);
|
||
|
if(!s && node.style){
|
||
|
node.style.display = "";
|
||
|
s = dv.getComputedStyle(node, null);
|
||
|
}
|
||
|
}
|
||
|
return s || {};
|
||
|
};
|
||
|
}else if(has("ie") && (has("ie") < 9 || has("quirks"))){
|
||
|
getComputedStyle = function(node){
|
||
|
// IE (as of 7) doesn't expose Element like sane browsers
|
||
|
// currentStyle can be null on IE8!
|
||
|
return node.nodeType == 1 /* ELEMENT_NODE*/ && node.currentStyle ? node.currentStyle : {};
|
||
|
};
|
||
|
}else{
|
||
|
getComputedStyle = function(node){
|
||
|
return node.nodeType == 1 /* ELEMENT_NODE*/ ?
|
||
|
node.ownerDocument.defaultView.getComputedStyle(node, null) : {};
|
||
|
};
|
||
|
}
|
||
|
style.getComputedStyle = getComputedStyle;
|
||
|
/*=====
|
||
|
style.getComputedStyle = function(node){
|
||
|
// summary:
|
||
|
// Returns a "computed style" object.
|
||
|
//
|
||
|
// description:
|
||
|
// Gets a "computed style" object which can be used to gather
|
||
|
// information about the current state of the rendered node.
|
||
|
//
|
||
|
// Note that this may behave differently on different browsers.
|
||
|
// Values may have different formats and value encodings across
|
||
|
// browsers.
|
||
|
//
|
||
|
// Note also that this method is expensive. Wherever possible,
|
||
|
// reuse the returned object.
|
||
|
//
|
||
|
// Use the dojo.style() method for more consistent (pixelized)
|
||
|
// return values.
|
||
|
//
|
||
|
// node: DOMNode
|
||
|
// A reference to a DOM node. Does NOT support taking an
|
||
|
// ID string for speed reasons.
|
||
|
// example:
|
||
|
// | dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
|
||
|
//
|
||
|
// example:
|
||
|
// Reusing the returned object, avoiding multiple lookups:
|
||
|
// | var cs = dojo.getComputedStyle(dojo.byId("someNode"));
|
||
|
// | var w = cs.width, h = cs.height;
|
||
|
return; // CSS2Properties
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
var toPixel;
|
||
|
if(!has("ie")){
|
||
|
toPixel = function(element, value){
|
||
|
// style values can be floats, client code may want
|
||
|
// to round for integer pixels.
|
||
|
return parseFloat(value) || 0;
|
||
|
};
|
||
|
}else{
|
||
|
toPixel = function(element, avalue){
|
||
|
if(!avalue){ return 0; }
|
||
|
// on IE7, medium is usually 4 pixels
|
||
|
if(avalue == "medium"){ return 4; }
|
||
|
// style values can be floats, client code may
|
||
|
// want to round this value for integer pixels.
|
||
|
if(avalue.slice && avalue.slice(-2) == 'px'){ return parseFloat(avalue); }
|
||
|
var s = element.style, rs = element.runtimeStyle, cs = element.currentStyle,
|
||
|
sLeft = s.left, rsLeft = rs.left;
|
||
|
rs.left = cs.left;
|
||
|
try{
|
||
|
// 'avalue' may be incompatible with style.left, which can cause IE to throw
|
||
|
// this has been observed for border widths using "thin", "medium", "thick" constants
|
||
|
// those particular constants could be trapped by a lookup
|
||
|
// but perhaps there are more
|
||
|
s.left = avalue;
|
||
|
avalue = s.pixelLeft;
|
||
|
}catch(e){
|
||
|
avalue = 0;
|
||
|
}
|
||
|
s.left = sLeft;
|
||
|
rs.left = rsLeft;
|
||
|
return avalue;
|
||
|
};
|
||
|
}
|
||
|
style.toPixelValue = toPixel;
|
||
|
/*=====
|
||
|
style.toPixelValue = function(node, value){
|
||
|
// summary:
|
||
|
// converts style value to pixels on IE or return a numeric value.
|
||
|
// node: DOMNode
|
||
|
// value: String
|
||
|
// returns: Number
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
// FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
|
||
|
|
||
|
var astr = "DXImageTransform.Microsoft.Alpha";
|
||
|
var af = function(n, f){
|
||
|
try{
|
||
|
return n.filters.item(astr);
|
||
|
}catch(e){
|
||
|
return f ? {} : null;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var _getOpacity =
|
||
|
has("ie") < 9 || (has("ie") < 10 && has("quirks")) ? function(node){
|
||
|
try{
|
||
|
return af(node).Opacity / 100; // Number
|
||
|
}catch(e){
|
||
|
return 1; // Number
|
||
|
}
|
||
|
} :
|
||
|
function(node){
|
||
|
return getComputedStyle(node).opacity;
|
||
|
};
|
||
|
|
||
|
var _setOpacity =
|
||
|
has("ie") < 9 || (has("ie") < 10 && has("quirks")) ? function(/*DomNode*/ node, /*Number*/ opacity){
|
||
|
var ov = opacity * 100, opaque = opacity == 1;
|
||
|
node.style.zoom = opaque ? "" : 1;
|
||
|
|
||
|
if(!af(node)){
|
||
|
if(opaque){
|
||
|
return opacity;
|
||
|
}
|
||
|
node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")";
|
||
|
}else{
|
||
|
af(node, 1).Opacity = ov;
|
||
|
}
|
||
|
|
||
|
// on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661),
|
||
|
//but still update the opacity value so we can get a correct reading if it is read later.
|
||
|
af(node, 1).Enabled = !opaque;
|
||
|
|
||
|
if(node.tagName.toLowerCase() == "tr"){
|
||
|
for(var td = node.firstChild; td; td = td.nextSibling){
|
||
|
if(td.tagName.toLowerCase() == "td"){
|
||
|
_setOpacity(td, opacity);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return opacity;
|
||
|
} :
|
||
|
function(node, opacity){
|
||
|
return node.style.opacity = opacity;
|
||
|
};
|
||
|
|
||
|
var _pixelNamesCache = {
|
||
|
left: true, top: true
|
||
|
};
|
||
|
var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border
|
||
|
function _toStyleValue(node, type, value){
|
||
|
//TODO: should we really be doing string case conversion here? Should we cache it? Need to profile!
|
||
|
type = type.toLowerCase();
|
||
|
if(has("ie")){
|
||
|
if(value == "auto"){
|
||
|
if(type == "height"){ return node.offsetHeight; }
|
||
|
if(type == "width"){ return node.offsetWidth; }
|
||
|
}
|
||
|
if(type == "fontweight"){
|
||
|
switch(value){
|
||
|
case 700: return "bold";
|
||
|
case 400:
|
||
|
default: return "normal";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if(!(type in _pixelNamesCache)){
|
||
|
_pixelNamesCache[type] = _pixelRegExp.test(type);
|
||
|
}
|
||
|
return _pixelNamesCache[type] ? toPixel(node, value) : value;
|
||
|
}
|
||
|
|
||
|
var _floatStyle = has("ie") ? "styleFloat" : "cssFloat",
|
||
|
_floatAliases = {"cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle};
|
||
|
|
||
|
// public API
|
||
|
|
||
|
style.get = function getStyle(/*DOMNode|String*/ node, /*String?*/ name){
|
||
|
// summary:
|
||
|
// Accesses styles on a node.
|
||
|
// description:
|
||
|
// Getting the style value uses the computed style for the node, so the value
|
||
|
// will be a calculated value, not just the immediate node.style value.
|
||
|
// Also when getting values, use specific style names,
|
||
|
// like "borderBottomWidth" instead of "border" since compound values like
|
||
|
// "border" are not necessarily reflected as expected.
|
||
|
// If you want to get node dimensions, use `dojo.marginBox()`,
|
||
|
// `dojo.contentBox()` or `dojo.position()`.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to node to get style for
|
||
|
// name: String?
|
||
|
// the style property to get
|
||
|
// example:
|
||
|
// Passing only an ID or node returns the computed style object of
|
||
|
// the node:
|
||
|
// | dojo.getStyle("thinger");
|
||
|
// example:
|
||
|
// Passing a node and a style property returns the current
|
||
|
// normalized, computed value for that property:
|
||
|
// | dojo.getStyle("thinger", "opacity"); // 1 by default
|
||
|
|
||
|
var n = dom.byId(node), l = arguments.length, op = (name == "opacity");
|
||
|
if(l == 2 && op){
|
||
|
return _getOpacity(n);
|
||
|
}
|
||
|
name = _floatAliases[name] || name;
|
||
|
var s = style.getComputedStyle(n);
|
||
|
return (l == 1) ? s : _toStyleValue(n, name, s[name] || n.style[name]); /* CSS2Properties||String||Number */
|
||
|
};
|
||
|
|
||
|
style.set = function setStyle(/*DOMNode|String*/ node, /*String|Object*/ name, /*String?*/ value){
|
||
|
// summary:
|
||
|
// Sets styles on a node.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to node to set style for
|
||
|
// name: String|Object
|
||
|
// the style property to set in DOM-accessor format
|
||
|
// ("borderWidth", not "border-width") or an object with key/value
|
||
|
// pairs suitable for setting each property.
|
||
|
// value: String?
|
||
|
// If passed, sets value on the node for style, handling
|
||
|
// cross-browser concerns. When setting a pixel value,
|
||
|
// be sure to include "px" in the value. For instance, top: "200px".
|
||
|
// Otherwise, in some cases, some browsers will not apply the style.
|
||
|
//
|
||
|
// example:
|
||
|
// Passing a node, a style property, and a value changes the
|
||
|
// current display of the node and returns the new computed value
|
||
|
// | dojo.setStyle("thinger", "opacity", 0.5); // == 0.5
|
||
|
//
|
||
|
// example:
|
||
|
// Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
|
||
|
// | dojo.setStyle("thinger", {
|
||
|
// | "opacity": 0.5,
|
||
|
// | "border": "3px solid black",
|
||
|
// | "height": "300px"
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// When the CSS style property is hyphenated, the JavaScript property is camelCased.
|
||
|
// font-size becomes fontSize, and so on.
|
||
|
// | dojo.setStyle("thinger",{
|
||
|
// | fontSize:"14pt",
|
||
|
// | letterSpacing:"1.2em"
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// dojo/NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
|
||
|
// dojo.style() on every element of the list. See: `dojo.query()` and `dojo/NodeList`
|
||
|
// | dojo.query(".someClassName").style("visibility","hidden");
|
||
|
// | // or
|
||
|
// | dojo.query("#baz > div").style({
|
||
|
// | opacity:0.75,
|
||
|
// | fontSize:"13pt"
|
||
|
// | });
|
||
|
|
||
|
var n = dom.byId(node), l = arguments.length, op = (name == "opacity");
|
||
|
name = _floatAliases[name] || name;
|
||
|
if(l == 3){
|
||
|
return op ? _setOpacity(n, value) : n.style[name] = value; // Number
|
||
|
}
|
||
|
for(var x in name){
|
||
|
style.set(node, x, name[x]);
|
||
|
}
|
||
|
return style.getComputedStyle(n);
|
||
|
};
|
||
|
|
||
|
return style;
|
||
|
});
|