style.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.html.ext-dojo.style"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.html.ext-dojo.style"] = true;
  8. dojo.provide("dojox.html.ext-dojo.style");
  9. dojo.experimental("dojox.html.ext-dojo.style");
  10. // summary: Extensions to dojo.style adding the css3 "transform" and "transform-origin" properties on IE5.5+
  11. // description:
  12. // A Package to extend the dojo.style function
  13. // Supported transformation functions:
  14. // matrix, translate, translateX, translateY, scale, scaleX, scaleY, rotate, skewX, skewY, skew
  15. dojo.mixin(dojox.html["ext-dojo"].style, {
  16. supportsTransform: true,
  17. _toPx: function(measure){
  18. var ds = dojo.style, _conversion = this._conversion;
  19. if(typeof measure === "number"){
  20. return measure + "px";
  21. }else if(measure.toLowerCase().indexOf("px") != -1){
  22. return measure;
  23. }
  24. // "native" conversion in px
  25. !_conversion.parentNode && dojo.place(_conversion, dojo.body());
  26. ds(_conversion, "margin", measure);
  27. return ds(_conversion, "margin");
  28. },
  29. init: function(){
  30. var ds = dojo.style, docStyle = dojo.doc.documentElement.style, extStyle = dojox.html["ext-dojo"].style;
  31. dojo.style = function( /*DomNode|String*/ node,
  32. /*String?|Object?*/ style,
  33. /*String?*/ value){
  34. // summary:
  35. // extended dojo.style()
  36. // description:
  37. // extended dojo.style() function, capable of handling the css3 "transform" and "transform-origin" properties
  38. // example:
  39. // | dojo.style("rotate(20deg) scaleX(1.5) scaleY(2) skew(10deg, 20deg)")
  40. var n = dojo.byId(node),
  41. tr = (style == "transform"),
  42. to = (style == "transformOrigin"),
  43. args = arguments.length
  44. ;
  45. if(args == 3){
  46. if(tr){
  47. extStyle.setTransform(n, value, true);
  48. }else if(to){
  49. extStyle.setTransformOrigin(n, value);
  50. }else{
  51. ds(node, style, value);
  52. }
  53. }
  54. if(args == 2){
  55. if(tr){
  56. return extStyle.getTransform(node);
  57. }else if(to){
  58. return extStyle.getTransformOrigin(node);
  59. }else{
  60. return ds(node, style);
  61. }
  62. }
  63. };
  64. // prefixes and property names
  65. for(var i = 0, tPrefix = ["WebkitT", "MozT", "OT", "t"]; i < tPrefix.length; i++){
  66. if(typeof docStyle[tPrefix[i] + "ransform"] !== "undefined"){
  67. this.tPropertyName = tPrefix[i] + "ransform";
  68. }
  69. if(typeof docStyle[tPrefix[i] + "ransformOrigin"] !== "undefined"){
  70. this.toPropertyName = tPrefix[i] + "ransformOrigin";
  71. }
  72. }
  73. if(this.tPropertyName){
  74. this.setTransform = function(/*DomNode*/node, /*String*/ transform){
  75. return dojo.style(node, this.tPropertyName, transform);
  76. };
  77. this.getTransform = function(/*DomNode*/node){
  78. return dojo.style(node, this.tPropertyName);
  79. };
  80. }else if(dojo.isIE){
  81. this.setTransform = this._setTransformFilter;
  82. this.getTransform = this._getTransformFilter;
  83. }
  84. if(this.toPropertyName){
  85. this.setTransformOrigin = function(/*DomNode*/node, /*String*/ transformOrigin){
  86. return dojo.style(node, this.toPropertyName, transformOrigin);
  87. };
  88. this.getTransformOrigin = function(/*DomNode*/node){
  89. return dojo.style(node, this.toPropertyName);
  90. };
  91. }else if(dojo.isIE){
  92. this.setTransformOrigin = this._setTransformOriginFilter;
  93. this.getTransformOrigin = this._getTransformOriginFilter;
  94. }else{
  95. this.supportsTransform = false;
  96. }
  97. this._conversion = dojo.create("div", {
  98. style: {
  99. position: "absolute",
  100. top: "-100px",
  101. left: "-100px",
  102. fontSize: 0,
  103. width: "0",
  104. backgroundPosition: "50% 50%"
  105. }
  106. });
  107. },
  108. _notSupported: function(){
  109. console.warn("Sorry, this browser doesn't support transform and transform-origin");
  110. },
  111. _setTransformOriginFilter: function(/*DomNode*/ node, /*String*/ transformOrigin){
  112. var to = dojo.trim(transformOrigin)
  113. .replace(" top", " 0")
  114. .replace("left ", "0 ")
  115. .replace(" center", "50%")
  116. .replace("center ", "50% ")
  117. .replace(" bottom", " 100%")
  118. .replace("right ", "100% ")
  119. .replace(/\s+/, " "),
  120. toAry = to.split(" "),
  121. n = dojo.byId(node),
  122. t = this.getTransform(n),
  123. validOrigin = true
  124. ;
  125. for(var i = 0; i < toAry.length; i++){
  126. validOrigin = validOrigin && /^0|(\d+(%|px|pt|in|pc|mm|cm))$/.test(toAry[i]);
  127. if(toAry[i].indexOf("%") == -1){
  128. toAry[i] = this._toPx(toAry[i]);
  129. }
  130. }
  131. if(!validOrigin){
  132. return;
  133. }
  134. if(!toAry.length || toAry.length > 2 ){
  135. return;
  136. }
  137. dojo.attr(n, "dojo-transform-origin", toAry.join(" "));
  138. t && this.setTransform(node, t);
  139. },
  140. _getTransformOriginFilter: function(/*DomNode*/ node){
  141. return dojo.attr(node, "dojo-transform-origin") || "50% 50%";
  142. },
  143. _setTransformFilter: function(/*DomNode*/ node, /*String*/ transform){
  144. // Using the Matrix Filter to implement the transform property on IE
  145. var t = transform.replace(/\s/g, ""),
  146. n = dojo.byId(node),
  147. transforms = t.split(")"),
  148. toRad = 1, toRad1 = 1,
  149. mstr = "DXImageTransform.Microsoft.Matrix",
  150. hasAttr = dojo.hasAttr,
  151. attr = dojo.attr,
  152. // Math functions
  153. PI = Math.PI, cos = Math.cos, sin = Math.sin, tan = Math.tan, max = Math.max, min = Math.min, abs = Math.abs,
  154. degToRad = PI/180, gradToRad = PI/200,
  155. // current transform
  156. ct = "", currentTransform = "",
  157. matchingTransforms = [],
  158. x0 = 0, y0 = 0, dx = 0, dy = 0, xc = 0, yc = 0, a = 0,
  159. // default transform, identity matrix
  160. m11 = 1, m12 = 0, m21 = 0, m22 = 1,
  161. // no translation
  162. tx = 0, ty = 0,
  163. props = [m11, m12, m21, m22, tx, ty],
  164. hasMatrix = false,
  165. ds = dojo.style,
  166. newPosition = ds(n, "position") == "absolute" ? "absolute" : "relative",
  167. w = ds(n, "width") + ds(n, "paddingLeft") + ds(n, "paddingRight"),
  168. h = ds(n, "height") + ds(n, "paddingTop") + ds(n, "paddingBottom"),
  169. toPx = this._toPx
  170. ;
  171. !hasAttr(n, "dojo-transform-origin") && this.setTransformOrigin(n, "50% 50%");
  172. for(var i = 0, l = transforms.length; i < l; i++){
  173. matchingTransforms = transforms[i].match(/matrix|rotate|scaleX|scaleY|scale|skewX|skewY|skew|translateX|translateY|translate/);
  174. currentTransform = matchingTransforms ? matchingTransforms[0] : "";
  175. switch(currentTransform){
  176. case "matrix":
  177. // generic transformation
  178. //
  179. // matrix:
  180. // m11 m12
  181. //
  182. // m21 m22
  183. //
  184. ct = transforms[i].replace(/matrix\(|\)/g, "");
  185. var matrix = ct.split(",");
  186. m11 = props[0]*matrix[0] + props[1]*matrix[2];
  187. m12 = props[0]*matrix[1] + props[1]*matrix[3];
  188. m21 = props[2]*matrix[0] + props[3]*matrix[2];
  189. m22 = props[2]*matrix[1] + props[3]*matrix[3];
  190. tx = props[4] + matrix[4];
  191. ty = props[5] + matrix[5];
  192. break;
  193. case "rotate":
  194. // rotate
  195. //
  196. // rotation angle:
  197. // a (rad, deg or grad)
  198. //
  199. // matrix:
  200. // cos(a) -sin(a)
  201. //
  202. // sin(a) cos(a)
  203. //
  204. ct = transforms[i].replace(/rotate\(|\)/g, "");
  205. toRad = ct.indexOf("deg") != -1 ? degToRad : ct.indexOf("grad") != -1 ? gradToRad : 1;
  206. a = parseFloat(ct)*toRad;
  207. var s = sin(a),
  208. c = cos(a)
  209. ;
  210. m11 = props[0]*c + props[1]*s;
  211. m12 = -props[0]*s + props[1]*c;
  212. m21 = props[2]*c + props[3]*s;
  213. m22 = -props[2]*s + props[3]*c;
  214. break;
  215. case "skewX":
  216. // skewX
  217. //
  218. // skew angle:
  219. // a (rad, deg or grad)
  220. //
  221. // matrix:
  222. // 1 tan(a)
  223. //
  224. // 0 1
  225. //
  226. ct = transforms[i].replace(/skewX\(|\)/g, "");
  227. toRad = ct.indexOf("deg") != -1 ? degToRad : ct.indexOf("grad") != -1 ? gradToRad : 1;
  228. var ta = tan(parseFloat(ct)*toRad);
  229. m11 = props[0];
  230. m12 = props[0]*ta + props[1];
  231. m21 = props[2];
  232. m22 = props[2]*ta + props[3];
  233. break;
  234. case "skewY":
  235. // skewY
  236. //
  237. // skew angle:
  238. // a (rad, deg or grad)
  239. //
  240. // matrix:
  241. // 1 0
  242. //
  243. // tan(a) 1
  244. //
  245. ct = transforms[i].replace(/skewY\(|\)/g, "");
  246. toRad = ct.indexOf("deg") != -1 ? degToRad : ct.indexOf("grad") != -1 ? gradToRad : 1;
  247. ta = tan(parseFloat(ct)*toRad);
  248. m11 = props[0] + props[1]*ta;
  249. m12 = props[1];
  250. m21 = props[2] + props[3]*ta;
  251. m22 = props[3];
  252. break;
  253. case "skew":
  254. // skew
  255. //
  256. // skew angles:
  257. // a0 (rad, deg or grad)
  258. // a1 (rad, deg or grad)
  259. //
  260. // matrix:
  261. // 1 tan(a0)
  262. //
  263. // tan(a1) 1
  264. //
  265. ct = transforms[i].replace(/skew\(|\)/g, "");
  266. var skewAry = ct.split(",");
  267. skewAry[1] = skewAry[1] || "0";
  268. toRad = skewAry[0].indexOf("deg") != -1 ? degToRad : skewAry[0].indexOf("grad") != -1 ? gradToRad : 1;
  269. toRad1 = skewAry[1].indexOf("deg") != -1 ? degToRad : skewAry[1].indexOf("grad") != -1 ? gradToRad : 1;
  270. var a0 = tan(parseFloat(skewAry[0])*toRad),
  271. a1 = tan(parseFloat(skewAry[1])*toRad1)
  272. ;
  273. m11 = props[0] + props[1]*a1;
  274. m12 = props[0]*a0 + props[1];
  275. m21 = props[2]+ props[3]*a1;
  276. m22 = props[2]*a0 + props[3];
  277. break;
  278. case "scaleX":
  279. // scaleX
  280. //
  281. // scale factor:
  282. // sx
  283. //
  284. // matrix:
  285. // sx 0
  286. //
  287. // 0 1
  288. //
  289. ct = parseFloat(transforms[i].replace(/scaleX\(|\)/g, "")) || 1;
  290. m11 = props[0]*ct;
  291. m12 = props[1];
  292. m21 = props[2]*ct;
  293. m22 = props[3];
  294. break;
  295. case "scaleY":
  296. // scaleY
  297. //
  298. // scale factor:
  299. // sy
  300. //
  301. // matrix:
  302. // 1 0
  303. //
  304. // 0 sy
  305. //
  306. ct = parseFloat(transforms[i].replace(/scaleY\(|\)/g, "")) || 1;
  307. m11 = props[0];
  308. m12 = props[1]*ct;
  309. m21 = props[2];
  310. m22 = props[3]*ct;
  311. break;
  312. case "scale":
  313. // scale
  314. //
  315. // scale factor:
  316. // sx, sy
  317. //
  318. // matrix:
  319. // sx 0
  320. //
  321. // 0 sy
  322. //
  323. ct = transforms[i].replace(/scale\(|\)/g, "");
  324. var scaleAry = ct.split(",");
  325. scaleAry[1] = scaleAry[1] || scaleAry[0];
  326. m11 = props[0]*scaleAry[0];
  327. m12 = props[1]*scaleAry[1];
  328. m21 = props[2]*scaleAry[0];
  329. m22 = props[3]*scaleAry[1];
  330. break;
  331. case "translateX":
  332. ct = parseInt(transforms[i].replace(/translateX\(|\)/g, "")) || 1;
  333. m11 = props[0];
  334. m12 = props[1];
  335. m21 = props[2];
  336. m22 = props[3];
  337. tx = toPx(ct);
  338. tx && attr(n, "dojo-transform-matrix-tx", tx);
  339. break;
  340. case "translateY":
  341. ct = parseInt(transforms[i].replace(/translateY\(|\)/g, "")) || 1;
  342. m11 = props[0];
  343. m12 = props[1];
  344. m21 = props[2];
  345. m22 = props[3];
  346. ty = toPx(ct);
  347. ty && attr(n, "dojo-transform-matrix-ty", ty);
  348. break;
  349. case "translate":
  350. ct = transforms[i].replace(/translate\(|\)/g, "");
  351. m11 = props[0];
  352. m12 = props[1];
  353. m21 = props[2];
  354. m22 = props[3];
  355. var translateAry = ct.split(",");
  356. translateAry[0] = parseInt(toPx(translateAry[0])) || 0;
  357. translateAry[1] = parseInt(toPx(translateAry[1])) || 0;
  358. tx = translateAry[0];
  359. ty = translateAry[1];
  360. tx && attr(n, "dojo-transform-matrix-tx", tx);
  361. ty && attr(n, "dojo-transform-matrix-ty", ty);
  362. break;
  363. }
  364. props = [m11, m12, m21, m22, tx, ty];
  365. }
  366. // test
  367. var Bx = min(w*m11 + h*m12, min(min(w*m11, h*m12), 0)),
  368. By = min(w*m21 + h*m22, min(min(w*m21, h*m22), 0))
  369. ;
  370. dx = -Bx;
  371. dy = -By;
  372. if(dojo.isIE < 8){
  373. // on IE < 8 the node must have hasLayout = true
  374. n.style.zoom = "1";
  375. if(newPosition != "absolute"){
  376. var parentWidth = ds(node.parentNode, "width"),
  377. tw = abs(w*m11),
  378. th = abs(h*m12),
  379. wMax = max(tw + th, max(max(th, tw), 0))
  380. ;
  381. dx -= (wMax - w) / 2 - (parentWidth > wMax ? 0 : (wMax - parentWidth) / 2);
  382. }
  383. }else if(dojo.isIE == 8){
  384. // IE8 bug, a filter is applied to positioned descendants
  385. // only if the parent has z-index
  386. ds(n, "zIndex") == "auto" && (n.style.zIndex = "0");
  387. }
  388. try{
  389. hasMatrix = !!n.filters.item(mstr);
  390. }catch(e){
  391. hasMatrix = false;
  392. }
  393. if(hasMatrix){
  394. n.filters.item(mstr).M11 = m11;
  395. n.filters.item(mstr).M12 = m12;
  396. n.filters.item(mstr).M21 = m21;
  397. n.filters.item(mstr).M22 = m22;
  398. // use 'nearest' for a faster transform
  399. n.filters.item(mstr).filterType = 'bilinear';
  400. n.filters.item(mstr).Dx = 0;
  401. n.filters.item(mstr).Dy = 0;
  402. n.filters.item(mstr).sizingMethod = 'auto expand';
  403. }else{
  404. n.style.filter +=
  405. " progid:" + mstr + "(M11=" + m11 +
  406. ",M12=" + m12 +
  407. ",M21=" + m21 +
  408. ",M22=" + m22 +
  409. ",FilterType='bilinear',Dx=0,Dy=0,sizingMethod='auto expand')"
  410. ;
  411. }
  412. tx = parseInt(attr(n, "dojo-transform-matrix-tx") || "0");
  413. ty = parseInt(attr(n, "dojo-transform-matrix-ty") || "0");
  414. // transform origin
  415. var toAry = attr(n, "dojo-transform-origin").split(" ");
  416. for(i = 0; i < 2; i++){
  417. toAry[i] = toAry[i] || "50%";
  418. }
  419. xc = (toAry[0].toString().indexOf("%") != -1) ? w * parseInt(toAry[0]) * .01 : toAry[0];
  420. yc = (toAry[1].toString().indexOf("%") != -1) ? h * parseInt(toAry[1]) * .01 : toAry[1];
  421. if(hasAttr(n, "dojo-startX")){
  422. x0 = parseInt(attr(n, "dojo-startX"));
  423. }else{
  424. x0 = parseInt(ds(n, "left"));
  425. attr(n, "dojo-startX", newPosition == "absolute" ? x0 : "0");
  426. }
  427. if(hasAttr(n, "dojo-startY")){
  428. y0 = parseInt(attr(n, "dojo-startY"));
  429. }else{
  430. y0 = parseInt(ds(n, "top"));
  431. attr(n, "dojo-startY", newPosition == "absolute" ? y0 : "0");
  432. }
  433. ds(n, {
  434. position: newPosition,
  435. left: x0 - parseInt(dx) + parseInt(xc) - ((parseInt(xc) - tx)*m11 + (parseInt(yc) - ty)*m12) + "px",
  436. top: y0 - parseInt(dy) + parseInt(yc) - ((parseInt(xc) - tx)*m21 + (parseInt(yc) - ty)*m22) + "px"
  437. });
  438. },
  439. _getTransformFilter: function(/*DomNode*/ node){
  440. try{
  441. var n = dojo.byId(node),
  442. item = n.filters.item(0)
  443. ;
  444. return "matrix(" + item.M11 + ", " + item.M12 + ", " + item.M21 + ", " +
  445. item.M22 + ", " + (dojo.attr(node, "dojo-transform-tx") || "0") + ", " + (dojo.attr(node, "dojo-transform-ty") || "0") + ")";
  446. }catch(e){
  447. return "matrix(1, 0, 0, 1, 0, 0)";
  448. }
  449. },
  450. setTransform: function(){
  451. this._notSupported();
  452. },
  453. setTransformOrigin: function(){
  454. this._notSupported();
  455. }
  456. });
  457. dojox.html["ext-dojo"].style.init();
  458. }