commit extjs-2.2.1
[extjs.git] / source / util / CSS.js
1 /*\r
2  * Ext JS Library 2.2.1\r
3  * Copyright(c) 2006-2009, Ext JS, LLC.\r
4  * licensing@extjs.com\r
5  * \r
6  * http://extjs.com/license\r
7  */\r
8 \r
9 /**\r
10  * @class Ext.util.CSS\r
11  * Utility class for manipulating CSS rules\r
12  * @singleton\r
13  */\r
14 Ext.util.CSS = function(){\r
15         var rules = null;\r
16         var doc = document;\r
17 \r
18     var camelRe = /(-[a-z])/gi;\r
19     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };\r
20 \r
21    return {\r
22    /**\r
23     * Creates a stylesheet from a text blob of rules.\r
24     * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.\r
25     * @param {String} cssText The text containing the css rules\r
26     * @param {String} id An id to add to the stylesheet for later removal\r
27     * @return {StyleSheet}\r
28     */\r
29    createStyleSheet : function(cssText, id){\r
30        var ss;\r
31        var head = doc.getElementsByTagName("head")[0];\r
32        var rules = doc.createElement("style");\r
33        rules.setAttribute("type", "text/css");\r
34        if(id){\r
35            rules.setAttribute("id", id);\r
36        }\r
37        if(Ext.isIE){\r
38            head.appendChild(rules);\r
39            ss = rules.styleSheet;\r
40            ss.cssText = cssText;\r
41        }else{\r
42            try{\r
43                 rules.appendChild(doc.createTextNode(cssText));\r
44            }catch(e){\r
45                rules.cssText = cssText;\r
46            }\r
47            head.appendChild(rules);\r
48            ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);\r
49        }\r
50        this.cacheStyleSheet(ss);\r
51        return ss;\r
52    },\r
53 \r
54    /**\r
55     * Removes a style or link tag by id\r
56     * @param {String} id The id of the tag\r
57     */\r
58    removeStyleSheet : function(id){\r
59        var existing = doc.getElementById(id);\r
60        if(existing){\r
61            existing.parentNode.removeChild(existing);\r
62        }\r
63    },\r
64 \r
65    /**\r
66     * Dynamically swaps an existing stylesheet reference for a new one\r
67     * @param {String} id The id of an existing link tag to remove\r
68     * @param {String} url The href of the new stylesheet to include\r
69     */\r
70    swapStyleSheet : function(id, url){\r
71        this.removeStyleSheet(id);\r
72        var ss = doc.createElement("link");\r
73        ss.setAttribute("rel", "stylesheet");\r
74        ss.setAttribute("type", "text/css");\r
75        ss.setAttribute("id", id);\r
76        ss.setAttribute("href", url);\r
77        doc.getElementsByTagName("head")[0].appendChild(ss);\r
78    },\r
79    \r
80    /**\r
81     * Refresh the rule cache if you have dynamically added stylesheets\r
82     * @return {Object} An object (hash) of rules indexed by selector\r
83     */\r
84    refreshCache : function(){\r
85        return this.getRules(true);\r
86    },\r
87 \r
88    // private\r
89    cacheStyleSheet : function(ss){\r
90        if(!rules){\r
91            rules = {};\r
92        }\r
93        try{// try catch for cross domain access issue\r
94            var ssRules = ss.cssRules || ss.rules;\r
95            for(var j = ssRules.length-1; j >= 0; --j){\r
96                rules[ssRules[j].selectorText] = ssRules[j];\r
97            }\r
98        }catch(e){}\r
99    },\r
100    \r
101    /**\r
102     * Gets all css rules for the document\r
103     * @param {Boolean} refreshCache true to refresh the internal cache\r
104     * @return {Object} An object (hash) of rules indexed by selector\r
105     */\r
106    getRules : function(refreshCache){\r
107                 if(rules == null || refreshCache){\r
108                         rules = {};\r
109                         var ds = doc.styleSheets;\r
110                         for(var i =0, len = ds.length; i < len; i++){\r
111                             try{\r
112                         this.cacheStyleSheet(ds[i]);\r
113                     }catch(e){} \r
114                 }\r
115                 }\r
116                 return rules;\r
117         },\r
118         \r
119         /**\r
120     * Gets an an individual CSS rule by selector(s)\r
121     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.\r
122     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically\r
123     * @return {CSSRule} The CSS rule or null if one is not found\r
124     */\r
125    getRule : function(selector, refreshCache){\r
126                 var rs = this.getRules(refreshCache);\r
127                 if(!Ext.isArray(selector)){\r
128                     return rs[selector];\r
129                 }\r
130                 for(var i = 0; i < selector.length; i++){\r
131                         if(rs[selector[i]]){\r
132                                 return rs[selector[i]];\r
133                         }\r
134                 }\r
135                 return null;\r
136         },\r
137         \r
138         \r
139         /**\r
140     * Updates a rule property\r
141     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.\r
142     * @param {String} property The css property\r
143     * @param {String} value The new value for the property\r
144     * @return {Boolean} true If a rule was found and updated\r
145     */\r
146    updateRule : function(selector, property, value){\r
147                 if(!Ext.isArray(selector)){\r
148                         var rule = this.getRule(selector);\r
149                         if(rule){\r
150                                 rule.style[property.replace(camelRe, camelFn)] = value;\r
151                                 return true;\r
152                         }\r
153                 }else{\r
154                         for(var i = 0; i < selector.length; i++){\r
155                                 if(this.updateRule(selector[i], property, value)){\r
156                                         return true;\r
157                                 }\r
158                         }\r
159                 }\r
160                 return false;\r
161         }\r
162    };   \r
163 }();