blob: c4f61b46a66b24d7320163a112c47d5782b8d478 [file] [log] [blame]
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is jquery-css-parser.
*
* The Initial Developer of the Original Code is Daniel Wachsstock.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bespin Team (bespin@mozilla.com)
*
* ORIGINAL MIT-licensed CODE LICENSE HEADER FOLLOWS:
// jQuery based CSS parser
// documentation: http://youngisrael-stl.org/wordpress/2009/01/16/jquery-css-parser/
// Version: 1.0
// Copyright (c) 2009 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.
* ***** END LICENSE BLOCK ***** */
dojo.provide("th.css");
dojo.declare("th.css.CSSParser", null, {
parse: function(str, ret) {
// parses the passed stylesheet into an object with properties containing objects with the attribute names and values
if (!ret) ret = {};
dojo.forEach(this.munge(str, false).split('`b%'), function(css){
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] = this.restore(css[0]);
var obj = ret[css[0]] || {};
ret[css[0]] = dojo.mixin(obj, this.parsedeclarations(css[1]));
}, this);
return ret;
},
// 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/)
REbraces: /{[^{}]*}/,
REfull: /\[[^\[\]]*\]|{[^{}]*}|\([^()]*\)|function(\s+\w+)?(\s*%b`\d+`b%){2}/, // match pairs of parentheses, brackets, and braces and function definitions.
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
REcomment_string:
/(?:\/\*(?:[^\*]|\*[^\/])*\*\/)|(\\.|"(?:[^\\\"]|\\.|\\\n)*"|'(?:[^\\\']|\\.|\\\n)*')/g,
REmunged: /%\w`(\d+)`\w%/,
uid: 0, // unique id number
munged: {}, // strings that were removed by the parser so they don't mess up searching for specific characters
munge: function(str, full) {
str = str
.replace(this.REatcomment, '$1') // strip /*@ comments but leave the text (to let invalid CSS through)
.replace(this.REcomment_string, dojo.hitch(this, function (s, string) { // strip strings and escaped characters, leaving munged markers, and strip comments
if (!string) return '';
var replacement = '%s`'+(++this.uid)+'`s%';
this.munged[this.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 ? this.REfull : this.REbraces;
while (match = RE.exec(str)) {
replacement = '%b`'+(++this.uid)+'`b%';
this.munged[this.uid] = match[0];
str = str.replace(RE, replacement);
}
return str;
},
restore: function(str) {
if (str === undefined) return str;
while (match = this.REmunged.exec(str)) {
str = str.replace(this.REmunged, this.munged[match[1]]);
}
return dojo.trim(str);
},
parsedeclarations: function(index){ // take a string from the munged array and parse it into an object of property: value pairs
var str = this.munged[index].replace(/(?:^\s*[{'"]\s*)|(?:\s*([^\\])[}'"]\s*$)/g, '$1'); // find the string and remove the surrounding braces or quotes
str = this.munge(str); // make sure any internal braces or strings are escaped
var parsed = {};
dojo.forEach(str.split(';'), function (decl) {
decl = decl.split(':');
if (decl.length < 2) return;
parsed[this.restore(decl[0])] = this.restore(decl[1]);
}, this);
return parsed;
}
});