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