Created
January 8, 2012 20:58
-
-
Save gka/1579670 to your computer and use it in GitHub Desktop.
CSS parsing in JavaScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This is the light version of Danial Wachsstock's jQuery based CSS parser | |
* http://bililite.com/blog/2009/01/16/jquery-css-parser/#parserdetails | |
* | |
* Everything is removed but the core css2object parsing | |
* | |
* Usage is straight forward: | |
* | |
* $.parseCSS('body { background: red; font-weight: 300 }'); | |
* // returns { 'body': { 'background': 'red', 'font-weight': 300 } } | |
* | |
*/ | |
// jQuery based CSS parser | |
// documentation: http://youngisrael-stl.org/wordpress/2009/01/16/jquery-css-parser/ | |
// Version: 1.3 | |
// Copyright (c) 2011 Daniel Wachsstock | |
// MIT license: | |
// Permission is hereby granted, free of charge, to any person | |
// obtaining a copy of this software and associated documentation | |
// files (the "Software"), to deal in the Software without | |
// restriction, including without limitation the rights to use, | |
// copy, modify, merge, publish, distribute, sublicense, and/or sell | |
// copies of the Software, and to permit persons to whom the | |
// Software is furnished to do so, subject to the following | |
// conditions: | |
// The above copyright notice and this permission notice shall be | |
// included in all copies or substantial portions of the Software. | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
// OTHER DEALINGS IN THE SOFTWARE. | |
(function($){ | |
$.parsecss = function(str, callback){ | |
var ret = {}; | |
str = munge(str).replace(/@(([^;`]|`[^b]|`b[^%])*(`b%)?);?/g, function(s,rule){ | |
// @rules end with ; or a block, with the semicolon not being part of the rule but the closing brace (represented by `b%) is | |
processAtRule($.trim(rule), callback); | |
return ''; | |
}); | |
$.each (str.split('`b%'), function(i,css){ // split on the end of a block | |
css = css.split('%b`'); // css[0] is the selector; css[1] is the index in munged for the cssText | |
if (css.length < 2) return; // invalid css | |
css[0] = restore(css[0]); | |
ret[css[0]] = $.extend(ret[css[0]] || {}, parsedeclarations(css[1])); | |
}); | |
if ($.isFunction(callback)) callback(ret); | |
else return ret; | |
}; | |
// caches | |
var munged = {}; // strings that were removed by the parser so they don't mess up searching for specific characters | |
// private functions | |
function parsedeclarations(index){ // take a string from the munged array and parse it into an object of property: value pairs | |
var str = munged[index].replace(/^{|}$/g, ''); // find the string and remove the surrounding braces | |
str = munge(str); // make sure any internal braces or strings are escaped | |
var parsed = {}; | |
$.each (str.split(';'), function (i, decl){ | |
decl = decl.split(':'); | |
if (decl.length < 2) return; | |
parsed[restore(decl[0])] = restore(decl.slice(1).join(':')); | |
}); | |
return parsed; | |
} | |
// replace strings and brace-surrounded blocks with %s`number`s% and %b`number`b%. By successively taking out the innermost | |
// blocks, we ensure that we're matching braces. No way to do this with just regular expressions. Obviously, this assumes no one | |
// would use %s` in the real world. | |
// Turns out this is similar to the method that Dean Edwards used for his CSS parser in IE7.js (http://code.google.com/p/ie7-js/) | |
var REbraces = /{[^{}]*}/; | |
var REfull = /\[[^\[\]]*\]|{[^{}]*}|\([^()]*\)|function(\s+\w+)?(\s*%b`\d+`b%){2}/; // match pairs of parentheses, brackets, and braces and function definitions. | |
var REatcomment = /\/\*@((?:[^\*]|\*[^\/])*)\*\//g; // comments of the form /*@ text */ have text parsed | |
// we have to combine the comments and the strings because comments can contain string delimiters and strings can contain comment delimiters | |
// var REcomment = /\/\*(?:[^\*]|\*[^\/])*\*\/|<!--|-->/g; // other comments are stripped. (this is a simplification of real SGML comments (see http://htmlhelp.com/reference/wilbur/misc/comment.html) , but it's what real browsers use) | |
// var REstring = /\\.|"(?:[^\\\"]|\\.|\\\n)*"|'(?:[^\\\']|\\.|\\\n)*'/g; // match escaped characters and strings | |
var REcomment_string = | |
/(?:\/\*(?:[^\*]|\*[^\/])*\*\/)|(\\.|"(?:[^\\\"]|\\.|\\\n)*"|'(?:[^\\\']|\\.|\\\n)*')/g; | |
var REmunged = /%\w`(\d+)`\w%/; | |
var uid = 0; // unique id number | |
function munge(str, full){ | |
str = str | |
.replace(REatcomment,'$1') // strip /*@ comments but leave the text (to let invalid CSS through) | |
.replace(REcomment_string, function (s, string){ // strip strings and escaped characters, leaving munged markers, and strip comments | |
if (!string) return ''; | |
var replacement = '%s`'+(++uid)+'`s%'; | |
munged[uid] = string.replace(/^\\/,''); // strip the backslash now | |
return replacement; | |
}) | |
; | |
// need a loop here rather than .replace since we need to replace nested braces | |
var RE = full ? REfull : REbraces; | |
while (match = RE.exec(str)){ | |
replacement = '%b`'+(++uid)+'`b%'; | |
munged[uid] = match[0]; | |
str = str.replace(RE, replacement); | |
} | |
return str; | |
} | |
function restore(str){ | |
if (str === undefined) return str; | |
while (match = REmunged.exec(str)){ | |
str = str.replace(REmunged, munged[match[1]]); | |
} | |
return $.trim(str); | |
} | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment