1/* 2 * JSS v0.3 - JavaScript Stylesheets 3 * https://github.com/Box9/jss 4 * 5 * Copyright (c) 2011, David Tang 6 * MIT Licensed (http://www.opensource.org/licenses/mit-license.php) 7 */ 8 9var jss = (function (undefined) { 10 var jss, 11 Jss, 12 // Shortcuts 13 doc = document, 14 head = doc.head || doc.getElementsByTagName('head')[0], 15 sheets = doc.styleSheets, 16 adjSelAttrRgx = /((?:\.|#)[^\.\s#]+)((?:\.|#)[^\.\s#]+)/g; 17 18 jss = function (selector, sheet) { 19 var obj = new Jss(); 20 obj.init(selector, sheet); 21 return obj; 22 }; 23 24 // Core functions for manipulating stylesheets 25 26 jss._sheetToNode = function (sheet) { 27 return sheet.ownerNode || sheet.owningElement; 28 }; 29 30 jss._nodeToSheet = function (node) { 31 var result = null, 32 i; 33 34 for (i = 0; i < sheets.length; i++) { 35 if (node === jss._sheetToNode(sheets[i])) { 36 result = sheets[i]; 37 break; 38 } 39 } 40 41 return result; 42 }; 43 44 jss._getSheets = function (sheetSelector) { 45 var results = [], 46 node, 47 i; 48 49 if (!sheetSelector) { 50 results = sheets; 51 } else if (typeof sheetSelector == 'number') { 52 results = [sheets[sheetSelector]]; 53 } else if (typeof sheetSelector == 'object') { 54 if (sheetSelector.href) { 55 for (i = 0; i < sheets.length; i++) { 56 node = jss._sheetToNode(sheets[i]); 57 if (sheetSelector.href && node.href == sheetSelector.href || 58 sheetSelector.title && node.title == sheetSelector.title) { 59 results.push(sheets[i]); 60 } 61 } 62 } 63 } 64 65 return results; 66 }; 67 68 jss._addSheet = function () { 69 var styleNode = doc.createElement('style'), 70 i; 71 72 styleNode.type = 'text/css'; 73 styleNode.rel = 'stylesheet'; 74 head.appendChild(styleNode); 75 76 return jss._nodeToSheet(styleNode); 77 }; 78 79 jss._removeSheet = function (sheet) { 80 var node = jss._sheetToNode(sheet); 81 node.parentNode.removeChild(node); 82 }; 83 84 jss._getRules = function (sheet, selector) { 85 var results = [], 86 rules, 87 i, 88 ruleText, 89 selText; 90 91 // Browsers report selectors in lowercase 92 if (selector) selector = selector.toLowerCase(); 93 94 if (typeof sheet.length == 'number') { 95 // Array of sheets 96 for (i = 0; i < sheet.length; i++) { 97 results = results.concat(jss._getRules(sheet[i], selector)); 98 } 99 } else { 100 // Single sheet 101 rules = sheet.cssRules || sheet.rules; 102 for (i = 0; i < rules.length; i++) { 103 // Warning, selectorText may not be correct in IE<9 104 // as it splits selectors with ',' into multiple rules. 105 // Also, certain rules (e.g. @rules) don't have selectorText 106 if (rules[i].selectorText) { 107 ruleText = rules[i].selectorText; 108 if (!selector || ruleText == selector || ruleText == jss._swapAdjSelAttr(selector)) { 109 results.push({ 110 sheet: sheet, 111 index: i, 112 style: rules[i].style 113 }); 114 } 115 } 116 } 117 } 118 119 return results; 120 }; 121 122 // IE9 stores rules with attributes (classes or ID's) adjacent in the opposite order as defined 123 // causing them to not be found, so this method swaps [#|.]sel1[#|.]sel2 to become [#|.]sel2[#|.]sel1 124 jss._swapAdjSelAttr = function (selector) { 125 var swap = '', 126 lastIndex = 0; 127 128 while ((match = adjSelAttrRgx.exec(selector)) != null) { 129 if (match[0] == '') break; 130 swap += selector.substring(lastIndex, match.index); 131 swap += selector.substr(match.index + match[1].length, match[2].length); 132 swap += selector.substr(match.index, match[1].length); 133 lastIndex = match.index + match[0].length; 134 } 135 swap += selector.substr(lastIndex); 136 137 return swap; 138 }; 139 140 // Add an (empty) rule 141 jss._addRule = function (sheet, selector) { 142 var rules = sheet.cssRules || sheet.rules, 143 index = rules.length; 144 145 if (sheet.insertRule) { 146 sheet.insertRule(selector + ' { }', index); 147 } else if (sheet.addRule) { 148 sheet.addRule(selector, null, index); 149 } 150 151 return { 152 sheet: sheet, 153 index: index, 154 style: rules[index].style 155 }; 156 }; 157 158 jss._removeRule = function (rule) { 159 var sheet = rule.sheet, 160 index = rule.index; 161 162 if (sheet.deleteRule) { 163 sheet.deleteRule(index); 164 } else if (sheet.removeRule) { 165 sheet.removeRule(index); 166 } 167 }; 168 169 jss._toCamelCase = function(prop) { 170 return prop.replace(/-([a-z])/gi, function(s, group1) {return group1.toUpperCase();}); 171 }; 172 173 // Object structure for some code candy 174 Jss = function () {}; 175 176 Jss.prototype = { 177 init: function (selector, sheet) { 178 var i; 179 180 if (sheet == null) { 181 if (!this.sheets) this.sheets = jss._getSheets(); 182 } else if (sheet === jss) { 183 if (jss.dfault === undefined) 184 jss.dfault = jss._addSheet(); 185 this.sheets = [jss.dfault]; 186 } else if (typeof sheet == 'number') { 187 this.sheets = jss._getSheets(sheet); 188 } else if (typeof sheet == 'object') { 189 // Recursive call to init 190 return this.init(selector, jss).add(sheet); 191 } 192 193 this.selector = selector; 194 195 return this; 196 }, 197 add: function (prop, value) { 198 var i; 199 200 // Add new rule to every sheet that doesn't already have it 201 for (i = 0; i < this.sheets.length; i++) { 202 if (jss._getRules(this.sheets[i], this.selector).length == 0) { 203 jss._addRule(this.sheets[i], this.selector); 204 } 205 } 206 207 this.set(prop, value); 208 209 return this; 210 }, 211 set: function (prop, value) { 212 var i, 213 rules, 214 propName; 215 216 if (value === undefined) { 217 if (prop && typeof prop == 'object') { 218 for (i in prop) { 219 if (!prop.hasOwnProperty(i)) continue; 220 this.set(i, prop[i]); 221 } 222 } 223 } else { 224 rules = jss._getRules(this.sheets, this.selector); 225 propName = jss._toCamelCase(prop); 226 // Set properties for each rule 227 for (i = 0; i < rules.length; i++) { 228 rules[i].style[propName] = value; 229 } 230 } 231 232 return this; 233 }, 234 get: function (prop) { 235 var result, 236 rules = jss._getRules(this.sheets, this.selector), 237 propName, 238 i, 239 j; 240 241 if (prop !== undefined) { 242 propName = jss._toCamelCase(prop); 243 for (i = rules.length - 1; i >=0; i--) { 244 // added test for emtpy string to handle style selector defined more than once 245 if (rules[i].style[propName] != null && rules[i].style[propName] != '') { 246 result = rules[i].style[propName]; 247 break; 248 } 249 } 250 } else { 251 result = {}; 252 for (i = 0; i < rules.length; i++) { 253 for (j = 0; j < rules[i].style.length; j++) { 254 propName = rules[i].style[j]; 255 result[propName] = rules[i].style[propName]; 256 } 257 } 258 } 259 260 return result; 261 }, 262 remove: function () { 263 var rules = jss._getRules(this.sheets, this.selector), 264 i; 265 266 // Remove backwards so indices don't shift 267 for (i = rules.length - 1; i >= 0; i--) { 268 jss._removeRule(rules[i]); 269 } 270 } 271 }; 272 273 return jss; 274})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.