dom-style.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. define("dojo/dom-style", ["./_base/sniff", "./dom"], function(has, dom){
  2. // module:
  3. // dojo/dom-style
  4. // summary:
  5. // This module defines the core dojo DOM style API.
  6. // =============================
  7. // Style Functions
  8. // =============================
  9. // getComputedStyle drives most of the style code.
  10. // Wherever possible, reuse the returned object.
  11. //
  12. // API functions below that need to access computed styles accept an
  13. // optional computedStyle parameter.
  14. // If this parameter is omitted, the functions will call getComputedStyle themselves.
  15. // This way, calling code can access computedStyle once, and then pass the reference to
  16. // multiple API functions.
  17. /*=====
  18. dojo.getComputedStyle = function(node){
  19. // summary:
  20. // Returns a "computed style" object.
  21. //
  22. // description:
  23. // Gets a "computed style" object which can be used to gather
  24. // information about the current state of the rendered node.
  25. //
  26. // Note that this may behave differently on different browsers.
  27. // Values may have different formats and value encodings across
  28. // browsers.
  29. //
  30. // Note also that this method is expensive. Wherever possible,
  31. // reuse the returned object.
  32. //
  33. // Use the dojo.style() method for more consistent (pixelized)
  34. // return values.
  35. //
  36. // node: DOMNode
  37. // A reference to a DOM node. Does NOT support taking an
  38. // ID string for speed reasons.
  39. // example:
  40. // | dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
  41. //
  42. // example:
  43. // Reusing the returned object, avoiding multiple lookups:
  44. // | var cs = dojo.getComputedStyle(dojo.byId("someNode"));
  45. // | var w = cs.width, h = cs.height;
  46. return; // CSS2Properties
  47. }
  48. =====*/
  49. /*=====
  50. dojo.toPixelValue = function(node, value){
  51. // summary:
  52. // converts style value to pixels on IE or return a numeric value.
  53. // node: DOMNode
  54. // value: String
  55. // returns: Number
  56. };
  57. =====*/
  58. /*=====
  59. dojo._toPixelValue = function(node, value){
  60. // summary:
  61. // Existing alias for `dojo._toPixelValue`. Deprecated, will be removed in 2.0.
  62. };
  63. =====*/
  64. /*=====
  65. dojo.getStyle = function(node, name){
  66. // summary:
  67. // Accesses styles on a node.
  68. // description:
  69. // Getting the style value uses the computed style for the node, so the value
  70. // will be a calculated value, not just the immediate node.style value.
  71. // Also when getting values, use specific style names,
  72. // like "borderBottomWidth" instead of "border" since compound values like
  73. // "border" are not necessarily reflected as expected.
  74. // If you want to get node dimensions, use `dojo.marginBox()`,
  75. // `dojo.contentBox()` or `dojo.position()`.
  76. // node: DOMNode|String
  77. // id or reference to node to get style for
  78. // name: String?
  79. // the style property to get
  80. // example:
  81. // Passing only an ID or node returns the computed style object of
  82. // the node:
  83. // | dojo.getStyle("thinger");
  84. // example:
  85. // Passing a node and a style property returns the current
  86. // normalized, computed value for that property:
  87. // | dojo.getStyle("thinger", "opacity"); // 1 by default
  88. };
  89. =====*/
  90. /*=====
  91. dojo.setStyle = function(node, name, value){
  92. // summary:
  93. // Sets styles on a node.
  94. // node: DOMNode|String
  95. // id or reference to node to set style for
  96. // name: String|Object
  97. // the style property to set in DOM-accessor format
  98. // ("borderWidth", not "border-width") or an object with key/value
  99. // pairs suitable for setting each property.
  100. // value: String?
  101. // If passed, sets value on the node for style, handling
  102. // cross-browser concerns. When setting a pixel value,
  103. // be sure to include "px" in the value. For instance, top: "200px".
  104. // Otherwise, in some cases, some browsers will not apply the style.
  105. //
  106. // example:
  107. // Passing a node, a style property, and a value changes the
  108. // current display of the node and returns the new computed value
  109. // | dojo.setStyle("thinger", "opacity", 0.5); // == 0.5
  110. //
  111. // example:
  112. // Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
  113. // | dojo.setStyle("thinger", {
  114. // | "opacity": 0.5,
  115. // | "border": "3px solid black",
  116. // | "height": "300px"
  117. // | });
  118. //
  119. // example:
  120. // When the CSS style property is hyphenated, the JavaScript property is camelCased.
  121. // font-size becomes fontSize, and so on.
  122. // | dojo.setStyle("thinger",{
  123. // | fontSize:"14pt",
  124. // | letterSpacing:"1.2em"
  125. // | });
  126. //
  127. // example:
  128. // dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
  129. // dojo.style() on every element of the list. See: `dojo.query()` and `dojo.NodeList()`
  130. // | dojo.query(".someClassName").style("visibility","hidden");
  131. // | // or
  132. // | dojo.query("#baz > div").style({
  133. // | opacity:0.75,
  134. // | fontSize:"13pt"
  135. // | });
  136. };
  137. =====*/
  138. // Although we normally eschew argument validation at this
  139. // level, here we test argument 'node' for (duck)type,
  140. // by testing nodeType, ecause 'document' is the 'parentNode' of 'body'
  141. // it is frequently sent to this function even
  142. // though it is not Element.
  143. var getComputedStyle, style = {};
  144. if(has("webkit")){
  145. getComputedStyle = function(/*DomNode*/node){
  146. var s;
  147. if(node.nodeType == 1){
  148. var dv = node.ownerDocument.defaultView;
  149. s = dv.getComputedStyle(node, null);
  150. if(!s && node.style){
  151. node.style.display = "";
  152. s = dv.getComputedStyle(node, null);
  153. }
  154. }
  155. return s || {};
  156. };
  157. }else if(has("ie") && (has("ie") < 9 || has("quirks"))){
  158. getComputedStyle = function(node){
  159. // IE (as of 7) doesn't expose Element like sane browsers
  160. return node.nodeType == 1 /* ELEMENT_NODE*/ ? node.currentStyle : {};
  161. };
  162. }else{
  163. getComputedStyle = function(node){
  164. return node.nodeType == 1 ?
  165. node.ownerDocument.defaultView.getComputedStyle(node, null) : {};
  166. };
  167. }
  168. style.getComputedStyle = getComputedStyle;
  169. var toPixel;
  170. if(!has("ie")){
  171. toPixel = function(element, value){
  172. // style values can be floats, client code may want
  173. // to round for integer pixels.
  174. return parseFloat(value) || 0;
  175. };
  176. }else{
  177. toPixel = function(element, avalue){
  178. if(!avalue){ return 0; }
  179. // on IE7, medium is usually 4 pixels
  180. if(avalue == "medium"){ return 4; }
  181. // style values can be floats, client code may
  182. // want to round this value for integer pixels.
  183. if(avalue.slice && avalue.slice(-2) == 'px'){ return parseFloat(avalue); }
  184. var s = element.style, rs = element.runtimeStyle, cs = element.currentStyle,
  185. sLeft = s.left, rsLeft = rs.left;
  186. rs.left = cs.left;
  187. try{
  188. // 'avalue' may be incompatible with style.left, which can cause IE to throw
  189. // this has been observed for border widths using "thin", "medium", "thick" constants
  190. // those particular constants could be trapped by a lookup
  191. // but perhaps there are more
  192. s.left = avalue;
  193. avalue = s.pixelLeft;
  194. }catch(e){
  195. avalue = 0;
  196. }
  197. s.left = sLeft;
  198. rs.left = rsLeft;
  199. return avalue;
  200. }
  201. }
  202. style.toPixelValue = toPixel;
  203. // FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
  204. var astr = "DXImageTransform.Microsoft.Alpha";
  205. var af = function(n, f){
  206. try{
  207. return n.filters.item(astr);
  208. }catch(e){
  209. return f ? {} : null;
  210. }
  211. };
  212. var _getOpacity =
  213. has("ie") < 9 || (has("ie") < 10 && has("quirks")) ? function(node){
  214. try{
  215. return af(node).Opacity / 100; // Number
  216. }catch(e){
  217. return 1; // Number
  218. }
  219. } :
  220. function(node){
  221. return getComputedStyle(node).opacity;
  222. };
  223. var _setOpacity =
  224. has("ie") < 9 || (has("ie") < 10 && has("quirks")) ? function(/*DomNode*/node, /*Number*/opacity){
  225. var ov = opacity * 100, opaque = opacity == 1;
  226. node.style.zoom = opaque ? "" : 1;
  227. if(!af(node)){
  228. if(opaque){
  229. return opacity;
  230. }
  231. node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")";
  232. }else{
  233. af(node, 1).Opacity = ov;
  234. }
  235. // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661),
  236. //but still update the opacity value so we can get a correct reading if it is read later.
  237. af(node, 1).Enabled = !opaque;
  238. if(node.tagName.toLowerCase() == "tr"){
  239. for(var td = node.firstChild; td; td = td.nextSibling){
  240. if(td.tagName.toLowerCase() == "td"){
  241. _setOpacity(td, opacity);
  242. }
  243. }
  244. }
  245. return opacity;
  246. } :
  247. function(node, opacity){
  248. return node.style.opacity = opacity;
  249. };
  250. var _pixelNamesCache = {
  251. left: true, top: true
  252. };
  253. var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border
  254. function _toStyleValue(node, type, value){
  255. //TODO: should we really be doing string case conversion here? Should we cache it? Need to profile!
  256. type = type.toLowerCase();
  257. if(has("ie")){
  258. if(value == "auto"){
  259. if(type == "height"){ return node.offsetHeight; }
  260. if(type == "width"){ return node.offsetWidth; }
  261. }
  262. if(type == "fontweight"){
  263. switch(value){
  264. case 700: return "bold";
  265. case 400:
  266. default: return "normal";
  267. }
  268. }
  269. }
  270. if(!(type in _pixelNamesCache)){
  271. _pixelNamesCache[type] = _pixelRegExp.test(type);
  272. }
  273. return _pixelNamesCache[type] ? toPixel(node, value) : value;
  274. }
  275. var _floatAliases = {cssFloat: 1, styleFloat: 1, "float": 1};
  276. // public API
  277. style.get = function getStyle(/*DOMNode|String*/ node, /*String?*/ name){
  278. var n = dom.byId(node), l = arguments.length, op = (name == "opacity");
  279. if(l == 2 && op){
  280. return _getOpacity(n);
  281. }
  282. name = _floatAliases[name] ? "cssFloat" in n.style ? "cssFloat" : "styleFloat" : name;
  283. var s = style.getComputedStyle(n);
  284. return (l == 1) ? s : _toStyleValue(n, name, s[name] || n.style[name]); /* CSS2Properties||String||Number */
  285. };
  286. style.set = function setStyle(/*DOMNode|String*/ node, /*String|Object*/ name, /*String?*/ value){
  287. var n = dom.byId(node), l = arguments.length, op = (name == "opacity");
  288. name = _floatAliases[name] ? "cssFloat" in n.style ? "cssFloat" : "styleFloat" : name;
  289. if(l == 3){
  290. return op ? _setOpacity(n, value) : n.style[name] = value; // Number
  291. }
  292. for(var x in name){
  293. style.set(node, x, name[x]);
  294. }
  295. return style.getComputedStyle(n);
  296. };
  297. return style;
  298. });