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