css.js
10 years ago
css.min.js
10 years ago
csslint.js
11 years ago
csslint.min.js
10 years ago
editor.js
11 years ago
editor.min.js
10 years ago
inspector.js
11 years ago
inspector.min.js
10 years ago
jquery.sizes.js
11 years ago
jquery.sizes.min.js
10 years ago
specificity.js
11 years ago
specificity.min.js
10 years ago
css.js
698 lines
| 1 | /* |
| 2 | The MIT License (MIT) |
| 3 | Copyright (c) 2015 JotForm |
| 4 | |
| 5 | Modifications made by SiteOrigin |
| 6 | */ |
| 7 | |
| 8 | /* jshint unused:false */ |
| 9 | /* global base64_decode, CSSWizardView, window, console, jQuery */ |
| 10 | (function ($) { |
| 11 | 'use strict'; |
| 12 | var fi = function () { |
| 13 | |
| 14 | this.cssImportStatements = []; |
| 15 | this.cssKeyframeStatements = []; |
| 16 | |
| 17 | this.cssRegex = new RegExp('([\\s\\S]*?){([\\s\\S]*?)}', 'gi'); |
| 18 | this.cssMediaQueryRegex = '((@media [\\s\\S]*?){([\\s\\S]*?}\\s*?)})'; |
| 19 | this.cssKeyframeRegex = '((@.*?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})'; |
| 20 | this.combinedCSSRegex = '((\\s*?@media[\\s\\S]*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})'; //to match css & media queries together |
| 21 | this.cssCommentsRegex = '(\\/\\*[\\s\\S]*?\\*\\/)'; |
| 22 | this.cssImportStatementRegex = new RegExp('@import .*?;', 'gi'); |
| 23 | }; |
| 24 | |
| 25 | /* |
| 26 | Strip outs css comments and returns cleaned css string |
| 27 | |
| 28 | @param css, the original css string to be stipped out of comments |
| 29 | |
| 30 | @return cleanedCSS contains no css comments |
| 31 | */ |
| 32 | fi.prototype.stripComments = function (cssString) { |
| 33 | var regex = new RegExp(this.cssCommentsRegex, 'gi'); |
| 34 | |
| 35 | return cssString.replace(regex, ''); |
| 36 | }; |
| 37 | |
| 38 | /* |
| 39 | Parses given css string, and returns css object |
| 40 | keys as selectors and values are css rules |
| 41 | |
| 42 | @param source css string to be parsed |
| 43 | |
| 44 | @return object css |
| 45 | */ |
| 46 | fi.prototype.parseCSS = function (source) { |
| 47 | |
| 48 | if (source === undefined) { |
| 49 | return []; |
| 50 | } |
| 51 | |
| 52 | var css = []; |
| 53 | |
| 54 | //get import statements |
| 55 | while (true) { |
| 56 | var imports = this.cssImportStatementRegex.exec(source); |
| 57 | if (imports !== null) { |
| 58 | this.cssImportStatements.push(imports[0]); |
| 59 | css.push({ |
| 60 | selector: '@imports', |
| 61 | type: 'imports', |
| 62 | styles: imports[0] |
| 63 | }); |
| 64 | } |
| 65 | else { |
| 66 | break; |
| 67 | } |
| 68 | } |
| 69 | source = source.replace(this.cssImportStatementRegex, ''); |
| 70 | //get keyframe statements |
| 71 | var keyframesRegex = new RegExp(this.cssKeyframeRegex, 'gi'); |
| 72 | var arr; |
| 73 | while (true) { |
| 74 | arr = keyframesRegex.exec(source); |
| 75 | if (arr === null) { |
| 76 | break; |
| 77 | } |
| 78 | css.push({ |
| 79 | selector: '@keyframes', |
| 80 | type: 'keyframes', |
| 81 | styles: arr[0] |
| 82 | }); |
| 83 | } |
| 84 | source = source.replace(keyframesRegex, ''); |
| 85 | |
| 86 | //unified regex |
| 87 | var unified = new RegExp(this.combinedCSSRegex, 'gi'); |
| 88 | |
| 89 | while (true) { |
| 90 | arr = unified.exec(source); |
| 91 | if (arr === null) { |
| 92 | break; |
| 93 | } |
| 94 | var selector = ''; |
| 95 | if (arr[2] === undefined) { |
| 96 | selector = arr[5].split('\r\n').join('\n').trim(); |
| 97 | } |
| 98 | else { |
| 99 | selector = arr[2].split('\r\n').join('\n').trim(); |
| 100 | } |
| 101 | |
| 102 | /* |
| 103 | fetch comments and associate it with current selector |
| 104 | */ |
| 105 | var commentsRegex = new RegExp(this.cssCommentsRegex, 'gi'); |
| 106 | var comments = commentsRegex.exec(selector); |
| 107 | if (comments !== null) { |
| 108 | selector = selector.replace(commentsRegex, '').trim(); |
| 109 | } |
| 110 | |
| 111 | // Never have more than a single line break in a row |
| 112 | selector = selector.replace(/\n+/, "\n"); |
| 113 | |
| 114 | //determine the type |
| 115 | if (selector.indexOf('@media') !== -1) { |
| 116 | //we have a media query |
| 117 | var cssObject = { |
| 118 | selector: selector, |
| 119 | type: 'media', |
| 120 | subStyles: this.parseCSS(arr[3] + '\n}') //recursively parse media query inner css |
| 121 | }; |
| 122 | if (comments !== null) { |
| 123 | cssObject.comments = comments[0]; |
| 124 | } |
| 125 | css.push(cssObject); |
| 126 | } |
| 127 | else { |
| 128 | //we have standard css |
| 129 | var rules = this.parseRules(arr[6]); |
| 130 | var style = { |
| 131 | selector: selector, |
| 132 | rules: rules |
| 133 | }; |
| 134 | if (selector === '@font-face') { |
| 135 | style.type = 'font-face'; |
| 136 | } |
| 137 | if (comments !== null) { |
| 138 | style.comments = comments[0]; |
| 139 | } |
| 140 | css.push(style); |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | return css; |
| 145 | }; |
| 146 | |
| 147 | /* |
| 148 | parses given string containing css directives |
| 149 | and returns an array of objects containing ruleName:ruleValue pairs |
| 150 | |
| 151 | @param rules, css directive string example |
| 152 | \n\ncolor:white;\n font-size:18px;\n |
| 153 | */ |
| 154 | fi.prototype.parseRules = function (rules) { |
| 155 | //convert all windows style line endings to unix style line endings |
| 156 | rules = rules.split('\r\n').join('\n'); |
| 157 | var ret = []; |
| 158 | |
| 159 | rules = rules.split(';'); |
| 160 | |
| 161 | //proccess rules line by line |
| 162 | for (var i = 0; i < rules.length; i++) { |
| 163 | var line = rules[i]; |
| 164 | |
| 165 | //determine if line is a valid css directive, ie color:white; |
| 166 | line = line.trim(); |
| 167 | if (line.indexOf(':') !== -1) { |
| 168 | //line contains : |
| 169 | line = line.split(':'); |
| 170 | var cssDirective = line[0].trim(); |
| 171 | var cssValue = line.slice(1).join(':').trim(); |
| 172 | |
| 173 | //push rule |
| 174 | ret.push({ |
| 175 | directive: cssDirective, |
| 176 | value: cssValue |
| 177 | }); |
| 178 | } |
| 179 | else { |
| 180 | //if there is no ':', but what if it was mis splitted value which starts with base64 |
| 181 | if (line.trim().substr(0, 7) === 'base64,') { //hack :) |
| 182 | ret[ret.length - 1].value += line.trim(); |
| 183 | } |
| 184 | else { |
| 185 | //add rule, even if it is defective |
| 186 | if (line.length > 0) { |
| 187 | ret.push({ |
| 188 | directive: '', |
| 189 | value: line, |
| 190 | defective: true |
| 191 | }); |
| 192 | } |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | return ret; //we are done! |
| 198 | }; |
| 199 | |
| 200 | /* |
| 201 | just returns the rule having given directive |
| 202 | if not found returns false; |
| 203 | */ |
| 204 | fi.prototype.findCorrespondingRule = function (rules, directive, value) { |
| 205 | if (value === undefined) { |
| 206 | value = false; |
| 207 | } |
| 208 | var ret = false; |
| 209 | for (var i = 0; i < rules.length; i++) { |
| 210 | if (rules[i].directive == directive) { |
| 211 | ret = rules[i]; |
| 212 | if (value === rules[i].value) { |
| 213 | break; |
| 214 | } |
| 215 | } |
| 216 | } |
| 217 | return ret; |
| 218 | }; |
| 219 | |
| 220 | /* |
| 221 | Finds styles that have given selector, compress them, |
| 222 | and returns them |
| 223 | */ |
| 224 | fi.prototype.findBySelector = function (cssObjectArray, selector, contains) { |
| 225 | if (contains === undefined) { |
| 226 | contains = false; |
| 227 | } |
| 228 | |
| 229 | var found = []; |
| 230 | for (var i = 0; i < cssObjectArray.length; i++) { |
| 231 | if (contains === false) { |
| 232 | if (cssObjectArray[i].selector === selector) { |
| 233 | found.push(cssObjectArray[i]); |
| 234 | } |
| 235 | } |
| 236 | else { |
| 237 | if (cssObjectArray[i].selector.indexOf(selector) !== -1) { |
| 238 | found.push(cssObjectArray[i]); |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | } |
| 243 | if (found.length < 2) { |
| 244 | return found; |
| 245 | } |
| 246 | else { |
| 247 | var base = found[0]; |
| 248 | for (i = 1; i < found.length; i++) { |
| 249 | this.intelligentCSSPush([base], found[i]); |
| 250 | } |
| 251 | return [base]; //we are done!! all properties merged into base! |
| 252 | } |
| 253 | }; |
| 254 | |
| 255 | /* |
| 256 | deletes cssObjects having given selector, and returns new array |
| 257 | */ |
| 258 | fi.prototype.deleteBySelector = function (cssObjectArray, selector) { |
| 259 | var ret = []; |
| 260 | for (var i = 0; i < cssObjectArray.length; i++) { |
| 261 | if (cssObjectArray[i].selector !== selector) { |
| 262 | ret.push(cssObjectArray[i]); |
| 263 | } |
| 264 | } |
| 265 | return ret; |
| 266 | }; |
| 267 | |
| 268 | /* |
| 269 | Compresses given cssObjectArray and tries to minimize |
| 270 | selector redundence. |
| 271 | */ |
| 272 | fi.prototype.compressCSS = function (cssObjectArray) { |
| 273 | var compressed = []; |
| 274 | var done = {}; |
| 275 | for (var i = 0; i < cssObjectArray.length; i++) { |
| 276 | var obj = cssObjectArray[i]; |
| 277 | if (done[obj.selector] === true) { |
| 278 | continue; |
| 279 | } |
| 280 | |
| 281 | var found = this.findBySelector(cssObjectArray, obj.selector); //found compressed |
| 282 | if ( found.length !== 0 ) { |
| 283 | compressed.push(found[0]); |
| 284 | done[obj.selector] = true; |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | return compressed; |
| 289 | }; |
| 290 | |
| 291 | /* |
| 292 | Received 2 css objects with following structure |
| 293 | { |
| 294 | rules : [{directive:"", value:""}, {directive:"", value:""}, ...] |
| 295 | selector : "SOMESELECTOR" |
| 296 | } |
| 297 | |
| 298 | returns the changed(new,removed,updated) values on css1 parameter, on same structure |
| 299 | |
| 300 | if two css objects are the same, then returns false |
| 301 | |
| 302 | if a css directive exists in css1 and css2, and its value is different, it is included in diff |
| 303 | if a css directive exists in css1 and not css2, it is then included in diff |
| 304 | if a css directive exists in css2 but not css1, then it is deleted in css1, it would be included in diff but will be marked as type='DELETED' |
| 305 | |
| 306 | @object css1 css object |
| 307 | @object css2 css object |
| 308 | |
| 309 | @return diff css object contains changed values in css1 in regards to css2 see test input output in /test/data/css.js |
| 310 | */ |
| 311 | fi.prototype.cssDiff = function (css1, css2) { |
| 312 | if (css1.selector !== css2.selector) { |
| 313 | return false; |
| 314 | } |
| 315 | |
| 316 | //if one of them is media query return false, because diff function can not operate on media queries |
| 317 | if ((css1.type === 'media' || css2.type === 'media')) { |
| 318 | return false; |
| 319 | } |
| 320 | |
| 321 | var diff = { |
| 322 | selector: css1.selector, |
| 323 | rules: [] |
| 324 | }; |
| 325 | var rule1, rule2; |
| 326 | for (var i = 0; i < css1.rules.length; i++) { |
| 327 | rule1 = css1.rules[i]; |
| 328 | //find rule2 which has the same directive as rule1 |
| 329 | rule2 = this.findCorrespondingRule(css2.rules, rule1.directive, rule1.value); |
| 330 | if (rule2 === false) { |
| 331 | //rule1 is a new rule in css1 |
| 332 | diff.rules.push(rule1); |
| 333 | } |
| 334 | else { |
| 335 | //rule2 was found only push if its value is different too |
| 336 | if (rule1.value !== rule2.value) { |
| 337 | diff.rules.push(rule1); |
| 338 | } |
| 339 | } |
| 340 | } |
| 341 | |
| 342 | //now for rules exists in css2 but not in css1, which means deleted rules |
| 343 | for (var ii = 0; ii < css2.rules.length; ii++) { |
| 344 | rule2 = css2.rules[ii]; |
| 345 | //find rule2 which has the same directive as rule1 |
| 346 | rule1 = this.findCorrespondingRule(css1.rules, rule2.directive); |
| 347 | if (rule1 === false) { |
| 348 | //rule1 is a new rule |
| 349 | rule2.type = 'DELETED'; //mark it as a deleted rule, so that other merge operations could be true |
| 350 | diff.rules.push(rule2); |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | |
| 355 | if (diff.rules.length === 0) { |
| 356 | return false; |
| 357 | } |
| 358 | return diff; |
| 359 | }; |
| 360 | |
| 361 | /* |
| 362 | Merges 2 different css objects together |
| 363 | using intelligentCSSPush, |
| 364 | |
| 365 | @param cssObjectArray, target css object array |
| 366 | @param newArray, source array that will be pushed into cssObjectArray parameter |
| 367 | @param reverse, [optional], if given true, first parameter will be traversed on reversed order |
| 368 | effectively giving priority to the styles in newArray |
| 369 | */ |
| 370 | fi.prototype.intelligentMerge = function (cssObjectArray, newArray, reverse) { |
| 371 | if (reverse === undefined) { |
| 372 | reverse = false; |
| 373 | } |
| 374 | |
| 375 | |
| 376 | for (var i = 0; i < newArray.length; i++) { |
| 377 | this.intelligentCSSPush(cssObjectArray, newArray[i], reverse); |
| 378 | } |
| 379 | for (i = 0; i < cssObjectArray.length; i++) { |
| 380 | var cobj = cssObjectArray[i]; |
| 381 | if (cobj.type === 'media' || (cobj.type === 'keyframes')) { |
| 382 | continue; |
| 383 | } |
| 384 | cobj.rules = this.compactRules(cobj.rules); |
| 385 | } |
| 386 | }; |
| 387 | |
| 388 | /* |
| 389 | inserts new css objects into a bigger css object |
| 390 | with same selectors grouped together |
| 391 | |
| 392 | @param cssObjectArray, array of bigger css object to be pushed into |
| 393 | @param minimalObject, single css object |
| 394 | @param reverse [optional] default is false, if given, cssObjectArray will be reverse traversed |
| 395 | resulting more priority in minimalObject's styles |
| 396 | */ |
| 397 | fi.prototype.intelligentCSSPush = function (cssObjectArray, minimalObject, reverse) { |
| 398 | var pushSelector = minimalObject.selector; |
| 399 | //find correct selector if not found just push minimalObject into cssObject |
| 400 | var cssObject = false; |
| 401 | |
| 402 | if (reverse === undefined) { |
| 403 | reverse = false; |
| 404 | } |
| 405 | |
| 406 | if (reverse === false) { |
| 407 | for (var i = 0; i < cssObjectArray.length; i++) { |
| 408 | if (cssObjectArray[i].selector === minimalObject.selector) { |
| 409 | cssObject = cssObjectArray[i]; |
| 410 | break; |
| 411 | } |
| 412 | } |
| 413 | } |
| 414 | else { |
| 415 | for (var j = cssObjectArray.length - 1; j > -1; j--) { |
| 416 | if (cssObjectArray[j].selector === minimalObject.selector) { |
| 417 | cssObject = cssObjectArray[j]; |
| 418 | break; |
| 419 | } |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | if (cssObject === false) { |
| 424 | cssObjectArray.push(minimalObject); //just push, because cssSelector is new |
| 425 | } |
| 426 | else { |
| 427 | if (minimalObject.type !== 'media') { |
| 428 | for (var ii = 0; ii < minimalObject.rules.length; ii++) { |
| 429 | var rule = minimalObject.rules[ii]; |
| 430 | //find rule inside cssObject |
| 431 | var oldRule = this.findCorrespondingRule(cssObject.rules, rule.directive); |
| 432 | if (oldRule === false) { |
| 433 | cssObject.rules.push(rule); |
| 434 | } else if (rule.type === 'DELETED') { |
| 435 | oldRule.type = 'DELETED'; |
| 436 | } |
| 437 | else { |
| 438 | //rule found just update value |
| 439 | |
| 440 | oldRule.value = rule.value; |
| 441 | } |
| 442 | } |
| 443 | } |
| 444 | else { |
| 445 | cssObject.subStyles = cssObject.subStyles.concat(minimalObject.subStyles); //TODO, make this intelligent too |
| 446 | } |
| 447 | |
| 448 | } |
| 449 | }; |
| 450 | |
| 451 | /* |
| 452 | filter outs rule objects whose type param equal to DELETED |
| 453 | |
| 454 | @param rules, array of rules |
| 455 | |
| 456 | @returns rules array, compacted by deleting all unnecessary rules |
| 457 | */ |
| 458 | fi.prototype.compactRules = function (rules) { |
| 459 | var newRules = []; |
| 460 | for (var i = 0; i < rules.length; i++) { |
| 461 | if (rules[i].type !== 'DELETED') { |
| 462 | newRules.push(rules[i]); |
| 463 | } |
| 464 | } |
| 465 | return newRules; |
| 466 | }; |
| 467 | /* |
| 468 | computes string for ace editor using this.css or given cssBase optional parameter |
| 469 | |
| 470 | @param [optional] cssBase, if given computes cssString from cssObject array |
| 471 | */ |
| 472 | fi.prototype.getCSSForEditor = function (cssBase, depth) { |
| 473 | if (depth === undefined) { |
| 474 | depth = 0; |
| 475 | } |
| 476 | var ret = ''; |
| 477 | if (cssBase === undefined) { |
| 478 | cssBase = this.css; |
| 479 | } |
| 480 | //append imports |
| 481 | for (var i = 0; i < cssBase.length; i++) { |
| 482 | if (cssBase[i].type === 'imports') { |
| 483 | ret += cssBase[i].styles + '\n\n'; |
| 484 | } |
| 485 | } |
| 486 | for (i = 0; i < cssBase.length; i++) { |
| 487 | var tmp = cssBase[i]; |
| 488 | if (tmp.selector === undefined) { //temporarily omit media queries |
| 489 | continue; |
| 490 | } |
| 491 | var comments = ""; |
| 492 | if (tmp.comments !== undefined) { |
| 493 | comments = tmp.comments + '\n'; |
| 494 | } |
| 495 | |
| 496 | if (tmp.type === 'media') { //also put media queries to output |
| 497 | ret += comments + tmp.selector + '{\n'; |
| 498 | ret += this.getCSSForEditor(tmp.subStyles, depth + 1); |
| 499 | ret += '}\n\n'; |
| 500 | } |
| 501 | else if (tmp.type !== 'keyframes' && tmp.type !== 'imports') { |
| 502 | ret += this.getSpaces(depth) + comments + tmp.selector + ' {\n'; |
| 503 | ret += this.getCSSOfRules(tmp.rules, depth + 1); |
| 504 | ret += this.getSpaces(depth) + '}\n\n'; |
| 505 | } |
| 506 | } |
| 507 | |
| 508 | //append keyFrames |
| 509 | for (i = 0; i < cssBase.length; i++) { |
| 510 | if (cssBase[i].type === 'keyframes') { |
| 511 | ret += cssBase[i].styles + '\n\n'; |
| 512 | } |
| 513 | } |
| 514 | |
| 515 | return ret; |
| 516 | }; |
| 517 | |
| 518 | fi.prototype.getImports = function (cssObjectArray) { |
| 519 | var imps = []; |
| 520 | for (var i = 0; i < cssObjectArray.length; i++) { |
| 521 | if (cssObjectArray[i].type === 'imports') { |
| 522 | imps.push(cssObjectArray[i].styles); |
| 523 | } |
| 524 | } |
| 525 | return imps; |
| 526 | }; |
| 527 | |
| 528 | /* |
| 529 | given rules array, returns visually formatted css string |
| 530 | to be used inside editor |
| 531 | */ |
| 532 | fi.prototype.getCSSOfRules = function (rules, depth) { |
| 533 | var ret = ''; |
| 534 | for (var i = 0; i < rules.length; i++) { |
| 535 | if (rules[i] === undefined) { |
| 536 | continue; |
| 537 | } |
| 538 | if( rules[i].value === '' ) { |
| 539 | continue; |
| 540 | } |
| 541 | |
| 542 | if (rules[i].defective === undefined) { |
| 543 | ret += this.getSpaces(depth) + rules[i].directive + ': ' + rules[i].value + ';\n'; |
| 544 | } |
| 545 | else { |
| 546 | ret += this.getSpaces(depth) + rules[i].value + ';\n'; |
| 547 | } |
| 548 | |
| 549 | } |
| 550 | return ret || '\n'; |
| 551 | }; |
| 552 | |
| 553 | /* |
| 554 | A very simple helper function returns number of spaces appended in a single string, |
| 555 | the number depends input parameter, namely input*2 |
| 556 | */ |
| 557 | fi.prototype.getSpaces = function (num) { |
| 558 | var ret = ''; |
| 559 | for (var i = 0; i < num * 2; i++) { |
| 560 | ret += ' '; |
| 561 | } |
| 562 | return ret; |
| 563 | }; |
| 564 | |
| 565 | /* |
| 566 | Given css string or objectArray, parses it and then for every selector, |
| 567 | prepends this.cssPreviewNamespace to prevent css collision issues |
| 568 | |
| 569 | @returns css string in which this.cssPreviewNamespace prepended |
| 570 | */ |
| 571 | fi.prototype.applyNamespacing = function (css, forcedNamespace) { |
| 572 | var cssObjectArray = css; |
| 573 | var namespaceClass = '.' + this.cssPreviewNamespace; |
| 574 | if (forcedNamespace !== undefined) { |
| 575 | namespaceClass = forcedNamespace; |
| 576 | } |
| 577 | |
| 578 | if (typeof css === 'string') { |
| 579 | cssObjectArray = this.parseCSS(css); |
| 580 | } |
| 581 | |
| 582 | for (var i = 0; i < cssObjectArray.length; i++) { |
| 583 | var obj = cssObjectArray[i]; |
| 584 | |
| 585 | //bypass namespacing for @font-face @keyframes @import |
| 586 | if (obj.selector.indexOf('@font-face') > -1 || obj.selector.indexOf('keyframes') > -1 || obj.selector.indexOf('@import') > -1 || obj.selector.indexOf('.form-all') > -1 || obj.selector.indexOf('#stage') > -1) { |
| 587 | continue; |
| 588 | } |
| 589 | |
| 590 | if (obj.type !== 'media') { |
| 591 | var selector = obj.selector.split(','); |
| 592 | var newSelector = []; |
| 593 | for (var j = 0; j < selector.length; j++) { |
| 594 | if (selector[j].indexOf('.supernova') === -1) { //do not apply namespacing to selectors including supernova |
| 595 | newSelector.push(namespaceClass + ' ' + selector[j]); |
| 596 | } |
| 597 | else { |
| 598 | newSelector.push(selector[j]); |
| 599 | } |
| 600 | } |
| 601 | obj.selector = newSelector.join(','); |
| 602 | } |
| 603 | else { |
| 604 | obj.subStyles = this.applyNamespacing(obj.subStyles, forcedNamespace); //handle media queries as well |
| 605 | } |
| 606 | } |
| 607 | |
| 608 | return cssObjectArray; |
| 609 | }; |
| 610 | |
| 611 | /* |
| 612 | given css string or object array, clears possible namespacing from |
| 613 | all of the selectors inside the css |
| 614 | */ |
| 615 | fi.prototype.clearNamespacing = function (css, returnObj) { |
| 616 | if (returnObj === undefined) { |
| 617 | returnObj = false; |
| 618 | } |
| 619 | var cssObjectArray = css; |
| 620 | var namespaceClass = '.' + this.cssPreviewNamespace; |
| 621 | if (typeof css === 'string') { |
| 622 | cssObjectArray = this.parseCSS(css); |
| 623 | } |
| 624 | |
| 625 | for (var i = 0; i < cssObjectArray.length; i++) { |
| 626 | var obj = cssObjectArray[i]; |
| 627 | |
| 628 | if (obj.type !== 'media') { |
| 629 | var selector = obj.selector.split(','); |
| 630 | var newSelector = []; |
| 631 | for (var j = 0; j < selector.length; j++) { |
| 632 | newSelector.push(selector[j].split(namespaceClass + ' ').join('')); |
| 633 | } |
| 634 | obj.selector = newSelector.join(','); |
| 635 | } |
| 636 | else { |
| 637 | obj.subStyles = this.clearNamespacing(obj.subStyles, true); //handle media queries as well |
| 638 | } |
| 639 | } |
| 640 | if (returnObj === false) { |
| 641 | return this.getCSSForEditor(cssObjectArray); |
| 642 | } |
| 643 | else { |
| 644 | return cssObjectArray; |
| 645 | } |
| 646 | |
| 647 | }; |
| 648 | |
| 649 | /* |
| 650 | creates a new style tag (also destroys the previous one) |
| 651 | and injects given css string into that css tag |
| 652 | */ |
| 653 | fi.prototype.createStyleElement = function (id, css, format) { |
| 654 | if (format === undefined) { |
| 655 | format = false; |
| 656 | } |
| 657 | |
| 658 | if (this.testMode === false && format !== 'nonamespace') { |
| 659 | //apply namespacing classes |
| 660 | css = this.applyNamespacing(css); |
| 661 | } |
| 662 | |
| 663 | if (typeof css !== 'string') { |
| 664 | css = this.getCSSForEditor(css); |
| 665 | } |
| 666 | //apply formatting for css |
| 667 | if (format === true) { |
| 668 | css = this.getCSSForEditor(this.parseCSS(css)); |
| 669 | } |
| 670 | |
| 671 | if (this.testMode !== false) { |
| 672 | return this.testMode('create style #' + id, css); //if test mode, just pass result to callback |
| 673 | } |
| 674 | |
| 675 | var __el = document.getElementById(id); |
| 676 | if (__el) { |
| 677 | __el.parentNode.removeChild(__el); |
| 678 | } |
| 679 | |
| 680 | var head = document.head || document.getElementsByTagName('head')[0], |
| 681 | style = document.createElement('style'); |
| 682 | |
| 683 | style.id = id; |
| 684 | style.type = 'text/css'; |
| 685 | |
| 686 | head.appendChild(style); |
| 687 | |
| 688 | if (style.styleSheet && !style.sheet) { |
| 689 | style.styleSheet.cssText = css; |
| 690 | } |
| 691 | else { |
| 692 | style.appendChild(document.createTextNode(css)); |
| 693 | } |
| 694 | }; |
| 695 | |
| 696 | window.cssjs = fi; |
| 697 | |
| 698 | })(); |