styles.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. define("dojox/html/styles", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/window", "dojo/_base/sniff"],
  2. function(lang, ArrayUtil, Window, has) {
  3. // summary:
  4. // Methods for creating and manipulating dynamic CSS Styles and Style Sheets
  5. //
  6. // example:
  7. // | dojox.html.createStyle("#myDiv input", "font-size:24px");
  8. // Creates Style #myDiv input, which can now be applied to myDiv, and
  9. // the inner input will be targeted
  10. // | dojox.html.createStyle(".myStyle", "color:#FF0000");
  11. // Now the class myStyle can be assigned to a node's className
  12. var dh = lang.getObject("dojox.html",true);
  13. var dynamicStyleMap = {};
  14. var pageStyleSheets = {};
  15. var titledSheets = [];
  16. dh.insertCssRule = function(/*String*/selector, /*String*/declaration, /*String*/styleSheetName){
  17. // summary:
  18. // Creates a style and attaches it to a dynamically created stylesheet
  19. // arguments:
  20. // selector:
  21. // A fully qualified class name, as it would appear in
  22. // a CSS dojo.doc. Start classes with periods, target
  23. // nodes with '#'. Large selectors can also be created
  24. // like:
  25. // | "#myDiv.myClass span input"
  26. // declaration:
  27. // A single string that would make up a style block, not
  28. // including the curly braces. Include semi-colons between
  29. // statements. Do not use JavaScript style declarations
  30. // in camel case, use as you would in a CSS dojo.doc:
  31. // | "color:#ffoooo;font-size:12px;margin-left:5px;"
  32. // styleSheetName: ( optional )
  33. // Name of the dynamic style sheet this rule should be
  34. // inserted into. If is not found by that name, it is
  35. // created. If no name is passed, the name "default" is
  36. // used.
  37. //
  38. var ss = dh.getDynamicStyleSheet(styleSheetName);
  39. var styleText = selector + " {" + declaration + "}";
  40. console.log("insertRule:", styleText);
  41. if(has("ie")){
  42. // Note: check for if(ss.cssText) does not work
  43. ss.cssText+=styleText;
  44. console.log("ss.cssText:", ss.cssText);
  45. }else if(ss.sheet){
  46. ss.sheet.insertRule(styleText, ss._indicies.length);
  47. }else{
  48. ss.appendChild(Window.doc.createTextNode(styleText));
  49. }
  50. ss._indicies.push(selector+" "+declaration);
  51. return selector; // String
  52. };
  53. dh.removeCssRule = function(/*String*/selector, /*String*/declaration, /*String*/styleSheetName){
  54. // summary:
  55. // Removes a cssRule base on the selector and declaration passed
  56. // The declaration is needed for cases of dupe selectors
  57. // description: Only removes DYNAMICALLY created cssRules. If you
  58. // created it with dh.insertCssRule, it can be removed.
  59. //
  60. var ss;
  61. var index=-1;
  62. var nm;
  63. var i;
  64. for(nm in dynamicStyleMap){
  65. if(styleSheetName && styleSheetName !== nm) {continue;}
  66. ss = dynamicStyleMap[nm];
  67. for(i=0;i<ss._indicies.length;i++){
  68. if(selector+" "+declaration === ss._indicies[i]){
  69. index = i;
  70. break;
  71. }
  72. }
  73. if(index>-1) { break; }
  74. }
  75. if(!ss){
  76. console.warn("No dynamic style sheet has been created from which to remove a rule.");
  77. return false;
  78. }
  79. if(index===-1){
  80. console.warn("The css rule was not found and could not be removed.");
  81. return false;
  82. }
  83. ss._indicies.splice(index, 1);
  84. if(has("ie")){
  85. // Note: check for if(ss.removeRule) does not work
  86. ss.removeRule(index);
  87. }else if(ss.sheet){
  88. ss.sheet.deleteRule(index);
  89. }
  90. return true; //Boolean
  91. };
  92. dh.modifyCssRule = function(selector, declaration, styleSheetName){
  93. //Not implemented - it seems to have some merit for changing some complex
  94. //selectors. It's not much use for changing simple ones like "span".
  95. //For now, simply write a new rule which will cascade over the first.
  96. // summary
  97. // Modfies an existing cssRule
  98. };
  99. dh.getStyleSheet = function(/*String*/styleSheetName){
  100. // summary:
  101. // Returns a style sheet based on the argument.
  102. // Searches dynamic style sheets first. If no matches,
  103. // searches document style sheets.
  104. //
  105. // argument: (optional)
  106. // A title or an href to a style sheet. Title can be
  107. // an attribute in a tag, or a dynamic style sheet
  108. // reference. Href can be the name of the file.
  109. // If no argument, the assumed created dynamic style
  110. // sheet is used.
  111. // try dynamic sheets first
  112. if(dynamicStyleMap[styleSheetName || "default"]){
  113. return dynamicStyleMap[styleSheetName || "default"];
  114. }
  115. if(!styleSheetName){
  116. // no arg is nly good for the default style sheet
  117. // and it has not been created yet.
  118. return false;
  119. }
  120. var allSheets = dh.getStyleSheets();
  121. // now try document style sheets by name
  122. if(allSheets[styleSheetName]){
  123. return dh.getStyleSheets()[styleSheetName];
  124. }
  125. // check for partial matches in hrefs (so that a fully
  126. //qualified name does not have to be passed)
  127. var nm;
  128. for ( nm in allSheets){
  129. if( allSheets[nm].href && allSheets[nm].href.indexOf(styleSheetName)>-1){
  130. return allSheets[nm];
  131. }
  132. }
  133. return false; //StyleSheet or false
  134. };
  135. dh.getDynamicStyleSheet = function(/*String*/styleSheetName){
  136. // summary:
  137. // Creates and returns a dynamically created style sheet
  138. // used for dynamic styles
  139. //
  140. // argument:
  141. // styleSheetName /* optional String */
  142. // The name given the style sheet so that multiple
  143. // style sheets can be created and referenced. If
  144. // no argument is given, the name "default" is used.
  145. //
  146. if(!styleSheetName){ styleSheetName="default"; }
  147. if(!dynamicStyleMap[styleSheetName]){
  148. if(Window.doc.createStyleSheet){ //IE
  149. dynamicStyleMap[styleSheetName] = Window.doc.createStyleSheet();
  150. if(has("ie") < 9) {
  151. // IE9 calls this read-only. Loving the new browser so far.
  152. dynamicStyleMap[styleSheetName].title = styleSheetName;
  153. }
  154. }else{
  155. dynamicStyleMap[styleSheetName] = Window.doc.createElement("style");
  156. dynamicStyleMap[styleSheetName].setAttribute("type", "text/css");
  157. Window.doc.getElementsByTagName("head")[0].appendChild(dynamicStyleMap[styleSheetName]);
  158. console.log(styleSheetName, " ss created: ", dynamicStyleMap[styleSheetName].sheet);
  159. }
  160. dynamicStyleMap[styleSheetName]._indicies = [];
  161. }
  162. return dynamicStyleMap[styleSheetName]; //StyleSheet
  163. };
  164. dh.enableStyleSheet = function(/*String*/styleSheetName){
  165. // summary:
  166. // Enables the style sheet with the name passed in the
  167. // argument. Deafults to the default style sheet.
  168. //
  169. var ss = dh.getStyleSheet(styleSheetName);
  170. if(ss){
  171. if(ss.sheet){
  172. ss.sheet.disabled = false;
  173. }else{
  174. ss.disabled = false;
  175. }
  176. }
  177. };
  178. dh.disableStyleSheet = function(styleSheetName){
  179. // summary:
  180. // Disables the dynamic style sheet with the name passed in the
  181. // argument. If no arg is passed, defaults to the default style sheet.
  182. //
  183. var ss = dh.getStyleSheet(styleSheetName);
  184. if(ss){
  185. if(ss.sheet){
  186. ss.sheet.disabled = true;
  187. }else{
  188. ss.disabled = true;
  189. }
  190. }
  191. };
  192. dh.activeStyleSheet = function(/*?String*/title){
  193. // summary:
  194. // Getter/Setter
  195. // description:
  196. // If passed a title, enables a that style sheet. All other
  197. // toggle-able style sheets are disabled.
  198. // If no argument is passed, returns currently enabled
  199. // style sheet.
  200. //
  201. var sheets = dh.getToggledStyleSheets();
  202. var i;
  203. if(arguments.length === 1){
  204. //console.log("sheets:", sheets);
  205. ArrayUtil.forEach(sheets, function(s){
  206. s.disabled = (s.title === title) ? false : true;
  207. });
  208. }else{
  209. for(i=0;i<sheets.length;i++){
  210. if(sheets[i].disabled === false){
  211. return sheets[i];
  212. }
  213. }
  214. }
  215. return true; //StyleSheet or Boolean - FIXME - doesn't make a lot of sense
  216. };
  217. dh.getPreferredStyleSheet = function(){
  218. // summary
  219. // Returns the style sheet that was initially enabled
  220. // on document launch.
  221. //TODO
  222. };
  223. dh.getToggledStyleSheets = function(){
  224. // summary:
  225. // Searches HTML for style sheets that are "toggle-able" -
  226. // can be enabled and disabled. These would include sheets
  227. // with the title attribute, as well as the REL attribute.
  228. // returns:
  229. // An array of all toggle-able style sheets
  230. // TODO: Sets of style sheets could be grouped according to
  231. // an ID and used in sets, much like different
  232. // groups of radio buttons. It would not however be
  233. // according to W3C spec
  234. //
  235. var nm;
  236. if(!titledSheets.length){
  237. var sObjects = dh.getStyleSheets();
  238. for(nm in sObjects){
  239. if(sObjects[nm].title){
  240. titledSheets.push(sObjects[nm]);
  241. }
  242. }
  243. }
  244. return titledSheets; //Array
  245. };
  246. dh.getStyleSheets = function(){
  247. // summary:
  248. // Collects all the style sheets referenced in the HTML page,
  249. // including any incuded via @import.
  250. //
  251. // returns:
  252. // An hash map of all the style sheets.
  253. //
  254. //TODO: Does not recursively search for @imports, so it will
  255. // only go one level deep.
  256. //
  257. if(pageStyleSheets.collected) {return pageStyleSheets;}
  258. var sheets = Window.doc.styleSheets;
  259. ArrayUtil.forEach(sheets, function(n){
  260. var s = (n.sheet) ? n.sheet : n;
  261. var name = s.title || s.href;
  262. if(has("ie")){
  263. // IE attaches a style sheet for VML - do not include this
  264. if(s.cssText.indexOf("#default#VML") === -1){
  265. if(s.href){
  266. // linked
  267. pageStyleSheets[name] = s;
  268. }else if(s.imports.length){
  269. // Imported via @import
  270. ArrayUtil.forEach(s.imports, function(si){
  271. pageStyleSheets[si.title || si.href] = si;
  272. });
  273. }else{
  274. //embedded within page
  275. pageStyleSheets[name] = s;
  276. }
  277. }
  278. }else{
  279. //linked or embedded
  280. pageStyleSheets[name] = s;
  281. pageStyleSheets[name].id = s.ownerNode.id;
  282. ArrayUtil.forEach(s.cssRules, function(r){
  283. if(r.href){
  284. // imported
  285. pageStyleSheets[r.href] = r.styleSheet;
  286. pageStyleSheets[r.href].id = s.ownerNode.id;
  287. }
  288. });
  289. }
  290. });
  291. //console.log("pageStyleSheets:", pageStyleSheets);
  292. pageStyleSheets.collected = true;
  293. return pageStyleSheets; //Object
  294. };
  295. return dh;
  296. });