Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / lib / selectivizr.js @ 3b463c5a

History | View | Annotate | Download (18.6 kB)

1 8d08f18a Kostas Papadimitriou
/*
2 8d08f18a Kostas Papadimitriou
selectivizr v1.0.2 - (c) Keith Clark, freely distributable under the terms 
3 8d08f18a Kostas Papadimitriou
of the MIT license.
4 8d08f18a Kostas Papadimitriou

5 8d08f18a Kostas Papadimitriou
selectivizr.com
6 8d08f18a Kostas Papadimitriou
*/
7 8d08f18a Kostas Papadimitriou
/* 
8 8d08f18a Kostas Papadimitriou
  
9 8d08f18a Kostas Papadimitriou
Notes about this source
10 8d08f18a Kostas Papadimitriou
-----------------------
11 8d08f18a Kostas Papadimitriou

12 8d08f18a Kostas Papadimitriou
 * The #DEBUG_START and #DEBUG_END comments are used to mark blocks of code
13 8d08f18a Kostas Papadimitriou
   that will be removed prior to building a final release version (using a
14 8d08f18a Kostas Papadimitriou
   pre-compression script)
15 8d08f18a Kostas Papadimitriou
  
16 8d08f18a Kostas Papadimitriou
  
17 8d08f18a Kostas Papadimitriou
References:
18 8d08f18a Kostas Papadimitriou
-----------
19 8d08f18a Kostas Papadimitriou
 
20 8d08f18a Kostas Papadimitriou
 * CSS Syntax          : http://www.w3.org/TR/2003/WD-css3-syntax-20030813/#style
21 8d08f18a Kostas Papadimitriou
 * Selectors           : http://www.w3.org/TR/css3-selectors/#selectors
22 8d08f18a Kostas Papadimitriou
 * IE Compatability    : http://msdn.microsoft.com/en-us/library/cc351024(VS.85).aspx
23 8d08f18a Kostas Papadimitriou
 * W3C Selector Tests  : http://www.w3.org/Style/CSS/Test/CSS3/Selectors/current/html/tests/
24 8d08f18a Kostas Papadimitriou
 
25 8d08f18a Kostas Papadimitriou
*/
26 8d08f18a Kostas Papadimitriou
27 8d08f18a Kostas Papadimitriou
(function(win) {
28 8d08f18a Kostas Papadimitriou
29 8d08f18a Kostas Papadimitriou
        // If browser isn't IE, then stop execution! This handles the script 
30 8d08f18a Kostas Papadimitriou
        // being loaded by non IE browsers because the developer didn't use 
31 8d08f18a Kostas Papadimitriou
        // conditional comments.
32 8d08f18a Kostas Papadimitriou
        if (/*@cc_on!@*/true) return;
33 8d08f18a Kostas Papadimitriou
34 8d08f18a Kostas Papadimitriou
        // =========================== Init Objects ============================
35 8d08f18a Kostas Papadimitriou
36 8d08f18a Kostas Papadimitriou
        var doc = document;
37 8d08f18a Kostas Papadimitriou
        var root = doc.documentElement;
38 8d08f18a Kostas Papadimitriou
        var xhr = getXHRObject();
39 8d08f18a Kostas Papadimitriou
        var ieVersion = /MSIE (\d+)/.exec(navigator.userAgent)[1];
40 8d08f18a Kostas Papadimitriou
        
41 8d08f18a Kostas Papadimitriou
        // If were not in standards mode, IE is too old / new or we can't create
42 8d08f18a Kostas Papadimitriou
        // an XMLHttpRequest object then we should get out now.
43 8d08f18a Kostas Papadimitriou
        if (doc.compatMode != 'CSS1Compat' || ieVersion<6 || ieVersion>8 || !xhr) {
44 8d08f18a Kostas Papadimitriou
                return;
45 8d08f18a Kostas Papadimitriou
        }
46 8d08f18a Kostas Papadimitriou
        
47 8d08f18a Kostas Papadimitriou
        
48 8d08f18a Kostas Papadimitriou
        // ========================= Common Objects ============================
49 8d08f18a Kostas Papadimitriou
50 8d08f18a Kostas Papadimitriou
        // Compatiable selector engines in order of CSS3 support. Note: '*' is
51 8d08f18a Kostas Papadimitriou
        // a placholder for the object key name. (basically, crude compression)
52 8d08f18a Kostas Papadimitriou
        var selectorEngines = {
53 8d08f18a Kostas Papadimitriou
                "NW"                                                                : "*.Dom.select",
54 8d08f18a Kostas Papadimitriou
                "MooTools"                                                        : "$$",
55 8d08f18a Kostas Papadimitriou
                "DOMAssistant"                                                : "*.$", 
56 8d08f18a Kostas Papadimitriou
                "Prototype"                                                        : "$$",
57 8d08f18a Kostas Papadimitriou
                "YAHOO"                                                                : "*.util.Selector.query",
58 8d08f18a Kostas Papadimitriou
                "Sizzle"                                                        : "*", 
59 8d08f18a Kostas Papadimitriou
                "jQuery"                                                        : "*",
60 8d08f18a Kostas Papadimitriou
                "dojo"                                                                : "*.query"
61 8d08f18a Kostas Papadimitriou
        };
62 8d08f18a Kostas Papadimitriou
63 8d08f18a Kostas Papadimitriou
        var selectorMethod;
64 8d08f18a Kostas Papadimitriou
        var enabledWatchers                                         = [];     // array of :enabled/:disabled elements to poll
65 8d08f18a Kostas Papadimitriou
        var ie6PatchID                                                         = 0;      // used to solve ie6's multiple class bug
66 8d08f18a Kostas Papadimitriou
        var patchIE6MultipleClasses                                = true;   // if true adds class bloat to ie6
67 8d08f18a Kostas Papadimitriou
        var namespace                                                         = "slvzr";
68 8d08f18a Kostas Papadimitriou
        
69 8d08f18a Kostas Papadimitriou
        // Stylesheet parsing regexp's
70 8d08f18a Kostas Papadimitriou
        var RE_COMMENT                                                        = /(\/\*[^*]*\*+([^\/][^*]*\*+)*\/)\s*/g;
71 8d08f18a Kostas Papadimitriou
        var RE_IMPORT                                                        = /@import\s*(?:(?:(?:url\(\s*(['"]?)(.*)\1)\s*\))|(?:(['"])(.*)\3))[^;]*;/g;
72 8d08f18a Kostas Papadimitriou
        var RE_ASSET_URL                                                 = /\burl\(\s*(["']?)(?!data:)([^"')]+)\1\s*\)/g;
73 8d08f18a Kostas Papadimitriou
        var RE_PSEUDO_STRUCTURAL                                = /^:(empty|(first|last|only|nth(-last)?)-(child|of-type))$/;
74 8d08f18a Kostas Papadimitriou
        var RE_PSEUDO_ELEMENTS                                        = /:(:first-(?:line|letter))/g;
75 8d08f18a Kostas Papadimitriou
        var RE_SELECTOR_GROUP                                        = /(^|})\s*([^\{]*?[\[:][^{]+)/g;
76 8d08f18a Kostas Papadimitriou
        var RE_SELECTOR_PARSE                                        = /([ +~>])|(:[a-z-]+(?:\(.*?\)+)?)|(\[.*?\])/g; 
77 8d08f18a Kostas Papadimitriou
        var RE_LIBRARY_INCOMPATIBLE_PSEUDOS                = /(:not\()?:(hover|enabled|disabled|focus|checked|target|active|visited|first-line|first-letter)\)?/g;
78 8d08f18a Kostas Papadimitriou
        var RE_PATCH_CLASS_NAME_REPLACE                        = /[^\w-]/g;
79 8d08f18a Kostas Papadimitriou
        
80 8d08f18a Kostas Papadimitriou
        // HTML UI element regexp's
81 8d08f18a Kostas Papadimitriou
        var RE_INPUT_ELEMENTS                                        = /^(INPUT|SELECT|TEXTAREA|BUTTON)$/;
82 8d08f18a Kostas Papadimitriou
        var RE_INPUT_CHECKABLE_TYPES                        = /^(checkbox|radio)$/;
83 8d08f18a Kostas Papadimitriou
84 8d08f18a Kostas Papadimitriou
        // Broken attribute selector implementations (IE7/8 native [^=""], [$=""] and [*=""])
85 8d08f18a Kostas Papadimitriou
        var BROKEN_ATTR_IMPLEMENTATIONS                        = ieVersion>6 ? /[\$\^*]=(['"])\1/ : null;
86 8d08f18a Kostas Papadimitriou
87 8d08f18a Kostas Papadimitriou
        // Whitespace normalization regexp's
88 8d08f18a Kostas Papadimitriou
        var RE_TIDY_TRAILING_WHITESPACE                        = /([(\[+~])\s+/g;
89 8d08f18a Kostas Papadimitriou
        var RE_TIDY_LEADING_WHITESPACE                        = /\s+([)\]+~])/g;
90 8d08f18a Kostas Papadimitriou
        var RE_TIDY_CONSECUTIVE_WHITESPACE                = /\s+/g;
91 8d08f18a Kostas Papadimitriou
        var RE_TIDY_TRIM_WHITESPACE                                = /^\s*((?:[\S\s]*\S)?)\s*$/;
92 8d08f18a Kostas Papadimitriou
        
93 8d08f18a Kostas Papadimitriou
        // String constants
94 8d08f18a Kostas Papadimitriou
        var EMPTY_STRING                                                = "";
95 8d08f18a Kostas Papadimitriou
        var SPACE_STRING                                                = " ";
96 8d08f18a Kostas Papadimitriou
        var PLACEHOLDER_STRING                                        = "$1";
97 8d08f18a Kostas Papadimitriou
98 8d08f18a Kostas Papadimitriou
        // =========================== Patching ================================
99 8d08f18a Kostas Papadimitriou
100 8d08f18a Kostas Papadimitriou
        // --[ patchStyleSheet() ]----------------------------------------------
101 8d08f18a Kostas Papadimitriou
        // Scans the passed cssText for selectors that require emulation and
102 8d08f18a Kostas Papadimitriou
        // creates one or more patches for each matched selector.
103 8d08f18a Kostas Papadimitriou
        function patchStyleSheet( cssText ) {
104 8d08f18a Kostas Papadimitriou
                return cssText.replace(RE_PSEUDO_ELEMENTS, PLACEHOLDER_STRING).
105 8d08f18a Kostas Papadimitriou
                        replace(RE_SELECTOR_GROUP, function(m, prefix, selectorText) {        
106 8d08f18a Kostas Papadimitriou
                            var selectorGroups = selectorText.split(",");
107 8d08f18a Kostas Papadimitriou
                            for (var c = 0, cs = selectorGroups.length; c < cs; c++) {
108 8d08f18a Kostas Papadimitriou
                                    var selector = normalizeSelectorWhitespace(selectorGroups[c]) + SPACE_STRING;
109 8d08f18a Kostas Papadimitriou
                                    var patches = [];
110 8d08f18a Kostas Papadimitriou
                                    selectorGroups[c] = selector.replace(RE_SELECTOR_PARSE, 
111 8d08f18a Kostas Papadimitriou
                                            function(match, combinator, pseudo, attribute, index) {
112 8d08f18a Kostas Papadimitriou
                                                    if (combinator) {
113 8d08f18a Kostas Papadimitriou
                                                            if (patches.length>0) {
114 8d08f18a Kostas Papadimitriou
                                                                    applyPatches( selector.substring(0, index), patches );
115 8d08f18a Kostas Papadimitriou
                                                                    patches = [];
116 8d08f18a Kostas Papadimitriou
                                                            }
117 8d08f18a Kostas Papadimitriou
                                                            return combinator;
118 8d08f18a Kostas Papadimitriou
                                                    }                
119 8d08f18a Kostas Papadimitriou
                                                    else {
120 8d08f18a Kostas Papadimitriou
                                                            var patch = (pseudo) ? patchPseudoClass( pseudo ) : patchAttribute( attribute );
121 8d08f18a Kostas Papadimitriou
                                                            if (patch) {
122 8d08f18a Kostas Papadimitriou
                                                                    patches.push(patch);
123 8d08f18a Kostas Papadimitriou
                                                                    return "." + patch.className;
124 8d08f18a Kostas Papadimitriou
                                                            }
125 8d08f18a Kostas Papadimitriou
                                                            return match;
126 8d08f18a Kostas Papadimitriou
                                                    }
127 8d08f18a Kostas Papadimitriou
                                            }
128 8d08f18a Kostas Papadimitriou
                                    );
129 8d08f18a Kostas Papadimitriou
                            }
130 8d08f18a Kostas Papadimitriou
                            return prefix + selectorGroups.join(",");
131 8d08f18a Kostas Papadimitriou
                    });
132 8d08f18a Kostas Papadimitriou
        };
133 8d08f18a Kostas Papadimitriou
134 8d08f18a Kostas Papadimitriou
        // --[ patchAttribute() ]-----------------------------------------------
135 8d08f18a Kostas Papadimitriou
        // returns a patch for an attribute selector.
136 8d08f18a Kostas Papadimitriou
        function patchAttribute( attr ) {
137 8d08f18a Kostas Papadimitriou
                return (!BROKEN_ATTR_IMPLEMENTATIONS || BROKEN_ATTR_IMPLEMENTATIONS.test(attr)) ? 
138 8d08f18a Kostas Papadimitriou
                        { className: createClassName(attr), applyClass: true } : null;
139 8d08f18a Kostas Papadimitriou
        };
140 8d08f18a Kostas Papadimitriou
141 8d08f18a Kostas Papadimitriou
        // --[ patchPseudoClass() ]---------------------------------------------
142 8d08f18a Kostas Papadimitriou
        // returns a patch for a pseudo-class
143 8d08f18a Kostas Papadimitriou
        function patchPseudoClass( pseudo ) {
144 8d08f18a Kostas Papadimitriou
145 8d08f18a Kostas Papadimitriou
                var applyClass = true;
146 8d08f18a Kostas Papadimitriou
                var className = createClassName(pseudo.slice(1));
147 8d08f18a Kostas Papadimitriou
                var isNegated = pseudo.substring(0, 5) == ":not(";
148 8d08f18a Kostas Papadimitriou
                var activateEventName;
149 8d08f18a Kostas Papadimitriou
                var deactivateEventName;
150 8d08f18a Kostas Papadimitriou
151 8d08f18a Kostas Papadimitriou
                // if negated, remove :not() 
152 8d08f18a Kostas Papadimitriou
                if (isNegated) {
153 8d08f18a Kostas Papadimitriou
                        pseudo = pseudo.slice(5, -1);
154 8d08f18a Kostas Papadimitriou
                }
155 8d08f18a Kostas Papadimitriou
                
156 8d08f18a Kostas Papadimitriou
                // bracket contents are irrelevant - remove them
157 8d08f18a Kostas Papadimitriou
                var bracketIndex = pseudo.indexOf("(")
158 8d08f18a Kostas Papadimitriou
                if (bracketIndex > -1) {
159 8d08f18a Kostas Papadimitriou
                        pseudo = pseudo.substring(0, bracketIndex);
160 8d08f18a Kostas Papadimitriou
                }                
161 8d08f18a Kostas Papadimitriou
                
162 8d08f18a Kostas Papadimitriou
                // check we're still dealing with a pseudo-class
163 8d08f18a Kostas Papadimitriou
                if (pseudo.charAt(0) == ":") {
164 8d08f18a Kostas Papadimitriou
                        switch (pseudo.slice(1)) {
165 8d08f18a Kostas Papadimitriou
166 8d08f18a Kostas Papadimitriou
                                case "root":
167 8d08f18a Kostas Papadimitriou
                                        applyClass = function(e) {
168 8d08f18a Kostas Papadimitriou
                                                return isNegated ? e != root : e == root;
169 8d08f18a Kostas Papadimitriou
                                        }
170 8d08f18a Kostas Papadimitriou
                                        break;
171 8d08f18a Kostas Papadimitriou
172 8d08f18a Kostas Papadimitriou
                                case "target":
173 8d08f18a Kostas Papadimitriou
                                        // :target is only supported in IE8
174 8d08f18a Kostas Papadimitriou
                                        if (ieVersion == 8) {
175 8d08f18a Kostas Papadimitriou
                                                applyClass = function(e) {
176 8d08f18a Kostas Papadimitriou
                                                        var handler = function() { 
177 8d08f18a Kostas Papadimitriou
                                                                var hash = location.hash;
178 8d08f18a Kostas Papadimitriou
                                                                var hashID = hash.slice(1);
179 8d08f18a Kostas Papadimitriou
                                                                return isNegated ? (hash == EMPTY_STRING || e.id != hashID) : (hash != EMPTY_STRING && e.id == hashID);
180 8d08f18a Kostas Papadimitriou
                                                        };
181 8d08f18a Kostas Papadimitriou
                                                        addEvent( win, "hashchange", function() {
182 8d08f18a Kostas Papadimitriou
                                                                toggleElementClass(e, className, handler());
183 8d08f18a Kostas Papadimitriou
                                                        })
184 8d08f18a Kostas Papadimitriou
                                                        return handler();
185 8d08f18a Kostas Papadimitriou
                                                }
186 8d08f18a Kostas Papadimitriou
                                                break;
187 8d08f18a Kostas Papadimitriou
                                        }
188 8d08f18a Kostas Papadimitriou
                                        return false;
189 8d08f18a Kostas Papadimitriou
                                
190 8d08f18a Kostas Papadimitriou
                                case "checked":
191 8d08f18a Kostas Papadimitriou
                                        applyClass = function(e) { 
192 8d08f18a Kostas Papadimitriou
                                                if (RE_INPUT_CHECKABLE_TYPES.test(e.type)) {
193 8d08f18a Kostas Papadimitriou
                                                        addEvent( e, "propertychange", function() {
194 8d08f18a Kostas Papadimitriou
                                                                if (event.propertyName == "checked") {
195 8d08f18a Kostas Papadimitriou
                                                                        toggleElementClass( e, className, e.checked !== isNegated );
196 8d08f18a Kostas Papadimitriou
                                                                }                                                         
197 8d08f18a Kostas Papadimitriou
                                                        })
198 8d08f18a Kostas Papadimitriou
                                                }
199 8d08f18a Kostas Papadimitriou
                                                return e.checked !== isNegated;
200 8d08f18a Kostas Papadimitriou
                                        }
201 8d08f18a Kostas Papadimitriou
                                        break;
202 8d08f18a Kostas Papadimitriou
                                        
203 8d08f18a Kostas Papadimitriou
                                case "disabled":
204 8d08f18a Kostas Papadimitriou
                                        isNegated = !isNegated;
205 8d08f18a Kostas Papadimitriou
206 8d08f18a Kostas Papadimitriou
                                case "enabled":
207 8d08f18a Kostas Papadimitriou
                                        applyClass = function(e) { 
208 8d08f18a Kostas Papadimitriou
                                                if (RE_INPUT_ELEMENTS.test(e.tagName)) {
209 8d08f18a Kostas Papadimitriou
                                                        addEvent( e, "propertychange", function() {
210 8d08f18a Kostas Papadimitriou
                                                                if (event.propertyName == "$disabled") {
211 8d08f18a Kostas Papadimitriou
                                                                        toggleElementClass( e, className, e.$disabled === isNegated );
212 8d08f18a Kostas Papadimitriou
                                                                } 
213 8d08f18a Kostas Papadimitriou
                                                        });
214 8d08f18a Kostas Papadimitriou
                                                        enabledWatchers.push(e);
215 8d08f18a Kostas Papadimitriou
                                                        e.$disabled = e.disabled;
216 8d08f18a Kostas Papadimitriou
                                                        return e.disabled === isNegated;
217 8d08f18a Kostas Papadimitriou
                                                }
218 8d08f18a Kostas Papadimitriou
                                                return pseudo == ":enabled" ? isNegated : !isNegated;
219 8d08f18a Kostas Papadimitriou
                                        }
220 8d08f18a Kostas Papadimitriou
                                        break;
221 8d08f18a Kostas Papadimitriou
                                        
222 8d08f18a Kostas Papadimitriou
                                case "focus":
223 8d08f18a Kostas Papadimitriou
                                        activateEventName = "focus";
224 8d08f18a Kostas Papadimitriou
                                        deactivateEventName = "blur";
225 8d08f18a Kostas Papadimitriou
                                                                
226 8d08f18a Kostas Papadimitriou
                                case "hover":
227 8d08f18a Kostas Papadimitriou
                                        if (!activateEventName) {
228 8d08f18a Kostas Papadimitriou
                                                activateEventName = "mouseenter";
229 8d08f18a Kostas Papadimitriou
                                                deactivateEventName = "mouseleave";
230 8d08f18a Kostas Papadimitriou
                                        }
231 8d08f18a Kostas Papadimitriou
                                        applyClass = function(e) {
232 8d08f18a Kostas Papadimitriou
                                                addEvent( e, isNegated ? deactivateEventName : activateEventName, function() {
233 8d08f18a Kostas Papadimitriou
                                                        toggleElementClass( e, className, true );
234 8d08f18a Kostas Papadimitriou
                                                })
235 8d08f18a Kostas Papadimitriou
                                                addEvent( e, isNegated ? activateEventName : deactivateEventName, function() {
236 8d08f18a Kostas Papadimitriou
                                                        toggleElementClass( e, className, false );
237 8d08f18a Kostas Papadimitriou
                                                })
238 8d08f18a Kostas Papadimitriou
                                                return isNegated;
239 8d08f18a Kostas Papadimitriou
                                        }
240 8d08f18a Kostas Papadimitriou
                                        break;
241 8d08f18a Kostas Papadimitriou
                                        
242 8d08f18a Kostas Papadimitriou
                                // everything else
243 8d08f18a Kostas Papadimitriou
                                default:
244 8d08f18a Kostas Papadimitriou
                                        // If we don't support this pseudo-class don't create 
245 8d08f18a Kostas Papadimitriou
                                        // a patch for it
246 8d08f18a Kostas Papadimitriou
                                        if (!RE_PSEUDO_STRUCTURAL.test(pseudo)) {
247 8d08f18a Kostas Papadimitriou
                                                return false;
248 8d08f18a Kostas Papadimitriou
                                        }
249 8d08f18a Kostas Papadimitriou
                                        break;
250 8d08f18a Kostas Papadimitriou
                        }
251 8d08f18a Kostas Papadimitriou
                }
252 8d08f18a Kostas Papadimitriou
                return { className: className, applyClass: applyClass };
253 8d08f18a Kostas Papadimitriou
        };
254 8d08f18a Kostas Papadimitriou
255 8d08f18a Kostas Papadimitriou
        // --[ applyPatches() ]-------------------------------------------------
256 8d08f18a Kostas Papadimitriou
        // uses the passed selector text to find DOM nodes and patch them        
257 8d08f18a Kostas Papadimitriou
        function applyPatches(selectorText, patches) {
258 8d08f18a Kostas Papadimitriou
                var elms;
259 8d08f18a Kostas Papadimitriou
                
260 8d08f18a Kostas Papadimitriou
                // Although some selector libraries can find :checked :enabled etc. 
261 8d08f18a Kostas Papadimitriou
                // we need to find all elements that could have that state because 
262 8d08f18a Kostas Papadimitriou
                // it can be changed by the user.
263 8d08f18a Kostas Papadimitriou
                var domSelectorText = selectorText.replace(RE_LIBRARY_INCOMPATIBLE_PSEUDOS, EMPTY_STRING);
264 8d08f18a Kostas Papadimitriou
                
265 8d08f18a Kostas Papadimitriou
                // If the dom selector equates to an empty string or ends with 
266 8d08f18a Kostas Papadimitriou
                // whitespace then we need to append a universal selector (*) to it.
267 8d08f18a Kostas Papadimitriou
                if (domSelectorText == EMPTY_STRING || domSelectorText.charAt(domSelectorText.length - 1) == SPACE_STRING) {
268 8d08f18a Kostas Papadimitriou
                        domSelectorText += "*";
269 8d08f18a Kostas Papadimitriou
                }
270 8d08f18a Kostas Papadimitriou
                
271 8d08f18a Kostas Papadimitriou
                // Ensure we catch errors from the selector library
272 8d08f18a Kostas Papadimitriou
                try {
273 8d08f18a Kostas Papadimitriou
                        elms = selectorMethod( domSelectorText );
274 8d08f18a Kostas Papadimitriou
                } catch (ex) {
275 8d08f18a Kostas Papadimitriou
                        // #DEBUG_START
276 8d08f18a Kostas Papadimitriou
                        log( "Selector '" + selectorText + "' threw exception '" + ex + "'" );
277 8d08f18a Kostas Papadimitriou
                        // #DEBUG_END
278 8d08f18a Kostas Papadimitriou
                }
279 8d08f18a Kostas Papadimitriou
280 8d08f18a Kostas Papadimitriou
281 8d08f18a Kostas Papadimitriou
                if (elms) {
282 8d08f18a Kostas Papadimitriou
                        for (var d = 0, dl = elms.length; d < dl; d++) {        
283 8d08f18a Kostas Papadimitriou
                                var elm = elms[d];
284 8d08f18a Kostas Papadimitriou
                                var cssClasses = elm.className;
285 8d08f18a Kostas Papadimitriou
                                for (var f = 0, fl = patches.length; f < fl; f++) {
286 8d08f18a Kostas Papadimitriou
                                        var patch = patches[f];
287 8d08f18a Kostas Papadimitriou
                                        
288 8d08f18a Kostas Papadimitriou
                                        if (!hasPatch(elm, patch)) {
289 8d08f18a Kostas Papadimitriou
                                                if (patch.applyClass && (patch.applyClass === true || patch.applyClass(elm) === true)) {
290 8d08f18a Kostas Papadimitriou
                                                        cssClasses = toggleClass(cssClasses, patch.className, true );
291 8d08f18a Kostas Papadimitriou
                                                }
292 8d08f18a Kostas Papadimitriou
                                        }
293 8d08f18a Kostas Papadimitriou
                                }
294 8d08f18a Kostas Papadimitriou
                                elm.className = cssClasses;
295 8d08f18a Kostas Papadimitriou
                        }
296 8d08f18a Kostas Papadimitriou
                }
297 8d08f18a Kostas Papadimitriou
        };
298 8d08f18a Kostas Papadimitriou
299 8d08f18a Kostas Papadimitriou
        // --[ hasPatch() ]-----------------------------------------------------
300 8d08f18a Kostas Papadimitriou
        // checks for the exsistence of a patch on an element
301 8d08f18a Kostas Papadimitriou
        function hasPatch( elm, patch ) {
302 8d08f18a Kostas Papadimitriou
                return new RegExp("(^|\\s)" + patch.className + "(\\s|$)").test(elm.className);
303 8d08f18a Kostas Papadimitriou
        };
304 8d08f18a Kostas Papadimitriou
        
305 8d08f18a Kostas Papadimitriou
        
306 8d08f18a Kostas Papadimitriou
        // =========================== Utility =================================
307 8d08f18a Kostas Papadimitriou
        
308 8d08f18a Kostas Papadimitriou
        function createClassName( className ) {
309 8d08f18a Kostas Papadimitriou
                return namespace + "-" + ((ieVersion == 6 && patchIE6MultipleClasses) ?
310 8d08f18a Kostas Papadimitriou
                        ie6PatchID++
311 8d08f18a Kostas Papadimitriou
                :
312 8d08f18a Kostas Papadimitriou
                        className.replace(RE_PATCH_CLASS_NAME_REPLACE, function(a) { return a.charCodeAt(0) }));
313 8d08f18a Kostas Papadimitriou
        };
314 8d08f18a Kostas Papadimitriou
315 8d08f18a Kostas Papadimitriou
        // --[ log() ]----------------------------------------------------------
316 8d08f18a Kostas Papadimitriou
        // #DEBUG_START
317 8d08f18a Kostas Papadimitriou
        function log( message ) {
318 8d08f18a Kostas Papadimitriou
                if (win.console) {
319 8d08f18a Kostas Papadimitriou
                        win.console.log(message);
320 8d08f18a Kostas Papadimitriou
                }
321 8d08f18a Kostas Papadimitriou
        };
322 8d08f18a Kostas Papadimitriou
        // #DEBUG_END
323 8d08f18a Kostas Papadimitriou
324 8d08f18a Kostas Papadimitriou
        // --[ trim() ]---------------------------------------------------------
325 8d08f18a Kostas Papadimitriou
        // removes leading, trailing whitespace from a string
326 8d08f18a Kostas Papadimitriou
        function trim( text ) {
327 8d08f18a Kostas Papadimitriou
                return text.replace(RE_TIDY_TRIM_WHITESPACE, PLACEHOLDER_STRING);
328 8d08f18a Kostas Papadimitriou
        };
329 8d08f18a Kostas Papadimitriou
330 8d08f18a Kostas Papadimitriou
        // --[ normalizeWhitespace() ]------------------------------------------
331 8d08f18a Kostas Papadimitriou
        // removes leading, trailing and consecutive whitespace from a string
332 8d08f18a Kostas Papadimitriou
        function normalizeWhitespace( text ) {
333 8d08f18a Kostas Papadimitriou
                return trim(text).replace(RE_TIDY_CONSECUTIVE_WHITESPACE, SPACE_STRING);
334 8d08f18a Kostas Papadimitriou
        };
335 8d08f18a Kostas Papadimitriou
336 8d08f18a Kostas Papadimitriou
        // --[ normalizeSelectorWhitespace() ]----------------------------------
337 8d08f18a Kostas Papadimitriou
        // tidies whitespace around selector brackets and combinators
338 8d08f18a Kostas Papadimitriou
        function normalizeSelectorWhitespace( selectorText ) {
339 8d08f18a Kostas Papadimitriou
                return normalizeWhitespace(selectorText.
340 8d08f18a Kostas Papadimitriou
                        replace(RE_TIDY_TRAILING_WHITESPACE, PLACEHOLDER_STRING).
341 8d08f18a Kostas Papadimitriou
                        replace(RE_TIDY_LEADING_WHITESPACE, PLACEHOLDER_STRING)
342 8d08f18a Kostas Papadimitriou
                );
343 8d08f18a Kostas Papadimitriou
        };
344 8d08f18a Kostas Papadimitriou
345 8d08f18a Kostas Papadimitriou
        // --[ toggleElementClass() ]-------------------------------------------
346 8d08f18a Kostas Papadimitriou
        // toggles a single className on an element
347 8d08f18a Kostas Papadimitriou
        function toggleElementClass( elm, className, on ) {
348 8d08f18a Kostas Papadimitriou
                var oldClassName = elm.className;
349 8d08f18a Kostas Papadimitriou
                var newClassName = toggleClass(oldClassName, className, on);
350 8d08f18a Kostas Papadimitriou
                if (newClassName != oldClassName) {
351 8d08f18a Kostas Papadimitriou
                        elm.className = newClassName;
352 8d08f18a Kostas Papadimitriou
                        elm.parentNode.className += EMPTY_STRING;
353 8d08f18a Kostas Papadimitriou
                }
354 8d08f18a Kostas Papadimitriou
        };
355 8d08f18a Kostas Papadimitriou
356 8d08f18a Kostas Papadimitriou
        // --[ toggleClass() ]--------------------------------------------------
357 8d08f18a Kostas Papadimitriou
        // adds / removes a className from a string of classNames. Used to 
358 8d08f18a Kostas Papadimitriou
        // manage multiple class changes without forcing a DOM redraw
359 8d08f18a Kostas Papadimitriou
        function toggleClass( classList, className, on ) {
360 8d08f18a Kostas Papadimitriou
                var re = RegExp("(^|\\s)" + className + "(\\s|$)");
361 8d08f18a Kostas Papadimitriou
                var classExists = re.test(classList);
362 8d08f18a Kostas Papadimitriou
                if (on) {
363 8d08f18a Kostas Papadimitriou
                        return classExists ? classList : classList + SPACE_STRING + className;
364 8d08f18a Kostas Papadimitriou
                } else {
365 8d08f18a Kostas Papadimitriou
                        return classExists ? trim(classList.replace(re, PLACEHOLDER_STRING)) : classList;
366 8d08f18a Kostas Papadimitriou
                }
367 8d08f18a Kostas Papadimitriou
        };
368 8d08f18a Kostas Papadimitriou
        
369 8d08f18a Kostas Papadimitriou
        // --[ addEvent() ]-----------------------------------------------------
370 8d08f18a Kostas Papadimitriou
        function addEvent(elm, eventName, eventHandler) {
371 8d08f18a Kostas Papadimitriou
                elm.attachEvent("on" + eventName, eventHandler);
372 8d08f18a Kostas Papadimitriou
        };
373 8d08f18a Kostas Papadimitriou
374 8d08f18a Kostas Papadimitriou
        // --[ getXHRObject() ]-------------------------------------------------
375 8d08f18a Kostas Papadimitriou
        function getXHRObject()
376 8d08f18a Kostas Papadimitriou
        {
377 8d08f18a Kostas Papadimitriou
                if (win.XMLHttpRequest) {
378 8d08f18a Kostas Papadimitriou
                        return new XMLHttpRequest;
379 8d08f18a Kostas Papadimitriou
                }
380 8d08f18a Kostas Papadimitriou
                try        { 
381 8d08f18a Kostas Papadimitriou
                        return new ActiveXObject('Microsoft.XMLHTTP');
382 8d08f18a Kostas Papadimitriou
                } catch(e) { 
383 8d08f18a Kostas Papadimitriou
                        return null;
384 8d08f18a Kostas Papadimitriou
                }
385 8d08f18a Kostas Papadimitriou
        };
386 8d08f18a Kostas Papadimitriou
387 8d08f18a Kostas Papadimitriou
        // --[ loadStyleSheet() ]-----------------------------------------------
388 8d08f18a Kostas Papadimitriou
        function loadStyleSheet( url ) {
389 8d08f18a Kostas Papadimitriou
                xhr.open("GET", url, false);
390 8d08f18a Kostas Papadimitriou
                xhr.send();
391 8d08f18a Kostas Papadimitriou
                return (xhr.status==200) ? xhr.responseText : EMPTY_STRING;        
392 8d08f18a Kostas Papadimitriou
        };
393 8d08f18a Kostas Papadimitriou
        
394 8d08f18a Kostas Papadimitriou
        // --[ resolveUrl() ]---------------------------------------------------
395 8d08f18a Kostas Papadimitriou
        // Converts a URL fragment to a fully qualified URL using the specified
396 8d08f18a Kostas Papadimitriou
        // context URL. Returns null if same-origin policy is broken
397 8d08f18a Kostas Papadimitriou
        function resolveUrl( url, contextUrl ) {
398 8d08f18a Kostas Papadimitriou
        
399 8d08f18a Kostas Papadimitriou
                function getProtocolAndHost( url ) {
400 8d08f18a Kostas Papadimitriou
                        return url.substring(0, url.indexOf("/", 8));
401 8d08f18a Kostas Papadimitriou
                };
402 8d08f18a Kostas Papadimitriou
                
403 8d08f18a Kostas Papadimitriou
                // absolute path
404 8d08f18a Kostas Papadimitriou
                if (/^https?:\/\//i.test(url)) {
405 8d08f18a Kostas Papadimitriou
                        return getProtocolAndHost(contextUrl) == getProtocolAndHost(url) ? url : null;
406 8d08f18a Kostas Papadimitriou
                }
407 8d08f18a Kostas Papadimitriou
                
408 8d08f18a Kostas Papadimitriou
                // root-relative path
409 8d08f18a Kostas Papadimitriou
                if (url.charAt(0)=="/")        {
410 8d08f18a Kostas Papadimitriou
                        return getProtocolAndHost(contextUrl) + url;
411 8d08f18a Kostas Papadimitriou
                }
412 8d08f18a Kostas Papadimitriou
413 8d08f18a Kostas Papadimitriou
                // relative path
414 8d08f18a Kostas Papadimitriou
                var contextUrlPath = contextUrl.split(/[?#]/)[0]; // ignore query string in the contextUrl        
415 8d08f18a Kostas Papadimitriou
                if (url.charAt(0) != "?" && contextUrlPath.charAt(contextUrlPath.length - 1) != "/") {
416 8d08f18a Kostas Papadimitriou
                        contextUrlPath = contextUrlPath.substring(0, contextUrlPath.lastIndexOf("/") + 1);
417 8d08f18a Kostas Papadimitriou
                }
418 8d08f18a Kostas Papadimitriou
                
419 8d08f18a Kostas Papadimitriou
                return contextUrlPath + url;
420 8d08f18a Kostas Papadimitriou
        };
421 8d08f18a Kostas Papadimitriou
        
422 8d08f18a Kostas Papadimitriou
        // --[ parseStyleSheet() ]----------------------------------------------
423 8d08f18a Kostas Papadimitriou
        // Downloads the stylesheet specified by the URL, removes it's comments
424 8d08f18a Kostas Papadimitriou
        // and recursivly replaces @import rules with their contents, ultimately
425 8d08f18a Kostas Papadimitriou
        // returning the full cssText.
426 8d08f18a Kostas Papadimitriou
        function parseStyleSheet( url ) {
427 8d08f18a Kostas Papadimitriou
                if (url) {
428 8d08f18a Kostas Papadimitriou
                        return loadStyleSheet(url).replace(RE_COMMENT, EMPTY_STRING).
429 8d08f18a Kostas Papadimitriou
                        replace(RE_IMPORT, function( match, quoteChar, importUrl, quoteChar2, importUrl2 ) { 
430 8d08f18a Kostas Papadimitriou
                                return parseStyleSheet(resolveUrl(importUrl || importUrl2, url));
431 8d08f18a Kostas Papadimitriou
                        }).
432 8d08f18a Kostas Papadimitriou
                        replace(RE_ASSET_URL, function( match, quoteChar, assetUrl ) { 
433 8d08f18a Kostas Papadimitriou
                                quoteChar = quoteChar || EMPTY_STRING;
434 8d08f18a Kostas Papadimitriou
                                return " url(" + quoteChar + resolveUrl(assetUrl, url) + quoteChar + ") "; 
435 8d08f18a Kostas Papadimitriou
                        });
436 8d08f18a Kostas Papadimitriou
                }
437 8d08f18a Kostas Papadimitriou
                return EMPTY_STRING;
438 8d08f18a Kostas Papadimitriou
        };
439 8d08f18a Kostas Papadimitriou
        
440 8d08f18a Kostas Papadimitriou
        // --[ init() ]---------------------------------------------------------
441 8d08f18a Kostas Papadimitriou
        function init() {
442 8d08f18a Kostas Papadimitriou
                // honour the <base> tag
443 8d08f18a Kostas Papadimitriou
                var url, stylesheet;
444 8d08f18a Kostas Papadimitriou
                var baseTags = doc.getElementsByTagName("BASE");
445 8d08f18a Kostas Papadimitriou
                var baseUrl = (baseTags.length > 0) ? baseTags[0].href : doc.location.href;
446 8d08f18a Kostas Papadimitriou
                
447 8d08f18a Kostas Papadimitriou
                /* Note: This code prevents IE from freezing / crashing when using 
448 8d08f18a Kostas Papadimitriou
                @font-face .eot files but it modifies the <head> tag and could
449 8d08f18a Kostas Papadimitriou
                trigger the IE stylesheet limit. It will also cause FOUC issues.
450 8d08f18a Kostas Papadimitriou
                If you choose to use it, make sure you comment out the for loop 
451 8d08f18a Kostas Papadimitriou
                directly below this comment.
452 8d08f18a Kostas Papadimitriou

453 8d08f18a Kostas Papadimitriou
                var head = doc.getElementsByTagName("head")[0];
454 8d08f18a Kostas Papadimitriou
                for (var c=doc.styleSheets.length-1; c>=0; c--) {
455 8d08f18a Kostas Papadimitriou
                        stylesheet = doc.styleSheets[c]
456 8d08f18a Kostas Papadimitriou
                        head.appendChild(doc.createElement("style"))
457 8d08f18a Kostas Papadimitriou
                        var patchedStylesheet = doc.styleSheets[doc.styleSheets.length-1];
458 8d08f18a Kostas Papadimitriou
                        
459 8d08f18a Kostas Papadimitriou
                        if (stylesheet.href != EMPTY_STRING) {
460 8d08f18a Kostas Papadimitriou
                                url = resolveUrl(stylesheet.href, baseUrl)
461 8d08f18a Kostas Papadimitriou
                                if (url) {
462 8d08f18a Kostas Papadimitriou
                                        patchedStylesheet.cssText = patchStyleSheet( parseStyleSheet( url ) )
463 8d08f18a Kostas Papadimitriou
                                        stylesheet.disabled = true
464 8d08f18a Kostas Papadimitriou
                                        setTimeout( function () {
465 8d08f18a Kostas Papadimitriou
                                                stylesheet.owningElement.parentNode.removeChild(stylesheet.owningElement)
466 8d08f18a Kostas Papadimitriou
                                        })
467 8d08f18a Kostas Papadimitriou
                                }
468 8d08f18a Kostas Papadimitriou
                        }
469 8d08f18a Kostas Papadimitriou
                }
470 8d08f18a Kostas Papadimitriou
                */
471 8d08f18a Kostas Papadimitriou
                
472 8d08f18a Kostas Papadimitriou
                for (var c = 0; c < doc.styleSheets.length; c++) {
473 8d08f18a Kostas Papadimitriou
                        stylesheet = doc.styleSheets[c]
474 8d08f18a Kostas Papadimitriou
                        if (stylesheet.href != EMPTY_STRING) {
475 8d08f18a Kostas Papadimitriou
                                url = resolveUrl(stylesheet.href, baseUrl);
476 8d08f18a Kostas Papadimitriou
                                if (url) {
477 8d08f18a Kostas Papadimitriou
                                        stylesheet.cssText = patchStyleSheet( parseStyleSheet( url ) );
478 8d08f18a Kostas Papadimitriou
                                }
479 8d08f18a Kostas Papadimitriou
                        }
480 8d08f18a Kostas Papadimitriou
                }
481 8d08f18a Kostas Papadimitriou
                
482 8d08f18a Kostas Papadimitriou
                // :enabled & :disabled polling script (since we can't hook 
483 8d08f18a Kostas Papadimitriou
                // onpropertychange event when an element is disabled) 
484 8d08f18a Kostas Papadimitriou
                if (enabledWatchers.length > 0) {
485 8d08f18a Kostas Papadimitriou
                        setInterval( function() {
486 8d08f18a Kostas Papadimitriou
                                for (var c = 0, cl = enabledWatchers.length; c < cl; c++) {
487 8d08f18a Kostas Papadimitriou
                                        var e = enabledWatchers[c];
488 8d08f18a Kostas Papadimitriou
                                        if (e.disabled !== e.$disabled) {
489 8d08f18a Kostas Papadimitriou
                                                if (e.disabled) {
490 8d08f18a Kostas Papadimitriou
                                                        e.disabled = false;
491 8d08f18a Kostas Papadimitriou
                                                        e.$disabled = true;
492 8d08f18a Kostas Papadimitriou
                                                        e.disabled = true;
493 8d08f18a Kostas Papadimitriou
                                                }
494 8d08f18a Kostas Papadimitriou
                                                else {
495 8d08f18a Kostas Papadimitriou
                                                        e.$disabled = e.disabled;
496 8d08f18a Kostas Papadimitriou
                                                }
497 8d08f18a Kostas Papadimitriou
                                        }
498 8d08f18a Kostas Papadimitriou
                                }
499 8d08f18a Kostas Papadimitriou
                        },250)
500 8d08f18a Kostas Papadimitriou
                }
501 8d08f18a Kostas Papadimitriou
        };
502 8d08f18a Kostas Papadimitriou
        
503 8d08f18a Kostas Papadimitriou
        // Bind selectivizr to the ContentLoaded event. 
504 8d08f18a Kostas Papadimitriou
        ContentLoaded(win, function() {
505 8d08f18a Kostas Papadimitriou
                // Determine the "best fit" selector engine
506 8d08f18a Kostas Papadimitriou
                for (var engine in selectorEngines) {
507 8d08f18a Kostas Papadimitriou
                        var members, member, context = win;
508 8d08f18a Kostas Papadimitriou
                        if (win[engine]) {
509 8d08f18a Kostas Papadimitriou
                                members = selectorEngines[engine].replace("*", engine).split(".");
510 8d08f18a Kostas Papadimitriou
                                while ((member = members.shift()) && (context = context[member])) {}
511 8d08f18a Kostas Papadimitriou
                                if (typeof context == "function") {
512 8d08f18a Kostas Papadimitriou
                                        selectorMethod = context;
513 8d08f18a Kostas Papadimitriou
                                        init();
514 8d08f18a Kostas Papadimitriou
                                        return;
515 8d08f18a Kostas Papadimitriou
                                }
516 8d08f18a Kostas Papadimitriou
                        }
517 8d08f18a Kostas Papadimitriou
                }
518 8d08f18a Kostas Papadimitriou
        });
519 8d08f18a Kostas Papadimitriou
        
520 8d08f18a Kostas Papadimitriou
        
521 8d08f18a Kostas Papadimitriou
        /*!
522 8d08f18a Kostas Papadimitriou
         * ContentLoaded.js by Diego Perini, modified for IE<9 only (to save space)
523 8d08f18a Kostas Papadimitriou
         *
524 8d08f18a Kostas Papadimitriou
         * Author: Diego Perini (diego.perini at gmail.com)
525 8d08f18a Kostas Papadimitriou
         * Summary: cross-browser wrapper for DOMContentLoaded
526 8d08f18a Kostas Papadimitriou
         * Updated: 20101020
527 8d08f18a Kostas Papadimitriou
         * License: MIT
528 8d08f18a Kostas Papadimitriou
         * Version: 1.2
529 8d08f18a Kostas Papadimitriou
         *
530 8d08f18a Kostas Papadimitriou
         * URL:
531 8d08f18a Kostas Papadimitriou
         * http://javascript.nwbox.com/ContentLoaded/
532 8d08f18a Kostas Papadimitriou
         * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
533 8d08f18a Kostas Papadimitriou
         *
534 8d08f18a Kostas Papadimitriou
         */
535 8d08f18a Kostas Papadimitriou
536 8d08f18a Kostas Papadimitriou
        // @w window reference
537 8d08f18a Kostas Papadimitriou
        // @f function reference
538 8d08f18a Kostas Papadimitriou
        function ContentLoaded(win, fn) {
539 8d08f18a Kostas Papadimitriou
540 8d08f18a Kostas Papadimitriou
                var done = false, top = true,
541 8d08f18a Kostas Papadimitriou
                init = function(e) {
542 8d08f18a Kostas Papadimitriou
                        if (e.type == "readystatechange" && doc.readyState != "complete") return;
543 8d08f18a Kostas Papadimitriou
                        (e.type == "load" ? win : doc).detachEvent("on" + e.type, init, false);
544 8d08f18a Kostas Papadimitriou
                        if (!done && (done = true)) fn.call(win, e.type || e);
545 8d08f18a Kostas Papadimitriou
                },
546 8d08f18a Kostas Papadimitriou
                poll = function() {
547 8d08f18a Kostas Papadimitriou
                        try { root.doScroll("left"); } catch(e) { setTimeout(poll, 50); return; }
548 8d08f18a Kostas Papadimitriou
                        init('poll');
549 8d08f18a Kostas Papadimitriou
                };
550 8d08f18a Kostas Papadimitriou
551 8d08f18a Kostas Papadimitriou
                if (doc.readyState == "complete") fn.call(win, EMPTY_STRING);
552 8d08f18a Kostas Papadimitriou
                else {
553 8d08f18a Kostas Papadimitriou
                        if (doc.createEventObject && root.doScroll) {
554 8d08f18a Kostas Papadimitriou
                                try { top = !win.frameElement; } catch(e) { }
555 8d08f18a Kostas Papadimitriou
                                if (top) poll();
556 8d08f18a Kostas Papadimitriou
                        }
557 8d08f18a Kostas Papadimitriou
                        addEvent(doc,"readystatechange", init);
558 8d08f18a Kostas Papadimitriou
                        addEvent(win,"load", init);
559 8d08f18a Kostas Papadimitriou
                }
560 8d08f18a Kostas Papadimitriou
        };
561 8d08f18a Kostas Papadimitriou
})(this);