OSDN Git Service

import source-tree based svn r84.
[bluegriffon/BlueGriffon.git] / base / content / bluegriffon / utils / css.js
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is BlueGriffon.
15  *
16  * The Initial Developer of the Original Code is
17  * Disruptive Innovations SARL.
18  * Portions created by the Initial Developer are Copyright (C) 2006
19  * the Initial Developer. All Rights Reserved.
20  *
21  * Contributor(s):
22  *   Daniel Glazman <daniel.glazman@disruptive-innovations.com>, Original author
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either the GNU General Public License Version 2 or later (the "GPL"), or
26  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
38 var CssUtils = {
39         getStyleSheets: function CssUtils_getStyleSheets(aDoc)
40         {
41                 return aDoc.styleSheets;
42         },
43
44   _enumerateStyleSheet: function CssUtils__enumerateStyleSheet(aSheet, aCallback)
45   {
46     if (aCallback(aSheet))
47       return;
48     var rules = aSheet.cssRules;
49     for (var j = 0; j < rules.length; j++)
50     {
51       var rule = rules.item(j);
52       switch (rule.type)
53       {
54         case CSSRule.IMPORT_RULE:
55           this._enumerateStyleSheet(rule.styleSheet, aCallback);
56           break;
57         case CSSRule.MEDIA_RULE:
58           this._enumerateStyleSheet(rule, aCallback);
59           break;
60         default:
61           break;
62       }
63
64     }
65   },
66
67   enumerateStyleSheets: function CssUtils_enumerateStyleSheets(aDocument, aCallback)
68   {
69         var stylesheetsList = aDocument.styleSheets;
70     for (var i = 0; i < stylesheetsList.length; i++)
71     {
72       var sheet = stylesheetsList.item(i);
73       this._enumerateStyleSheet(sheet, aCallback);
74     }
75   },
76
77   getComputedStyle: function CssUtils_getComputedStyle(aElt)
78   {
79         return aElt.ownerDocument.defaultView.getComputedStyle(aElt, "");
80   },
81
82   findClassesInSelector: function CssUtils_findClassesInSelector(aSelector)
83   {
84     return aSelector.match( /\.-?([_a-z]|[\200-\377]|((\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?)|\\[^\r\n\f0-9a-f]))([_a-z0-9-]|[\200-\377]|((\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?)|\\[^\r\n\f0-9a-f]))*/gi );
85   },
86
87   findIdsInSelector: function CssUtils_findClassesInSelector(aSelector)
88   {
89     return aSelector.match( /#-?([_a-z]|[\200-\377]|((\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?)|\\[^\r\n\f0-9a-f]))([_a-z0-9-]|[\200-\377]|((\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?)|\\[^\r\n\f0-9a-f]))*/gi );
90   },
91
92   getCssHintsFromDocument: function CssUtils_getAllClassesFromDocument(aDocument, aDetector)
93   {
94     var classList = [];
95   
96     function enumerateClass(aSheet)
97     {
98       var cssRules = aSheet.cssRules;
99       for (var i = 0; i < cssRules.length; i++)
100       {
101         var rule = cssRules.item(i);
102         if (rule.type == CSSRule.STYLE_RULE)
103         {
104           var selectorText = rule.selectorText;
105           var matches = aDetector(selectorText);
106           if (matches)
107             for (var j = 0; j < matches.length; j++)
108               classList.push(matches[j].substr(1));
109         }
110       }
111       return false;
112     }
113   
114     CssUtils.enumerateStyleSheets(aDocument, enumerateClass);
115
116     return classList;
117   },
118
119   getAllClassesForDocument: function CssUtils_getAllClassesForDocument(aDocument)
120   {
121     return this.getCssHintsFromDocument(aDocument, this.findClassesInSelector);
122   },
123
124   getAllIdsForDocument: function CssUtils_getAllClassesForDocument(aDocument)
125   {
126     return this.getCssHintsFromDocument(aDocument, this.findIdsInSelector);
127   },
128
129   getAllLocalRulesForSelector: function CssUtils_getAllLocalRulesForSelector(aDocument, aSelector)
130   {
131     var ruleList = [];
132   
133     function enumerateRules(aSheet)
134     {
135       if (aSheet.ownerNode instanceof HTMLStyleElement)
136       {
137         var cssRules = aSheet.cssRules;
138         for (var i = 0; i < cssRules.length; i++)
139         {
140           var rule = cssRules.item(i);
141           if (rule.type == CSSRule.STYLE_RULE)
142           {
143             var selectorText = rule.selectorText;
144             if (selectorText == aSelector)
145               ruleList.push({rule:rule, index:i});
146           }
147         }
148         return false;
149       }
150       return true;
151     }
152   
153     CssUtils.enumerateStyleSheets(aDocument, enumerateRules);
154
155     return ruleList;
156   },
157
158   deleteAllLocalRulesForSelector: function CssUtils_deleteAllLocalRulesForSelector(aDocument, aSelector, aDeclarations)
159   {
160     var ruleList = this.getAllLocalRulesForSelector(aDocument, aSelector);
161     var l = ruleList.length;
162     for (var i = 0; i < l; i++)
163     {
164       var rule = ruleList[i].rule;
165       var parentRule = rule.parentRule;
166       var parentStyleSheet = rule.parentStyleSheet;
167       if (rule.type == CSSRule.STYLE_RULE && !parentRule)
168       {
169         if (aDeclarations)
170         {
171           for (var j = 0; j < aDeclarations.length; j++)
172             rule.style.removeProperty(aDeclarations[j].property);
173           if (!rule.style.length)
174             parentStyleSheet.deleteRule(ruleList[i].index);
175         }
176         else
177           parentStyleSheet.deleteRule(ruleList[i].index);
178       }
179       this.reserializeEmbeddedStylesheet(parentStyleSheet);
180     }
181   },
182
183   getStyleSheetForScreen: function CssUtils_getStyleSheetForScreen(aDocument)
184   {
185     var styleElements = aDocument.getElementsByTagName("style");
186     var stylesheet = null;
187     if (styleElements.length)
188     {
189       // try to find a stylesheet for the correct media
190       for (var i = 0; !stylesheet && i < styleElements.length; i++)
191       {
192         var styleElement = styleElements[i];
193         if (styleElement.hasAttribute("media"))
194         {
195           var mediaAttr = styleElement.getAttribute("media");
196           if (mediaAttr.indexOf("screen") != -1||
197               mediaAttr.indexOf("all") != -1)
198             stylesheet = styleElement.sheet;
199         }
200         else
201           stylesheet = styleElement.sheet;
202       }
203     }
204     if (!stylesheet)
205     {
206       var styleElement = aDocument.createElement("style");
207       styleElement.setAttribute("type", "text/css");
208       var textNode = aDocument.createTextNode("/* created by BlueGriffon */");
209       styleElement.appendChild(textNode);
210       aDocument.getElementsByTagName("head")[0].appendChild(styleElement);
211       stylesheet = styleElement.sheet;
212     }
213     return stylesheet;
214   },
215
216   addRuleForSelector: function CssUtils_addRuleForSelector(aDocument, aSelector, aDeclarations)
217   {
218     this.deleteAllLocalRulesForSelector(aDocument, aSelector, aDeclarations);
219     var ruleList = this.getAllLocalRulesForSelector(aDocument, aSelector);
220
221     if (!ruleList || !ruleList.length)
222     {
223       var stylesheet = this.getStyleSheetForScreen(aDocument);
224       var str = stylesheet.ownerNode.textContent;
225       str += "\n" + aSelector + " {";
226       for (var j = 0; j < aDeclarations.length; j++)
227       {
228         var property = aDeclarations[j].property;
229         var value = aDeclarations[j].value;
230         var priority = aDeclarations[j].priority;
231         str += "\n  " + property + ": " +
232                value +
233                (priority ? " !important;" : ";");
234       }
235       str += "\n}\n";
236       stylesheet.ownerNode.firstChild.data = str;
237       return;
238     }
239
240     var rule = ruleList[ruleList.length -1].rule;
241     for (var j = 0; j < aDeclarations.length; j++)
242     {
243         var property = aDeclarations[j].property;
244         var value = aDeclarations[j].value;
245         var priority = aDeclarations[j].priority ? " !important" : "";
246
247         rule.style.setProperty(property,
248                                value,
249                                priority);
250     }
251
252     this.reserializeEmbeddedStylesheet(rule.parentStyleSheet);
253   },
254
255   reserializeEmbeddedStylesheet: function CssUtils_reserializeEmbeddedStylesheet(aSheet)
256   {
257     var cssRules = aSheet.cssRules;
258     var str = "";
259     for (var i = 0; i < cssRules.length; i++)
260     {
261       var rule = cssRules[i];
262       switch (rule.type)
263       {
264         case CSSRule.CHARSET_RULE:
265         case CSSRule.IMPORT_RULE:
266           str += (i ? "\n" : "") + rule.cssText;
267           break;
268         case CSSRule.STYLE_RULE:
269           {
270             str += (i ? "\n" : "") + rule.selectorText + " {\n " +
271                    rule.style.cssText.replace( /;/g , ";\n");
272             /*var declarations = rule.style;
273             for (var j = 0; j < declarations.length; j++)
274             {
275               var property = declarations.item(j);
276               var value = declarations.getPropertyValue(property);
277               var priority = declarations.getPropertyPriority(property);
278               str += "\n  " + property + ": " +
279                      value +
280                      (priority ? ";" : " !important;");
281             }*/
282           }
283           break;
284         default:
285           break;
286       }
287       str += "}\n";
288     }
289     var styleElt = aSheet.ownerNode;
290     var child = styleElt.firstChild;
291     while (child)
292     {
293       var tmp = child.nextSibling;
294       styleElt.removeChild(child);
295       child = tmp;
296     }
297     var textNode = styleElt.ownerDocument.createTextNode(str);
298     styleElt.appendChild(textNode);
299   },
300
301   getUseCSSPref: function()
302   {
303     try {
304       var useCSS = GetPrefs().getIntPref("bluegriffon.css.policy");
305       return useCSS;
306     }
307     catch(e) { dump("Cannot get preference bluegriffon.css.policy; defaulting to HTML attributes") }
308
309     return 0;
310   }
311 };
312