diff --git a/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/code_mirror_support.xml b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/code_mirror_support.xml index 582f518525454ee8824be06b2dbf7d93adb6f851..db84371104bfc068151687aebde7002e55289c18 100644 --- a/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/code_mirror_support.xml +++ b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/code_mirror_support.xml @@ -28,7 +28,7 @@ <script type="text/javascript" src="&dtml-portal_url;/codemirror/lib/codemirror.js"></script>\n <link rel="stylesheet" href="&dtml-portal_url;/codemirror/lib/codemirror.css">\n -<script type="text/javascript" src="&dtml-portal_url;/codemirror/mode/python/python.js"></script>\n +<script type="text/javascript" src="&dtml-portal_url;/codemirror/mode/&dtml-mode;/&dtml-mode;.js"></script>\n <script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/edit/matchbrackets.js"></script>\n \n <!-- Trailing spaces -->\n @@ -50,6 +50,7 @@ -->\n <link rel="stylesheet" href="&dtml-portal_url;/codemirror/addon/hint/show-hint.css">\n <script src="&dtml-portal_url;/codemirror/addon/hint/show-hint.js"></script>\n +<script src="&dtml-portal_url;/codemirror/addon/hint/anyword-hint.js"></script>\n \n <!-- Code folding -->\n <link rel="stylesheet" href="&dtml-portal_url;/codemirror/addon/fold/foldgutter.css">\n @@ -63,11 +64,18 @@ <script type="text/javascript" src="&dtml-portal_url;/diff_match_patch/javascript/diff_match_patch_uncompressed.js"></script>\n <script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/merge/merge.js"></script>\n \n -<!-- Lint\n - TODO: Only support Python for now -->\n +<!-- Linter -->\n <link rel="stylesheet" href="&dtml-portal_url;/codemirror/addon/lint/lint.css">\n <script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/lint/lint.js"></script>\n \n +<dtml-if expr="mode == \'javascript\'">\n +<script type="text/javascript" src="&dtml-portal_url;/jshint.js"></script>\n +<script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/lint/javascript-lint.js"></script>\n +<dtml-elif expr="mode == \'css\'">\n +<script type="text/javascript" src="&dtml-portal_url;/csslint.js"></script>\n +<script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/lint/css-lint.js"></script>\n +</dtml-if>\n +\n <style type="text/css">\n .maximize_fullscreen_message {\n display: table;\n @@ -134,6 +142,8 @@ }\n </style>\n \n +<!-- TODO: Only supported for ZODB Components -->\n +<dtml-unless bound_names>\n <input type="button" value="Maximize" onclick="maximize()"\n class="editor_action_button" />\n <input type="button" value="Fullscreen" onclick="switchToFullScreen(cm)"\n @@ -141,11 +151,8 @@ \n <div id="merge" style="height: 100%; width: 100%">\n <div id="view" style="display: none;"></div>\n -\n -<textarea id="&dtml-field_id;" name="&dtml-field_id;" style="display: none;">\n -<dtml-var content>\n -</textarea>\n </div>\n +</dtml-unless>\n \n <script type="text/javascript">\n error_element = $(\'div.input > .error\');\n @@ -155,6 +162,29 @@ merge_mode_elem = null;\n \n maximize_mode_message = $(\'<span id="maximize_message">Press ESC to leave maximize mode</span>\');\n +\n + function getTextareaField() {\n + // When the textarea does not exist yet (eg ERP5Form EditorField)\n +<dtml-if field_id>\n + textarea = $(\'#&dtml-field_id;\');\n + if(!textarea.length) {\n + $(\'#merge\').append(\n + \'<textarea id="&dtml-field_id;" name="&dtml-field_id;" style="display: none;">\' + \n + `&dtml-content;` +\n + \'</textarea>\');\n +\n + textarea = $(\'#&dtml-field_id;\');\n + }\n +<dtml-elif textarea_selector>\n + textarea = $(\'<dtml-var name="textarea_selector">\');\n +<dtml-else>\n + <dtml-raise NameError>\n + Either \'textarea_selector\' or \'field_id\' (ID of the textarea field to be\n + created) must be passed.\n + </dtml-raise>\n +</dtml-if>\n + return textarea;\n + }\n \n function maximizeFullscreenRemoveSaveMessage() {\n $(\'.maximize_fullscreen_message\').remove();\n @@ -291,7 +321,7 @@ \n if(merge_mode_elem)\n // TODO: Hack, \'cm\' should work!\n - $(\'#&dtml-field_id;\').val(merge_mode_elem.edit.getValue());\n + getTextareaField().val(merge_mode_elem.edit.getValue());\n else\n cm.save();\n \n @@ -401,9 +431,14 @@ }\n \n function checkPythonSourceCode(text, updateLinting, options, cm) {\n + checker_parameters = {code: text};\n +<dtml-if bound_names>\n + checker_parameters[\'bound_names\'] = <dtml-var name="bound_names">;\n + checker_parameters[\'params\'] = $(\'input[name="params"]\').val();\n +</dtml-if>\n $.post(\n \'&dtml-portal_url;/ERP5Site_checkPythonSourceCodeAsJSON\',\n - {\'data\': JSON.stringify({code: text})},\n + {\'data\': JSON.stringify(checker_parameters)},\n function(data){\n var messages = data.annotations;\n var found = [];\n @@ -420,11 +455,20 @@ updateLinting(cm, found);\n });\n }\n +\n +<dtml-if expr="mode == \'python\'">\n + lint_option = {"getAnnotations": checkPythonSourceCode,\n + "async": true};\n +<dtml-elif expr="mode in (\'css\', \'javascript\')">\n + lint_option = true;\n +<dtml-else>\n + lint_option = false;\n +</dtml-if>\n \n // CodeMirror expects a DOM element, not a JQuery Object\n var cm = CodeMirror.fromTextArea(\n - $(\'#&dtml-field_id;\')[0],\n - {mode: "python",\n + getTextareaField()[0],\n + {mode: "&dtml-mode;",\n lineNumbers: true,\n showTrailingSpace: true,\n tabSize: 2,\n @@ -439,8 +483,7 @@ gutters: ["CodeMirror-lint-markers",\n "CodeMirror-linenumbers",\n "CodeMirror-foldgutter"],\n - lint: {"getAnnotations": checkPythonSourceCode,\n - "async": true}\n + lint: lint_option\n });\n //cm.foldCode(CodeMirror.Pos(8, 0));\n \n @@ -475,7 +518,7 @@ {value: cm.getValue(),\n orig: data,\n highlightDifferences: true,\n - mode: "python",\n + mode: "&dtml-mode;",\n lineNumbers: true,\n showTrailingSpace: true,\n matchBrackets: true,\n @@ -630,7 +673,10 @@ success: successHandler});\n }\n \n +<dtml-unless bound_names>\n + <!-- TODO: Not supported for Python Scripts yet -->\n generateHistorySelectElement();\n +</dtml-unless>\n </script>\n diff --git a/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/csslint.js.xml b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/csslint.js.xml new file mode 100644 index 0000000000000000000000000000000000000000..95b12447e10ae855705596d1e9541b8316cec1a0 --- /dev/null +++ b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/csslint.js.xml @@ -0,0 +1,9388 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="File" module="OFS.Image"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_EtagSupport__etag</string> </key> + <value> <string>ts29784826.78</string> </value> + </item> + <item> + <key> <string>__name__</string> </key> + <value> <string>csslint.js</string> </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>application/javascript</string> </value> + </item> + <item> + <key> <string>data</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> + </value> + </item> + <item> + <key> <string>precondition</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>size</string> </key> + <value> <int>306511</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> + <record id="2" aka="AAAAAAAAAAI="> + <pickle> + <global name="Pdata" module="OFS.Image"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>data</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +/*!\n +CSSLint\n +Copyright (c) 2013 Nicole Sullivan and Nicholas C. Zakas. All rights reserved.\n +\n +Permission is hereby granted, free of charge, to any person obtaining a copy\n +of this software and associated documentation files (the "Software"), to deal\n +in the Software without restriction, including without limitation the rights\n +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n +copies of the Software, and to permit persons to whom the Software is\n +furnished to do so, subject to the following conditions:\n +\n +The above copyright notice and this permission notice shall be included in\n +all copies or substantial portions of the Software.\n +\n +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n +THE SOFTWARE.\n +\n +*/\n +/* Build: v0.10.0 15-August-2013 01:07:22 */\n +var exports = exports || {};\n +var CSSLint = (function(){\n +/*!\n +Parser-Lib\n +Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved.\n +\n +Permission is hereby granted, free of charge, to any person obtaining a copy\n +of this software and associated documentation files (the "Software"), to deal\n +in the Software without restriction, including without limitation the rights\n +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n +copies of the Software, and to permit persons to whom the Software is\n +furnished to do so, subject to the following conditions:\n +\n +The above copyright notice and this permission notice shall be included in\n +all copies or substantial portions of the Software.\n +\n +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n +THE SOFTWARE.\n +\n +*/\n +/* Version v0.2.3, Build time: 19-June-2013 11:16:15 */\n +var parserlib = {};\n +(function(){\n +\n +\n +/**\n + * A generic base to inherit from for any object\n + * that needs event handling.\n + * @class EventTarget\n + * @constructor\n + */\n +function EventTarget(){\n +\n + /**\n + * The array of listeners for various events.\n + * @type Object\n + * @property _listeners\n + * @private\n + */\n + this._listeners = {};\n +}\n +\n +EventTarget.prototype = {\n +\n + //restore constructor\n + constructor: EventTarget,\n +\n + /**\n + * Adds a listener for a given event type.\n + * @param {String} type The type of event to add a listener for.\n + * @param {Function} listener The function to call when the event occurs.\n + * @return {void}\n + * @method addListener\n + */\n + addListener: function(type, listener){\n + if (!this._listeners[type]){\n + this._listeners[type] = [];\n + }\n +\n + this._listeners[type].push(listener);\n + },\n +\n + /**\n + * Fires an event based on the passed-in object.\n + * @param {Object|String} event An object with at least a \'type\' attribute\n + * or a string indicating the event name.\n + * @return {void}\n + * @method fire\n + */\n + fire: function(event){\n + if (typeof event == "string"){\n + event = { type: event };\n + }\n + if (typeof event.target != "undefined"){\n + event.target = this;\n + }\n +\n + if (typeof event.type == "undefined"){\n + throw new Error("Event object missing \'type\' property.");\n + }\n +\n + if (this._listeners[event.type]){\n +\n + //create a copy of the array and use that so listeners can\'t chane\n + var listeners = this._listeners[event.type].concat();\n + for (var i=0, len=listeners.length; i < len; i++){\n + listeners[i].call(this, event);\n + }\n + }\n + },\n +\n + /**\n + * Removes a listener for a given event type.\n + * @param {String} type The type of event to remove a listener from.\n + * @param {Function} listener The function to remove from the event.\n + * @return {void}\n + * @method removeListener\n + */\n + removeListener: function(type, listener){\n + if (this._listeners[type]){\n + var listeners = this._listeners[type];\n + for (var i=0, len=listeners.length; i < len; i++){\n + if (listeners[i] === listener){\n + listeners.splice(i, 1);\n + break;\n + }\n + }\n +\n +\n + }\n + }\n +};\n +/**\n + * Convenient way to read through strings.\n + * @namespace parserlib.util\n + * @class StringReader\n + * @constructor\n + * @param {String} text The text to read.\n + */\n +function StringReader(text){\n +\n + /**\n + * The input text with line endings normalized.\n + * @property _input\n + * @type String\n + * @private\n + */\n + this._input = text.replace(/\\n\\r?/g, "\\n");\n +\n +\n + /**\n + * The row for the character to be read next.\n + * @property _line\n + * @type int\n + * @private\n + */\n + this._line = 1;\n +\n +\n + /**\n + * The column for the character to be read next.\n + * @property _col\n + * @type int\n + * @private\n + */\n + this._col = 1;\n +\n + /**\n + * The index of the character in the input to be read next.\n + * @property _cursor\n + * @type int\n + * @private\n + */\n + this._cursor = 0;\n +}\n +\n +StringReader.prototype = {\n +\n + //restore constructor\n + constructor: StringReader,\n +\n + //-------------------------------------------------------------------------\n + // Position info\n + //-------------------------------------------------------------------------\n +\n + /**\n + * Returns the column of the character to be read next.\n + * @return {int} The column of the character to be read next.\n + * @method getCol\n + */\n + getCol: function(){\n + return this._col;\n + },\n +\n + /**\n + * Returns the row of the character to be read next.\n + * @return {int} The row of the character to be read next.\n + * @method getLine\n + */\n + getLine: function(){\n + return this._line ;\n + },\n +\n + /**\n + * Determines if you\'re at the end of the input.\n + * @return {Boolean} True if there\'s no more input, false otherwise.\n + * @method eof\n + */\n + eof: function(){\n + return (this._cursor == this._input.length);\n + },\n +\n + //-------------------------------------------------------------------------\n + // Basic reading\n + //-------------------------------------------------------------------------\n +\n + /**\n + * Reads the next character without advancing the cursor.\n + * @param {int} count How many characters to look ahead (default is 1).\n + * @return {String} The next character or null if there is no next character.\n + * @method peek\n + */\n + peek: function(count){\n + var c = null;\n + count = (typeof count == "undefined" ? 1 : count);\n +\n + //if we\'re not at the end of the input...\n + if (this._cursor < this._input.length){\n +\n + //get character and increment cursor and column\n + c = this._input.charAt(this._cursor + count - 1);\n + }\n +\n + return c;\n + },\n +\n + /**\n + * Reads the next character from the input and adjusts the row and column\n + * accordingly.\n + * @return {String} The next character or null if there is no next character.\n + * @method read\n + */\n + read: function(){\n + var c = null;\n +\n + //if we\'re not at the end of the input...\n + if (this._cursor < this._input.length){\n +\n + //if the last character was a newline, increment row count\n + //and reset column count\n + if (this._input.charAt(this._cursor) == "\\n"){\n + this._line++;\n + this._col=1;\n + } else {\n + this._col++;\n + }\n +\n + //get character and increment cursor and column\n + c = this._input.charAt(this._cursor++);\n + }\n +\n + return c;\n + },\n +\n + //-------------------------------------------------------------------------\n + // Misc\n + //-------------------------------------------------------------------------\n +\n + /**\n + * Saves the current location so it can be returned to later.\n + * @method mark\n + * @return {void}\n + */\n + mark: function(){\n + this._bookmark = {\n + cursor: this._cursor,\n + line: this._line,\n + col: this._col\n + };\n + },\n +\n + reset: function(){\n + if (this._bookmark){\n + this._cursor = this._bookmark.cursor;\n + this._line = this._bookmark.line;\n + this._col = this._bookmark.col;\n + delete this._bookmark;\n + }\n + },\n +\n + //-------------------------------------------------------------------------\n + // Advanced reading\n + //-------------------------------------------------------------------------\n +\n + /**\n + * Reads up to and including the given string. Throws an error if that\n + * string is not found.\n + * @param {String} pattern The string to read.\n + * @return {String} The string when it is found.\n + * @throws Error when the string pattern is not found.\n + * @method readTo\n + */\n + readTo: function(pattern){\n +\n + var buffer = "",\n + c;\n +\n + /*\n + * First, buffer must be the same length as the pattern.\n + * Then, buffer must end with the pattern or else reach the\n + * end of the input.\n + */\n + while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){\n + c = this.read();\n + if (c){\n + buffer += c;\n + } else {\n + throw new Error("Expected \\"" + pattern + "\\" at line " + this._line + ", col " + this._col + ".");\n + }\n + }\n +\n + return buffer;\n +\n + },\n +\n + /**\n + * Reads characters while each character causes the given\n + * filter function to return true. The function is passed\n + * in each character and either returns true to continue\n + * reading or false to stop.\n + * @param {Function} filter The function to read on each character.\n + * @return {String} The string made up of all characters that passed the\n + * filter check.\n + * @method readWhile\n + */\n + readWhile: function(filter){\n +\n + var buffer = "",\n + c = this.read();\n +\n + while(c !== null && filter(c)){\n + buffer += c;\n + c = this.read();\n + }\n +\n + return buffer;\n +\n + },\n +\n + /**\n + * Reads characters that match either text or a regular expression and\n + * returns those characters. If a match is found, the row and column\n + * are adjusted; if no match is found, the reader\'s state is unchanged.\n + * reading or false to stop.\n + * @param {String|RegExp} matchter If a string, then the literal string\n + * value is searched for. If a regular expression, then any string\n + * matching the pattern is search for.\n + * @return {String} The string made up of all characters that matched or\n + * null if there was no match.\n + * @method readMatch\n + */\n + readMatch: function(matcher){\n +\n + var source = this._input.substring(this._cursor),\n + value = null;\n +\n + //if it\'s a string, just do a straight match\n + if (typeof matcher == "string"){\n + if (source.indexOf(matcher) === 0){\n + value = this.readCount(matcher.length);\n + }\n + } else if (matcher instanceof RegExp){\n + if (matcher.test(source)){\n + value = this.readCount(RegExp.lastMatch.length);\n + }\n + }\n +\n + return value;\n + },\n +\n +\n + /**\n + * Reads a given number of characters. If the end of the input is reached,\n + * it reads only the remaining characters and does not throw an error.\n + * @param {int} count The number of characters to read.\n + * @return {String} The string made up the read characters.\n + * @method readCount\n + */\n + readCount: function(count){\n + var buffer = "";\n +\n + while(count--){\n + buffer += this.read();\n + }\n +\n + return buffer;\n + }\n +\n +};\n +/**\n + * Type to use when a syntax error occurs.\n + * @class SyntaxError\n + * @namespace parserlib.util\n + * @constructor\n + * @param {String} message The error message.\n + * @param {int} line The line at which the error occurred.\n + * @param {int} col The column at which the error occurred.\n + */\n +function SyntaxError(message, line, col){\n +\n + /**\n + * The column at which the error occurred.\n + * @type int\n + * @property col\n + */\n + this.col = col;\n +\n + /**\n + * The line at which the error occurred.\n + * @type int\n + * @property line\n + */\n + this.line = line;\n +\n + /**\n + * The text representation of the unit.\n + * @type String\n + * @property text\n + */\n + this.message = message;\n +\n +}\n +\n +//inherit from Error\n +SyntaxError.prototype = new Error();\n +/**\n + * Base type to represent a single syntactic unit.\n + * @class SyntaxUnit\n + * @namespace parserlib.util\n + * @constructor\n + * @param {String} text The text of the unit.\n + * @param {int} line The line of text on which the unit resides.\n + * @param {int} col The column of text on which the unit resides.\n + */\n +function SyntaxUnit(text, line, col, type){\n +\n +\n + /**\n + * The column of text on which the unit resides.\n + * @type int\n + * @property col\n + */\n + this.col = col;\n +\n + /**\n + * The line of text on which the unit resides.\n + * @type int\n + * @property line\n + */\n + this.line = line;\n +\n + /**\n + * The text representation of the unit.\n + * @type String\n + * @property text\n + */\n + this.text = text;\n +\n + /**\n + * The type of syntax unit.\n + * @type int\n + * @property type\n + */\n + this.type = type;\n +}\n +\n +/**\n + * Create a new syntax unit based solely on the given token.\n + * Convenience method for creating a new syntax unit when\n + * it represents a single token instead of multiple.\n + * @param {Object} token The token object to represent.\n + * @return {parserlib.util.SyntaxUnit} The object representing the token.\n + * @static\n + * @method fromToken\n + */\n +SyntaxUnit.fromToken = function(token){\n + return new SyntaxUnit(token.value, token.startLine, token.startCol);\n +};\n +\n +SyntaxUnit.prototype = {\n +\n + //restore constructor\n + constructor: SyntaxUnit,\n +\n + /**\n + * Returns the text representation of the unit.\n + * @return {String} The text representation of the unit.\n + * @method valueOf\n + */\n + valueOf: function(){\n + return this.toString();\n + },\n +\n + /**\n + * Returns the text representation of the unit.\n + * @return {String} The text representation of the unit.\n + * @method toString\n + */\n + toString: function(){\n + return this.text;\n + }\n +\n +};\n +/*global StringReader, SyntaxError*/\n +\n +/**\n + * Generic TokenStream providing base functionality.\n + * @class TokenStreamBase\n + * @namespace parserlib.util\n + * @constructor\n + * @param {String|StringReader} input The text to tokenize or a reader from\n + * which to read the input.\n + */\n +function TokenStreamBase(input, tokenData){\n +\n + /**\n + * The string reader for easy access to the text.\n + * @type StringReader\n + * @property _reader\n + * @private\n + */\n + this._reader = input ? new StringReader(input.toString()) : null;\n +\n + /**\n + * Token object for the last consumed token.\n + * @type Token\n + * @property _token\n + * @private\n + */\n + this._token = null;\n +\n + /**\n + * The array of token information.\n + * @type Array\n + * @property _tokenData\n + * @private\n + */\n + this._tokenData = tokenData;\n +\n + /**\n + * Lookahead token buffer.\n + * @type Array\n + * @property _lt\n + * @private\n + */\n + this._lt = [];\n +\n + /**\n + * Lookahead token buffer index.\n + * @type int\n + * @property _ltIndex\n + * @private\n + */\n + this._ltIndex = 0;\n +\n + this._ltIndexCache = [];\n +}\n +\n +/**\n + * Accepts an array of token information and outputs\n + * an array of token data containing key-value mappings\n + * and matching functions that the TokenStream needs.\n + * @param {Array} tokens An array of token descriptors.\n + * @return {Array} An array of processed token data.\n + * @method createTokenData\n + * @static\n + */\n +TokenStreamBase.createTokenData = function(tokens){\n +\n + var nameMap = [],\n + typeMap = {},\n + tokenData = tokens.concat([]),\n + i = 0,\n + len = tokenData.length+1;\n +\n + tokenData.UNKNOWN = -1;\n + tokenData.unshift({name:"EOF"});\n +\n + for (; i < len; i++){\n + nameMap.push(tokenData[i].name);\n + tokenData[tokenData[i].name] = i;\n + if (tokenData[i].text){\n + typeMap[tokenData[i].text] = i;\n + }\n + }\n +\n + tokenData.name = function(tt){\n + return nameMap[tt];\n + };\n +\n + tokenData.type = function(c){\n + return typeMap[c];\n + };\n +\n + return tokenData;\n +};\n +\n +TokenStreamBase.prototype = {\n +\n + //restore constructor\n + constructor: TokenStreamBase,\n +\n + //-------------------------------------------------------------------------\n + // Matching methods\n + //-------------------------------------------------------------------------\n +\n + /**\n + * Determines if the next token matches the given token type.\n + * If so, that token is consumed; if not, the token is placed\n + * back onto the token stream. You can pass in any number of\n + * token types and this will return true if any of the token\n + * types is found.\n + * @param {int|int[]} tokenTypes Either a single token type or an array of\n + * token types that the next token might be. If an array is passed,\n + * it\'s assumed that the token can be any of these.\n + * @param {variant} channel (Optional) The channel to read from. If not\n + * provided, reads from the default (unnamed) channel.\n + * @return {Boolean} True if the token type matches, false if not.\n + * @method match\n + */\n + match: function(tokenTypes, channel){\n +\n + //always convert to an array, makes things easier\n + if (!(tokenTypes instanceof Array)){\n + tokenTypes = [tokenTypes];\n + }\n +\n + var tt = this.get(channel),\n + i = 0,\n + len = tokenTypes.length;\n +\n + while(i < len){\n + if (tt == tokenTypes[i++]){\n + return true;\n + }\n + }\n +\n + //no match found, put the token back\n + this.unget();\n + return false;\n + },\n +\n + /**\n + * Determines if the next token matches the given token type.\n + * If so, that token is consumed; if not, an error is thrown.\n + * @param {int|int[]} tokenTypes Either a single token type or an array of\n + * token types that the next token should be. If an array is passed,\n + * it\'s assumed that the token must be one of these.\n + * @param {variant} channel (Optional) The channel to read from. If not\n + * provided, reads from the default (unnamed) channel.\n + * @return {void}\n + * @method mustMatch\n + */\n + mustMatch: function(tokenTypes, channel){\n +\n + var token;\n +\n + //always convert to an array, makes things easier\n + if (!(tokenTypes instanceof Array)){\n + tokenTypes = [tokenTypes];\n + }\n +\n + if (!this.match.apply(this, arguments)){\n + token = this.LT(1);\n + throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name +\n + " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);\n + }\n + },\n +\n + //-------------------------------------------------------------------------\n + // Consuming methods\n + //-------------------------------------------------------------------------\n +\n + /**\n + * Keeps reading from the token stream until either one of the specified\n + * token types is found or until the end of the input is reached.\n + * @param {int|int[]} tokenTypes Either a single token type or an array of\n + * token types that the next token should be. If an array is passed,\n + * it\'s assumed that the token must be one of these.\n + * @param {variant} channel (Optional) The channel to read from. If not\n + * provided, reads from the default (unnamed) channel.\n + * @return {void}\n + * @method advance\n + */\n + advance: function(tokenTypes, channel){\n +\n + while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){\n + this.get();\n + }\n +\n + return this.LA(0);\n + },\n +\n + /**\n + * Consumes the next token from the token stream.\n + * @return {int} The token type of the token that was just consumed.\n + * @method get\n + */\n + get: function(channel){\n +\n + var tokenInfo = this._tokenData,\n + reader = this._reader,\n + value,\n + i =0,\n + len = tokenInfo.length,\n + found = false,\n + token,\n + info;\n +\n + //check the lookahead buffer first\n + if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){\n +\n + i++;\n + this._token = this._lt[this._ltIndex++];\n + info = tokenInfo[this._token.type];\n +\n + //obey channels logic\n + while((info.channel !== undefined && channel !== info.channel) &&\n + this._ltIndex < this._lt.length){\n + this._token = this._lt[this._ltIndex++];\n + info = tokenInfo[this._token.type];\n + i++;\n + }\n +\n + //here be dragons\n + if ((info.channel === undefined || channel === info.channel) &&\n + this._ltIndex <= this._lt.length){\n + this._ltIndexCache.push(i);\n + return this._token.type;\n + }\n + }\n +\n + //call token retriever method\n + token = this._getToken();\n +\n + //if it should be hidden, don\'t save a token\n + if (token.type > -1 && !tokenInfo[token.type].hide){\n +\n + //apply token channel\n + token.channel = tokenInfo[token.type].channel;\n +\n + //save for later\n + this._token = token;\n + this._lt.push(token);\n +\n + //save space that will be moved (must be done before array is truncated)\n + this._ltIndexCache.push(this._lt.length - this._ltIndex + i);\n +\n + //keep the buffer under 5 items\n + if (this._lt.length > 5){\n + this._lt.shift();\n + }\n +\n + //also keep the shift buffer under 5 items\n + if (this._ltIndexCache.length > 5){\n + this._ltIndexCache.shift();\n + }\n +\n + //update lookahead index\n + this._ltIndex = this._lt.length;\n + }\n +\n + /*\n + * Skip to the next token if:\n + * 1. The token type is marked as hidden.\n + * 2. The token type has a channel specified and it isn\'t the current channel.\n + */\n + info = tokenInfo[token.type];\n + if (info &&\n + (info.hide ||\n + (info.channel !== undefined && channel !== info.channel))){\n + return this.get(channel);\n + } else {\n + //return just the type\n + return token.type;\n + }\n + },\n +\n + /**\n + * Looks ahead a certain number of tokens and returns the token type at\n + * that position. This will throw an error if you lookahead past the\n + * end of input, past the size of the lookahead buffer, or back past\n + * the first token in the lookahead buffer.\n + * @param {int} The index of the token type to retrieve. 0 for the\n + * current token, 1 for the next, -1 for the previous, etc.\n + * @return {int} The token type of the token in the given position.\n + * @method LA\n + */\n + LA: function(index){\n + var total = index,\n + tt;\n + if (index > 0){\n + //TODO: Store 5 somewhere\n + if (index > 5){\n + throw new Error("Too much lookahead.");\n + }\n +\n + //get all those tokens\n + while(total){\n + tt = this.get();\n + total--;\n + }\n +\n + //unget all those tokens\n + while(total < index){\n + this.unget();\n + total++;\n + }\n + } else if (index < 0){\n +\n + if(this._lt[this._ltIndex+index]){\n + tt = this._lt[this._ltIndex+index].type;\n + } else {\n + throw new Error("Too much lookbehind.");\n + }\n +\n + } else {\n + tt = this._token.type;\n + }\n +\n + return tt;\n +\n + },\n +\n + /**\n + * Looks ahead a certain number of tokens and returns the token at\n + * that position. This will throw an error if you lookahead past the\n + * end of input, past the size of the lookahead buffer, or back past\n + * the first token in the lookahead buffer.\n + * @param {int} The index of the token type to retrieve. 0 for the\n + * current token, 1 for the next, -1 for the previous, etc.\n + * @return {Object} The token of the token in the given position.\n + * @method LA\n + */\n + LT: function(index){\n +\n + //lookahead first to prime the token buffer\n + this.LA(index);\n +\n + //now find the token, subtract one because _ltIndex is already at the next index\n + return this._lt[this._ltIndex+index-1];\n + },\n +\n + /**\n + * Returns the token type for the next token in the stream without\n + * consuming it.\n + * @return {int} The token type of the next token in the stream.\n + * @method peek\n + */\n + peek: function(){\n + return this.LA(1);\n + },\n +\n + /**\n + * Returns the actual token object for the last consumed token.\n + * @return {Token} The token object for the last consumed token.\n + * @method token\n + */\n + token: function(){\n + return this._token;\n + },\n +\n + /**\n + * Returns the name of the token for the given token type.\n + * @param {int} tokenType The type of token to get the name of.\n + * @return {String} The name of the token or "UNKNOWN_TOKEN" for any\n + * invalid token type.\n + * @method tokenName\n + */\n + tokenName: function(tokenType){\n + if (tokenType < 0 || tokenType > this._tokenData.length){\n + return "UNKNOWN_TOKEN";\n + } else {\n + return this._tokenData[tokenType].name;\n + }\n + },\n +\n + /**\n + * Returns the token type value for the given token name.\n + * @param {String} tokenName The name of the token whose value should be returned.\n + * @return {int} The token type value for the given token name or -1\n + * for an unknown token.\n + * @method tokenName\n + */\n + tokenType: function(tokenName){\n + return this._tokenData[tokenName] || -1;\n + },\n +\n + /**\n + * Returns the last consumed token to the token stream.\n + * @method unget\n + */\n + unget: function(){\n + //if (this._ltIndex > -1){\n + if (this._ltIndexCache.length){\n + this._ltIndex -= this._ltIndexCache.pop();//--;\n + this._token = this._lt[this._ltIndex - 1];\n + } else {\n + throw new Error("Too much lookahead.");\n + }\n + }\n +\n +};\n +\n +\n +\n +\n +parserlib.util = {\n +StringReader: StringReader,\n +SyntaxError : SyntaxError,\n +SyntaxUnit : SyntaxUnit,\n +EventTarget : EventTarget,\n +TokenStreamBase : TokenStreamBase\n +};\n +})();\n +\n +\n +/*\n +Parser-Lib\n +Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved.\n +\n +Permission is hereby granted, free of charge, to any person obtaining a copy\n +of this software and associated documentation files (the "Software"), to deal\n +in the Software without restriction, including without limitation the rights\n +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n +copies of the Software, and to permit persons to whom the Software is\n +furnished to do so, subject to the following conditions:\n +\n +The above copyright notice and this permission notice shall be included in\n +all copies or substantial portions of the Software.\n +\n +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n +THE SOFTWARE.\n +\n +*/\n +/* Version v0.2.3, Build time: 19-June-2013 11:16:15 */\n +(function(){\n +var EventTarget = parserlib.util.EventTarget,\n +TokenStreamBase = parserlib.util.TokenStreamBase,\n +StringReader = parserlib.util.StringReader,\n +SyntaxError = parserlib.util.SyntaxError,\n +SyntaxUnit = parserlib.util.SyntaxUnit;\n +\n +\n +var Colors = {\n + aliceblue :"#f0f8ff",\n + antiquewhite :"#faebd7",\n + aqua :"#00ffff",\n + aquamarine :"#7fffd4",\n + azure :"#f0ffff",\n + beige :"#f5f5dc",\n + bisque :"#ffe4c4",\n + black :"#000000",\n + blanchedalmond :"#ffebcd",\n + blue :"#0000ff",\n + blueviolet :"#8a2be2",\n + brown :"#a52a2a",\n + burlywood :"#deb887",\n + cadetblue :"#5f9ea0",\n + chartreuse :"#7fff00",\n + chocolate :"#d2691e",\n + coral :"#ff7f50",\n + cornflowerblue :"#6495ed",\n + cornsilk :"#fff8dc",\n + crimson :"#dc143c",\n + cyan :"#00ffff",\n + darkblue :"#00008b",\n + darkcyan :"#008b8b",\n + darkgoldenrod :"#b8860b",\n + darkgray :"#a9a9a9",\n + darkgreen :"#006400",\n + darkkhaki :"#bdb76b",\n + darkmagenta :"#8b008b",\n + darkolivegreen :"#556b2f",\n + darkorange :"#ff8c00",\n + darkorchid :"#9932cc",\n + darkred :"#8b0000",\n + darksalmon :"#e9967a",\n + darkseagreen :"#8fbc8f",\n + darkslateblue :"#483d8b",\n + darkslategray :"#2f4f4f",\n + darkturquoise :"#00ced1",\n + darkviolet :"#9400d3",\n + deeppink :"#ff1493",\n + deepskyblue :"#00bfff",\n + dimgray :"#696969",\n + dodgerblue :"#1e90ff",\n + firebrick :"#b22222",\n + floralwhite :"#fffaf0",\n + forestgreen :"#228b22",\n + fuchsia :"#ff00ff",\n + gainsboro :"#dcdcdc",\n + ghostwhite :"#f8f8ff",\n + gold :"#ffd700",\n + goldenrod :"#daa520",\n + gray :"#808080",\n + green :"#008000",\n + greenyellow :"#adff2f",\n + honeydew :"#f0fff0",\n + hotpink :"#ff69b4",\n + indianred :"#cd5c5c",\n + indigo :"#4b0082",\n + ivory :"#fffff0",\n + khaki :"#f0e68c",\n + lavender :"#e6e6fa",\n + lavenderblush :"#fff0f5",\n + lawngreen :"#7cfc00",\n + lemonchiffon :"#fffacd",\n + lightblue :"#add8e6",\n + lightcoral :"#f08080",\n + lightcyan :"#e0ffff",\n + lightgoldenrodyellow :"#fafad2",\n + lightgray :"#d3d3d3",\n + lightgreen :"#90ee90",\n + lightpink :"#ffb6c1",\n + lightsalmon :"#ffa07a",\n + lightseagreen :"#20b2aa",\n + lightskyblue :"#87cefa",\n + lightslategray :"#778899",\n + lightsteelblue :"#b0c4de",\n + lightyellow :"#ffffe0",\n + lime :"#00ff00",\n + limegreen :"#32cd32",\n + linen :"#faf0e6",\n + magenta :"#ff00ff",\n + maroon :"#800000",\n + mediumaquamarine:"#66cdaa",\n + mediumblue :"#0000cd",\n + mediumorchid :"#ba55d3",\n + mediumpurple :"#9370d8",\n + mediumseagreen :"#3cb371",\n + mediumslateblue :"#7b68ee",\n + mediumspringgreen :"#00fa9a",\n + mediumturquoise :"#48d1cc",\n + mediumvioletred :"#c71585",\n + midnightblue :"#191970",\n + mintcream :"#f5fffa",\n + mistyrose :"#ffe4e1",\n + moccasin :"#ffe4b5",\n + navajowhite :"#ffdead",\n + navy :"#000080",\n + oldlace :"#fdf5e6",\n + olive :"#808000",\n + olivedrab :"#6b8e23",\n + orange :"#ffa500",\n + orangered :"#ff4500",\n + orchid :"#da70d6",\n + palegoldenrod :"#eee8aa",\n + palegreen :"#98fb98",\n + paleturquoise :"#afeeee",\n + palevioletred :"#d87093",\n + papayawhip :"#ffefd5",\n + peachpuff :"#ffdab9",\n + peru :"#cd853f",\n + pink :"#ffc0cb",\n + plum :"#dda0dd",\n + powderblue :"#b0e0e6",\n + purple :"#800080",\n + red :"#ff0000",\n + rosybrown :"#bc8f8f",\n + royalblue :"#4169e1",\n + saddlebrown :"#8b4513",\n + salmon :"#fa8072",\n + sandybrown :"#f4a460",\n + seagreen :"#2e8b57",\n + seashell :"#fff5ee",\n + sienna :"#a0522d",\n + silver :"#c0c0c0",\n + skyblue :"#87ceeb",\n + slateblue :"#6a5acd",\n + slategray :"#708090",\n + snow :"#fffafa",\n + springgreen :"#00ff7f",\n + steelblue :"#4682b4",\n + tan :"#d2b48c",\n + teal :"#008080",\n + thistle :"#d8bfd8",\n + tomato :"#ff6347",\n + turquoise :"#40e0d0",\n + violet :"#ee82ee",\n + wheat :"#f5deb3",\n + white :"#ffffff",\n + whitesmoke :"#f5f5f5",\n + yellow :"#ffff00",\n + yellowgreen :"#9acd32",\n + //CSS2 system colors http://www.w3.org/TR/css3-color/#css2-system\n + activeBorder :"Active window border.",\n + activecaption :"Active window caption.",\n + appworkspace :"Background color of multiple document interface.",\n + background :"Desktop background.",\n + buttonface :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.",\n + buttonhighlight :"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",\n + buttonshadow :"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",\n + buttontext :"Text on push buttons.",\n + captiontext :"Text in caption, size box, and scrollbar arrow box.",\n + graytext :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.",\n + highlight :"Item(s) selected in a control.",\n + highlighttext :"Text of item(s) selected in a control.",\n + inactiveborder :"Inactive window border.",\n + inactivecaption :"Inactive window caption.",\n + inactivecaptiontext :"Color of text in an inactive caption.",\n + infobackground :"Background color for tooltip controls.",\n + infotext :"Text color for tooltip controls.",\n + menu :"Menu background.",\n + menutext :"Text in menus.",\n + scrollbar :"Scroll bar gray area.",\n + threeddarkshadow :"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",\n + threedface :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",\n + threedhighlight :"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",\n + threedlightshadow :"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",\n + threedshadow :"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",\n + window :"Window background.",\n + windowframe :"Window frame.",\n + windowtext :"Text in windows."\n +};\n +/*global SyntaxUnit, Parser*/\n +/**\n + * Represents a selector combinator (whitespace, +, >).\n + * @namespace parserlib.css\n + * @class Combinator\n + * @extends parserlib.util.SyntaxUnit\n + * @constructor\n + * @param {String} text The text representation of the unit.\n + * @param {int} line The line of text on which the unit resides.\n + * @param {int} col The column of text on which the unit resides.\n + */\n +function Combinator(text, line, col){\n +\n + SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE);\n +\n + /**\n + * The type of modifier.\n + * @type String\n + * @property type\n + */\n + this.type = "unknown";\n +\n + //pretty simple\n + if (/^\\s+$/.test(text)){\n + this.type = "descendant";\n + } else if (text == ">"){\n + this.type = "child";\n + } else if (text == "+"){\n + this.type = "adjacent-sibling";\n + } else if (text == "~"){\n + this.type = "sibling";\n + }\n +\n +}\n +\n +Combinator.prototype = new SyntaxUnit();\n +Combinator.prototype.constructor = Combinator;\n +\n +\n +/*global SyntaxUnit, Parser*/\n +/**\n + * Represents a media feature, such as max-width:500.\n + * @namespace parserlib.css\n + * @class MediaFeature\n + * @extends parserlib.util.SyntaxUnit\n + * @constructor\n + * @param {SyntaxUnit} name The name of the feature.\n + * @param {SyntaxUnit} value The value of the feature or null if none.\n + */\n +function MediaFeature(name, value){\n +\n + SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE);\n +\n + /**\n + * The name of the media feature\n + * @type String\n + * @property name\n + */\n + this.name = name;\n +\n + /**\n + * The value for the feature or null if there is none.\n + * @type SyntaxUnit\n + * @property value\n + */\n + this.value = value;\n +}\n +\n +MediaFeature.prototype = new SyntaxUnit();\n +MediaFeature.prototype.constructor = MediaFeature;\n +\n +\n +/*global SyntaxUnit, Parser*/\n +/**\n + * Represents an individual media query.\n + * @namespace parserlib.css\n + * @class MediaQuery\n + * @extends parserlib.util.SyntaxUnit\n + * @constructor\n + * @param {String} modifier The modifier "not" or "only" (or null).\n + * @param {String} mediaType The type of media (i.e., "print").\n + * @param {Array} parts Array of selectors parts making up this selector.\n + * @param {int} line The line of text on which the unit resides.\n + * @param {int} col The column of text on which the unit resides.\n + */\n +function MediaQuery(modifier, mediaType, features, line, col){\n +\n + SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE);\n +\n + /**\n + * The media modifier ("not" or "only")\n + * @type String\n + * @property modifier\n + */\n + this.modifier = modifier;\n +\n + /**\n + * The mediaType (i.e., "print")\n + * @type String\n + * @property mediaType\n + */\n + this.mediaType = mediaType;\n +\n + /**\n + * The parts that make up the selector.\n + * @type Array\n + * @property features\n + */\n + this.features = features;\n +\n +}\n +\n +MediaQuery.prototype = new SyntaxUnit();\n +MediaQuery.prototype.constructor = MediaQuery;\n +\n +\n +/*global Tokens, TokenStream, SyntaxError, Properties, Validation, ValidationError, SyntaxUnit,\n + PropertyValue, PropertyValuePart, SelectorPart, SelectorSubPart, Selector,\n + PropertyName, Combinator, MediaFeature, MediaQuery, EventTarget */\n +\n +/**\n + * A CSS3 parser.\n + * @namespace parserlib.css\n + * @class Parser\n + * @constructor\n + * @param {Object} options (Optional) Various options for the parser:\n + * starHack (true|false) to allow IE6 star hack as valid,\n + * underscoreHack (true|false) to interpret leading underscores\n + * as IE6-7 targeting for known properties, ieFilters (true|false)\n + * to indicate that IE < 8 filters should be accepted and not throw\n + * syntax errors.\n + */\n +function Parser(options){\n +\n + //inherit event functionality\n + EventTarget.call(this);\n +\n +\n + this.options = options || {};\n +\n + this._tokenStream = null;\n +}\n +\n +//Static constants\n +Parser.DEFAULT_TYPE = 0;\n +Parser.COMBINATOR_TYPE = 1;\n +Parser.MEDIA_FEATURE_TYPE = 2;\n +Parser.MEDIA_QUERY_TYPE = 3;\n +Parser.PROPERTY_NAME_TYPE = 4;\n +Parser.PROPERTY_VALUE_TYPE = 5;\n +Parser.PROPERTY_VALUE_PART_TYPE = 6;\n +Parser.SELECTOR_TYPE = 7;\n +Parser.SELECTOR_PART_TYPE = 8;\n +Parser.SELECTOR_SUB_PART_TYPE = 9;\n +\n +Parser.prototype = function(){\n +\n + var proto = new EventTarget(), //new prototype\n + prop,\n + additions = {\n +\n + //restore constructor\n + constructor: Parser,\n +\n + //instance constants - yuck\n + DEFAULT_TYPE : 0,\n + COMBINATOR_TYPE : 1,\n + MEDIA_FEATURE_TYPE : 2,\n + MEDIA_QUERY_TYPE : 3,\n + PROPERTY_NAME_TYPE : 4,\n + PROPERTY_VALUE_TYPE : 5,\n + PROPERTY_VALUE_PART_TYPE : 6,\n + SELECTOR_TYPE : 7,\n + SELECTOR_PART_TYPE : 8,\n + SELECTOR_SUB_PART_TYPE : 9,\n +\n + //-----------------------------------------------------------------\n + // Grammar\n + //-----------------------------------------------------------------\n +\n + _stylesheet: function(){\n +\n + /*\n + * stylesheet\n + * : [ CHARSET_SYM S* STRING S* \';\' ]?\n + * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*\n + * [ namespace [S|CDO|CDC]* ]*\n + * [ [ ruleset | media | page | font_face | keyframes ] [S|CDO|CDC]* ]*\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + charset = null,\n + count,\n + token,\n + tt;\n +\n + this.fire("startstylesheet");\n +\n + //try to read character set\n + this._charset();\n +\n + this._skipCruft();\n +\n + //try to read imports - may be more than one\n + while (tokenStream.peek() == Tokens.IMPORT_SYM){\n + this._import();\n + this._skipCruft();\n + }\n +\n + //try to read namespaces - may be more than one\n + while (tokenStream.peek() == Tokens.NAMESPACE_SYM){\n + this._namespace();\n + this._skipCruft();\n + }\n +\n + //get the next token\n + tt = tokenStream.peek();\n +\n + //try to read the rest\n + while(tt > Tokens.EOF){\n +\n + try {\n +\n + switch(tt){\n + case Tokens.MEDIA_SYM:\n + this._media();\n + this._skipCruft();\n + break;\n + case Tokens.PAGE_SYM:\n + this._page();\n + this._skipCruft();\n + break;\n + case Tokens.FONT_FACE_SYM:\n + this._font_face();\n + this._skipCruft();\n + break;\n + case Tokens.KEYFRAMES_SYM:\n + this._keyframes();\n + this._skipCruft();\n + break;\n + case Tokens.VIEWPORT_SYM:\n + this._viewport();\n + this._skipCruft();\n + break;\n + case Tokens.UNKNOWN_SYM: //unknown @ rule\n + tokenStream.get();\n + if (!this.options.strict){\n +\n + //fire error event\n + this.fire({\n + type: "error",\n + error: null,\n + message: "Unknown @ rule: " + tokenStream.LT(0).value + ".",\n + line: tokenStream.LT(0).startLine,\n + col: tokenStream.LT(0).startCol\n + });\n +\n + //skip braces\n + count=0;\n + while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){\n + count++; //keep track of nesting depth\n + }\n +\n + while(count){\n + tokenStream.advance([Tokens.RBRACE]);\n + count--;\n + }\n +\n + } else {\n + //not a syntax error, rethrow it\n + throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol);\n + }\n + break;\n + case Tokens.S:\n + this._readWhitespace();\n + break;\n + default:\n + if(!this._ruleset()){\n +\n + //error handling for known issues\n + switch(tt){\n + case Tokens.CHARSET_SYM:\n + token = tokenStream.LT(1);\n + this._charset(false);\n + throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol);\n + case Tokens.IMPORT_SYM:\n + token = tokenStream.LT(1);\n + this._import(false);\n + throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol);\n + case Tokens.NAMESPACE_SYM:\n + token = tokenStream.LT(1);\n + this._namespace(false);\n + throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol);\n + default:\n + tokenStream.get(); //get the last token\n + this._unexpectedToken(tokenStream.token());\n + }\n +\n + }\n + }\n + } catch(ex) {\n + if (ex instanceof SyntaxError && !this.options.strict){\n + this.fire({\n + type: "error",\n + error: ex,\n + message: ex.message,\n + line: ex.line,\n + col: ex.col\n + });\n + } else {\n + throw ex;\n + }\n + }\n +\n + tt = tokenStream.peek();\n + }\n +\n + if (tt != Tokens.EOF){\n + this._unexpectedToken(tokenStream.token());\n + }\n +\n + this.fire("endstylesheet");\n + },\n +\n + _charset: function(emit){\n + var tokenStream = this._tokenStream,\n + charset,\n + token,\n + line,\n + col;\n +\n + if (tokenStream.match(Tokens.CHARSET_SYM)){\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol;\n +\n + this._readWhitespace();\n + tokenStream.mustMatch(Tokens.STRING);\n +\n + token = tokenStream.token();\n + charset = token.value;\n +\n + this._readWhitespace();\n + tokenStream.mustMatch(Tokens.SEMICOLON);\n +\n + if (emit !== false){\n + this.fire({\n + type: "charset",\n + charset:charset,\n + line: line,\n + col: col\n + });\n + }\n + }\n + },\n +\n + _import: function(emit){\n + /*\n + * import\n + * : IMPORT_SYM S*\n + * [STRING|URI] S* media_query_list? \';\' S*\n + */\n +\n + var tokenStream = this._tokenStream,\n + tt,\n + uri,\n + importToken,\n + mediaList = [];\n +\n + //read import symbol\n + tokenStream.mustMatch(Tokens.IMPORT_SYM);\n + importToken = tokenStream.token();\n + this._readWhitespace();\n +\n + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);\n +\n + //grab the URI value\n + uri = tokenStream.token().value.replace(/(?:url\\()?["\']([^"\']+)["\']\\)?/, "$1");\n +\n + this._readWhitespace();\n +\n + mediaList = this._media_query_list();\n +\n + //must end with a semicolon\n + tokenStream.mustMatch(Tokens.SEMICOLON);\n + this._readWhitespace();\n +\n + if (emit !== false){\n + this.fire({\n + type: "import",\n + uri: uri,\n + media: mediaList,\n + line: importToken.startLine,\n + col: importToken.startCol\n + });\n + }\n +\n + },\n +\n + _namespace: function(emit){\n + /*\n + * namespace\n + * : NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* \';\' S*\n + */\n +\n + var tokenStream = this._tokenStream,\n + line,\n + col,\n + prefix,\n + uri;\n +\n + //read import symbol\n + tokenStream.mustMatch(Tokens.NAMESPACE_SYM);\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol;\n + this._readWhitespace();\n +\n + //it\'s a namespace prefix - no _namespace_prefix() method because it\'s just an IDENT\n + if (tokenStream.match(Tokens.IDENT)){\n + prefix = tokenStream.token().value;\n + this._readWhitespace();\n + }\n +\n + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);\n + /*if (!tokenStream.match(Tokens.STRING)){\n + tokenStream.mustMatch(Tokens.URI);\n + }*/\n +\n + //grab the URI value\n + uri = tokenStream.token().value.replace(/(?:url\\()?["\']([^"\']+)["\']\\)?/, "$1");\n +\n + this._readWhitespace();\n +\n + //must end with a semicolon\n + tokenStream.mustMatch(Tokens.SEMICOLON);\n + this._readWhitespace();\n +\n + if (emit !== false){\n + this.fire({\n + type: "namespace",\n + prefix: prefix,\n + uri: uri,\n + line: line,\n + col: col\n + });\n + }\n +\n + },\n +\n + _media: function(){\n + /*\n + * media\n + * : MEDIA_SYM S* media_query_list S* \'{\' S* ruleset* \'}\' S*\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + line,\n + col,\n + mediaList;// = [];\n +\n + //look for @media\n + tokenStream.mustMatch(Tokens.MEDIA_SYM);\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol;\n +\n + this._readWhitespace();\n +\n + mediaList = this._media_query_list();\n +\n + tokenStream.mustMatch(Tokens.LBRACE);\n + this._readWhitespace();\n +\n + this.fire({\n + type: "startmedia",\n + media: mediaList,\n + line: line,\n + col: col\n + });\n +\n + while(true) {\n + if (tokenStream.peek() == Tokens.PAGE_SYM){\n + this._page();\n + } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){\n + this._font_face();\n + } else if (!this._ruleset()){\n + break;\n + }\n + }\n +\n + tokenStream.mustMatch(Tokens.RBRACE);\n + this._readWhitespace();\n +\n + this.fire({\n + type: "endmedia",\n + media: mediaList,\n + line: line,\n + col: col\n + });\n + },\n +\n +\n + //CSS3 Media Queries\n + _media_query_list: function(){\n + /*\n + * media_query_list\n + * : S* [media_query [ \',\' S* media_query ]* ]?\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + mediaList = [];\n +\n +\n + this._readWhitespace();\n +\n + if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){\n + mediaList.push(this._media_query());\n + }\n +\n + while(tokenStream.match(Tokens.COMMA)){\n + this._readWhitespace();\n + mediaList.push(this._media_query());\n + }\n +\n + return mediaList;\n + },\n +\n + /*\n + * Note: "expression" in the grammar maps to the _media_expression\n + * method.\n +\n + */\n + _media_query: function(){\n + /*\n + * media_query\n + * : [ONLY | NOT]? S* media_type S* [ AND S* expression ]*\n + * | expression [ AND S* expression ]*\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + type = null,\n + ident = null,\n + token = null,\n + expressions = [];\n +\n + if (tokenStream.match(Tokens.IDENT)){\n + ident = tokenStream.token().value.toLowerCase();\n +\n + //since there\'s no custom tokens for these, need to manually check\n + if (ident != "only" && ident != "not"){\n + tokenStream.unget();\n + ident = null;\n + } else {\n + token = tokenStream.token();\n + }\n + }\n +\n + this._readWhitespace();\n +\n + if (tokenStream.peek() == Tokens.IDENT){\n + type = this._media_type();\n + if (token === null){\n + token = tokenStream.token();\n + }\n + } else if (tokenStream.peek() == Tokens.LPAREN){\n + if (token === null){\n + token = tokenStream.LT(1);\n + }\n + expressions.push(this._media_expression());\n + }\n +\n + if (type === null && expressions.length === 0){\n + return null;\n + } else {\n + this._readWhitespace();\n + while (tokenStream.match(Tokens.IDENT)){\n + if (tokenStream.token().value.toLowerCase() != "and"){\n + this._unexpectedToken(tokenStream.token());\n + }\n +\n + this._readWhitespace();\n + expressions.push(this._media_expression());\n + }\n + }\n +\n + return new MediaQuery(ident, type, expressions, token.startLine, token.startCol);\n + },\n +\n + //CSS3 Media Queries\n + _media_type: function(){\n + /*\n + * media_type\n + * : IDENT\n + * ;\n + */\n + return this._media_feature();\n + },\n +\n + /**\n + * Note: in CSS3 Media Queries, this is called "expression".\n + * Renamed here to avoid conflict with CSS3 Selectors\n + * definition of "expression". Also note that "expr" in the\n + * grammar now maps to "expression" from CSS3 selectors.\n + * @method _media_expression\n + * @private\n + */\n + _media_expression: function(){\n + /*\n + * expression\n + * : \'(\' S* media_feature S* [ \':\' S* expr ]? \')\' S*\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + feature = null,\n + token,\n + expression = null;\n +\n + tokenStream.mustMatch(Tokens.LPAREN);\n +\n + feature = this._media_feature();\n + this._readWhitespace();\n +\n + if (tokenStream.match(Tokens.COLON)){\n + this._readWhitespace();\n + token = tokenStream.LT(1);\n + expression = this._expression();\n + }\n +\n + tokenStream.mustMatch(Tokens.RPAREN);\n + this._readWhitespace();\n +\n + return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null));\n + },\n +\n + //CSS3 Media Queries\n + _media_feature: function(){\n + /*\n + * media_feature\n + * : IDENT\n + * ;\n + */\n + var tokenStream = this._tokenStream;\n +\n + tokenStream.mustMatch(Tokens.IDENT);\n +\n + return SyntaxUnit.fromToken(tokenStream.token());\n + },\n +\n + //CSS3 Paged Media\n + _page: function(){\n + /*\n + * page:\n + * PAGE_SYM S* IDENT? pseudo_page? S*\n + * \'{\' S* [ declaration | margin ]? [ \';\' S* [ declaration | margin ]? ]* \'}\' S*\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + line,\n + col,\n + identifier = null,\n + pseudoPage = null;\n +\n + //look for @page\n + tokenStream.mustMatch(Tokens.PAGE_SYM);\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol;\n +\n + this._readWhitespace();\n +\n + if (tokenStream.match(Tokens.IDENT)){\n + identifier = tokenStream.token().value;\n +\n + //The value \'auto\' may not be used as a page name and MUST be treated as a syntax error.\n + if (identifier.toLowerCase() === "auto"){\n + this._unexpectedToken(tokenStream.token());\n + }\n + }\n +\n + //see if there\'s a colon upcoming\n + if (tokenStream.peek() == Tokens.COLON){\n + pseudoPage = this._pseudo_page();\n + }\n +\n + this._readWhitespace();\n +\n + this.fire({\n + type: "startpage",\n + id: identifier,\n + pseudo: pseudoPage,\n + line: line,\n + col: col\n + });\n +\n + this._readDeclarations(true, true);\n +\n + this.fire({\n + type: "endpage",\n + id: identifier,\n + pseudo: pseudoPage,\n + line: line,\n + col: col\n + });\n +\n + },\n +\n + //CSS3 Paged Media\n + _margin: function(){\n + /*\n + * margin :\n + * margin_sym S* \'{\' declaration [ \';\' S* declaration? ]* \'}\' S*\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + line,\n + col,\n + marginSym = this._margin_sym();\n +\n + if (marginSym){\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol;\n +\n + this.fire({\n + type: "startpagemargin",\n + margin: marginSym,\n + line: line,\n + col: col\n + });\n +\n + this._readDeclarations(true);\n +\n + this.fire({\n + type: "endpagemargin",\n + margin: marginSym,\n + line: line,\n + col: col\n + });\n + return true;\n + } else {\n + return false;\n + }\n + },\n +\n + //CSS3 Paged Media\n + _margin_sym: function(){\n +\n + /*\n + * margin_sym :\n + * TOPLEFTCORNER_SYM |\n + * TOPLEFT_SYM |\n + * TOPCENTER_SYM |\n + * TOPRIGHT_SYM |\n + * TOPRIGHTCORNER_SYM |\n + * BOTTOMLEFTCORNER_SYM |\n + * BOTTOMLEFT_SYM |\n + * BOTTOMCENTER_SYM |\n + * BOTTOMRIGHT_SYM |\n + * BOTTOMRIGHTCORNER_SYM |\n + * LEFTTOP_SYM |\n + * LEFTMIDDLE_SYM |\n + * LEFTBOTTOM_SYM |\n + * RIGHTTOP_SYM |\n + * RIGHTMIDDLE_SYM |\n + * RIGHTBOTTOM_SYM\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream;\n +\n + if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM,\n + Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM,\n + Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM,\n + Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM,\n + Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM,\n + Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM,\n + Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM]))\n + {\n + return SyntaxUnit.fromToken(tokenStream.token());\n + } else {\n + return null;\n + }\n +\n + },\n +\n + _pseudo_page: function(){\n + /*\n + * pseudo_page\n + * : \':\' IDENT\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream;\n +\n + tokenStream.mustMatch(Tokens.COLON);\n + tokenStream.mustMatch(Tokens.IDENT);\n +\n + //TODO: CSS3 Paged Media says only "left", "center", and "right" are allowed\n +\n + return tokenStream.token().value;\n + },\n +\n + _font_face: function(){\n + /*\n + * font_face\n + * : FONT_FACE_SYM S*\n + * \'{\' S* declaration [ \';\' S* declaration ]* \'}\' S*\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + line,\n + col;\n +\n + //look for @page\n + tokenStream.mustMatch(Tokens.FONT_FACE_SYM);\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol;\n +\n + this._readWhitespace();\n +\n + this.fire({\n + type: "startfontface",\n + line: line,\n + col: col\n + });\n +\n + this._readDeclarations(true);\n +\n + this.fire({\n + type: "endfontface",\n + line: line,\n + col: col\n + });\n + },\n +\n + _viewport: function(){\n + /*\n + * viewport\n + * : VIEWPORT_SYM S*\n + * \'{\' S* declaration? [ \';\' S* declaration? ]* \'}\' S*\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + line,\n + col;\n +\n + tokenStream.mustMatch(Tokens.VIEWPORT_SYM);\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol;\n +\n + this._readWhitespace();\n +\n + this.fire({\n + type: "startviewport",\n + line: line,\n + col: col\n + });\n +\n + this._readDeclarations(true);\n +\n + this.fire({\n + type: "endviewport",\n + line: line,\n + col: col\n + });\n +\n + },\n +\n + _operator: function(inFunction){\n +\n + /*\n + * operator (outside function)\n + * : \'/\' S* | \',\' S* | /( empty )/\n + * operator (inside function)\n + * : \'/\' S* | \'+\' S* | \'*\' S* | \'-\' S* /( empty )/\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + token = null;\n +\n + if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) ||\n + (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){\n + token = tokenStream.token();\n + this._readWhitespace();\n + }\n + return token ? PropertyValuePart.fromToken(token) : null;\n +\n + },\n +\n + _combinator: function(){\n +\n + /*\n + * combinator\n + * : PLUS S* | GREATER S* | TILDE S* | S+\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + value = null,\n + token;\n +\n + if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){\n + token = tokenStream.token();\n + value = new Combinator(token.value, token.startLine, token.startCol);\n + this._readWhitespace();\n + }\n +\n + return value;\n + },\n +\n + _unary_operator: function(){\n +\n + /*\n + * unary_operator\n + * : \'-\' | \'+\'\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream;\n +\n + if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){\n + return tokenStream.token().value;\n + } else {\n + return null;\n + }\n + },\n +\n + _property: function(){\n +\n + /*\n + * property\n + * : IDENT S*\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + value = null,\n + hack = null,\n + tokenValue,\n + token,\n + line,\n + col;\n +\n + //check for star hack - throws error if not allowed\n + if (tokenStream.peek() == Tokens.STAR && this.options.starHack){\n + tokenStream.get();\n + token = tokenStream.token();\n + hack = token.value;\n + line = token.startLine;\n + col = token.startCol;\n + }\n +\n + if(tokenStream.match(Tokens.IDENT)){\n + token = tokenStream.token();\n + tokenValue = token.value;\n +\n + //check for underscore hack - no error if not allowed because it\'s valid CSS syntax\n + if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){\n + hack = "_";\n + tokenValue = tokenValue.substring(1);\n + }\n +\n + value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol));\n + this._readWhitespace();\n + }\n +\n + return value;\n + },\n +\n + //Augmented with CSS3 Selectors\n + _ruleset: function(){\n + /*\n + * ruleset\n + * : selectors_group\n + * \'{\' S* declaration? [ \';\' S* declaration? ]* \'}\' S*\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + tt,\n + selectors;\n +\n +\n + /*\n + * Error Recovery: If even a single selector fails to parse,\n + * then the entire ruleset should be thrown away.\n + */\n + try {\n + selectors = this._selectors_group();\n + } catch (ex){\n + if (ex instanceof SyntaxError && !this.options.strict){\n +\n + //fire error event\n + this.fire({\n + type: "error",\n + error: ex,\n + message: ex.message,\n + line: ex.line,\n + col: ex.col\n + });\n +\n + //skip over everything until closing brace\n + tt = tokenStream.advance([Tokens.RBRACE]);\n + if (tt == Tokens.RBRACE){\n + //if there\'s a right brace, the rule is finished so don\'t do anything\n + } else {\n + //otherwise, rethrow the error because it wasn\'t handled properly\n + throw ex;\n + }\n +\n + } else {\n + //not a syntax error, rethrow it\n + throw ex;\n + }\n +\n + //trigger parser to continue\n + return true;\n + }\n +\n + //if it got here, all selectors parsed\n + if (selectors){\n +\n + this.fire({\n + type: "startrule",\n + selectors: selectors,\n + line: selectors[0].line,\n + col: selectors[0].col\n + });\n +\n + this._readDeclarations(true);\n +\n + this.fire({\n + type: "endrule",\n + selectors: selectors,\n + line: selectors[0].line,\n + col: selectors[0].col\n + });\n +\n + }\n +\n + return selectors;\n +\n + },\n +\n + //CSS3 Selectors\n + _selectors_group: function(){\n +\n + /*\n + * selectors_group\n + * : selector [ COMMA S* selector ]*\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + selectors = [],\n + selector;\n +\n + selector = this._selector();\n + if (selector !== null){\n +\n + selectors.push(selector);\n + while(tokenStream.match(Tokens.COMMA)){\n + this._readWhitespace();\n + selector = this._selector();\n + if (selector !== null){\n + selectors.push(selector);\n + } else {\n + this._unexpectedToken(tokenStream.LT(1));\n + }\n + }\n + }\n +\n + return selectors.length ? selectors : null;\n + },\n +\n + //CSS3 Selectors\n + _selector: function(){\n + /*\n + * selector\n + * : simple_selector_sequence [ combinator simple_selector_sequence ]*\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + selector = [],\n + nextSelector = null,\n + combinator = null,\n + ws = null;\n +\n + //if there\'s no simple selector, then there\'s no selector\n + nextSelector = this._simple_selector_sequence();\n + if (nextSelector === null){\n + return null;\n + }\n +\n + selector.push(nextSelector);\n +\n + do {\n +\n + //look for a combinator\n + combinator = this._combinator();\n +\n + if (combinator !== null){\n + selector.push(combinator);\n + nextSelector = this._simple_selector_sequence();\n +\n + //there must be a next selector\n + if (nextSelector === null){\n + this._unexpectedToken(tokenStream.LT(1));\n + } else {\n +\n + //nextSelector is an instance of SelectorPart\n + selector.push(nextSelector);\n + }\n + } else {\n +\n + //if there\'s not whitespace, we\'re done\n + if (this._readWhitespace()){\n +\n + //add whitespace separator\n + ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol);\n +\n + //combinator is not required\n + combinator = this._combinator();\n +\n + //selector is required if there\'s a combinator\n + nextSelector = this._simple_selector_sequence();\n + if (nextSelector === null){\n + if (combinator !== null){\n + this._unexpectedToken(tokenStream.LT(1));\n + }\n + } else {\n +\n + if (combinator !== null){\n + selector.push(combinator);\n + } else {\n + selector.push(ws);\n + }\n +\n + selector.push(nextSelector);\n + }\n + } else {\n + break;\n + }\n +\n + }\n + } while(true);\n +\n + return new Selector(selector, selector[0].line, selector[0].col);\n + },\n +\n + //CSS3 Selectors\n + _simple_selector_sequence: function(){\n + /*\n + * simple_selector_sequence\n + * : [ type_selector | universal ]\n + * [ HASH | class | attrib | pseudo | negation ]*\n + * | [ HASH | class | attrib | pseudo | negation ]+\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n +\n + //parts of a simple selector\n + elementName = null,\n + modifiers = [],\n +\n + //complete selector text\n + selectorText= "",\n +\n + //the different parts after the element name to search for\n + components = [\n + //HASH\n + function(){\n + return tokenStream.match(Tokens.HASH) ?\n + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :\n + null;\n + },\n + this._class,\n + this._attrib,\n + this._pseudo,\n + this._negation\n + ],\n + i = 0,\n + len = components.length,\n + component = null,\n + found = false,\n + line,\n + col;\n +\n +\n + //get starting line and column for the selector\n + line = tokenStream.LT(1).startLine;\n + col = tokenStream.LT(1).startCol;\n +\n + elementName = this._type_selector();\n + if (!elementName){\n + elementName = this._universal();\n + }\n +\n + if (elementName !== null){\n + selectorText += elementName;\n + }\n +\n + while(true){\n +\n + //whitespace means we\'re done\n + if (tokenStream.peek() === Tokens.S){\n + break;\n + }\n +\n + //check for each component\n + while(i < len && component === null){\n + component = components[i++].call(this);\n + }\n +\n + if (component === null){\n +\n + //we don\'t have a selector\n + if (selectorText === ""){\n + return null;\n + } else {\n + break;\n + }\n + } else {\n + i = 0;\n + modifiers.push(component);\n + selectorText += component.toString();\n + component = null;\n + }\n + }\n +\n +\n + return selectorText !== "" ?\n + new SelectorPart(elementName, modifiers, selectorText, line, col) :\n + null;\n + },\n +\n + //CSS3 Selectors\n + _type_selector: function(){\n + /*\n + * type_selector\n + * : [ namespace_prefix ]? element_name\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + ns = this._namespace_prefix(),\n + elementName = this._element_name();\n +\n + if (!elementName){\n + /*\n + * Need to back out the namespace that was read due to both\n + * type_selector and universal reading namespace_prefix\n + * first. Kind of hacky, but only way I can figure out\n + * right now how to not change the grammar.\n + */\n + if (ns){\n + tokenStream.unget();\n + if (ns.length > 1){\n + tokenStream.unget();\n + }\n + }\n +\n + return null;\n + } else {\n + if (ns){\n + elementName.text = ns + elementName.text;\n + elementName.col -= ns.length;\n + }\n + return elementName;\n + }\n + },\n +\n + //CSS3 Selectors\n + _class: function(){\n + /*\n + * class\n + * : \'.\' IDENT\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + token;\n +\n + if (tokenStream.match(Tokens.DOT)){\n + tokenStream.mustMatch(Tokens.IDENT);\n + token = tokenStream.token();\n + return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1);\n + } else {\n + return null;\n + }\n +\n + },\n +\n + //CSS3 Selectors\n + _element_name: function(){\n + /*\n + * element_name\n + * : IDENT\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + token;\n +\n + if (tokenStream.match(Tokens.IDENT)){\n + token = tokenStream.token();\n + return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol);\n +\n + } else {\n + return null;\n + }\n + },\n +\n + //CSS3 Selectors\n + _namespace_prefix: function(){\n + /*\n + * namespace_prefix\n + * : [ IDENT | \'*\' ]? \'|\'\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + value = "";\n +\n + //verify that this is a namespace prefix\n + if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){\n +\n + if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){\n + value += tokenStream.token().value;\n + }\n +\n + tokenStream.mustMatch(Tokens.PIPE);\n + value += "|";\n +\n + }\n +\n + return value.length ? value : null;\n + },\n +\n + //CSS3 Selectors\n + _universal: function(){\n + /*\n + * universal\n + * : [ namespace_prefix ]? \'*\'\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + value = "",\n + ns;\n +\n + ns = this._namespace_prefix();\n + if(ns){\n + value += ns;\n + }\n +\n + if(tokenStream.match(Tokens.STAR)){\n + value += "*";\n + }\n +\n + return value.length ? value : null;\n +\n + },\n +\n + //CSS3 Selectors\n + _attrib: function(){\n + /*\n + * attrib\n + * : \'[\' S* [ namespace_prefix ]? IDENT S*\n + * [ [ PREFIXMATCH |\n + * SUFFIXMATCH |\n + * SUBSTRINGMATCH |\n + * \'=\' |\n + * INCLUDES |\n + * DASHMATCH ] S* [ IDENT | STRING ] S*\n + * ]? \']\'\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + value = null,\n + ns,\n + token;\n +\n + if (tokenStream.match(Tokens.LBRACKET)){\n + token = tokenStream.token();\n + value = token.value;\n + value += this._readWhitespace();\n +\n + ns = this._namespace_prefix();\n +\n + if (ns){\n + value += ns;\n + }\n +\n + tokenStream.mustMatch(Tokens.IDENT);\n + value += tokenStream.token().value;\n + value += this._readWhitespace();\n +\n + if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH,\n + Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){\n +\n + value += tokenStream.token().value;\n + value += this._readWhitespace();\n +\n + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);\n + value += tokenStream.token().value;\n + value += this._readWhitespace();\n + }\n +\n + tokenStream.mustMatch(Tokens.RBRACKET);\n +\n + return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol);\n + } else {\n + return null;\n + }\n + },\n +\n + //CSS3 Selectors\n + _pseudo: function(){\n +\n + /*\n + * pseudo\n + * : \':\' \':\'? [ IDENT | functional_pseudo ]\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + pseudo = null,\n + colons = ":",\n + line,\n + col;\n +\n + if (tokenStream.match(Tokens.COLON)){\n +\n + if (tokenStream.match(Tokens.COLON)){\n + colons += ":";\n + }\n +\n + if (tokenStream.match(Tokens.IDENT)){\n + pseudo = tokenStream.token().value;\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol - colons.length;\n + } else if (tokenStream.peek() == Tokens.FUNCTION){\n + line = tokenStream.LT(1).startLine;\n + col = tokenStream.LT(1).startCol - colons.length;\n + pseudo = this._functional_pseudo();\n + }\n +\n + if (pseudo){\n + pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col);\n + }\n + }\n +\n + return pseudo;\n + },\n +\n + //CSS3 Selectors\n + _functional_pseudo: function(){\n + /*\n + * functional_pseudo\n + * : FUNCTION S* expression \')\'\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + value = null;\n +\n + if(tokenStream.match(Tokens.FUNCTION)){\n + value = tokenStream.token().value;\n + value += this._readWhitespace();\n + value += this._expression();\n + tokenStream.mustMatch(Tokens.RPAREN);\n + value += ")";\n + }\n +\n + return value;\n + },\n +\n + //CSS3 Selectors\n + _expression: function(){\n + /*\n + * expression\n + * : [ [ PLUS | \'-\' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + value = "";\n +\n + while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION,\n + Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH,\n + Tokens.FREQ, Tokens.ANGLE, Tokens.TIME,\n + Tokens.RESOLUTION, Tokens.SLASH])){\n +\n + value += tokenStream.token().value;\n + value += this._readWhitespace();\n + }\n +\n + return value.length ? value : null;\n +\n + },\n +\n + //CSS3 Selectors\n + _negation: function(){\n + /*\n + * negation\n + * : NOT S* negation_arg S* \')\'\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + line,\n + col,\n + value = "",\n + arg,\n + subpart = null;\n +\n + if (tokenStream.match(Tokens.NOT)){\n + value = tokenStream.token().value;\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol;\n + value += this._readWhitespace();\n + arg = this._negation_arg();\n + value += arg;\n + value += this._readWhitespace();\n + tokenStream.match(Tokens.RPAREN);\n + value += tokenStream.token().value;\n +\n + subpart = new SelectorSubPart(value, "not", line, col);\n + subpart.args.push(arg);\n + }\n +\n + return subpart;\n + },\n +\n + //CSS3 Selectors\n + _negation_arg: function(){\n + /*\n + * negation_arg\n + * : type_selector | universal | HASH | class | attrib | pseudo\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + args = [\n + this._type_selector,\n + this._universal,\n + function(){\n + return tokenStream.match(Tokens.HASH) ?\n + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :\n + null;\n + },\n + this._class,\n + this._attrib,\n + this._pseudo\n + ],\n + arg = null,\n + i = 0,\n + len = args.length,\n + elementName,\n + line,\n + col,\n + part;\n +\n + line = tokenStream.LT(1).startLine;\n + col = tokenStream.LT(1).startCol;\n +\n + while(i < len && arg === null){\n +\n + arg = args[i].call(this);\n + i++;\n + }\n +\n + //must be a negation arg\n + if (arg === null){\n + this._unexpectedToken(tokenStream.LT(1));\n + }\n +\n + //it\'s an element name\n + if (arg.type == "elementName"){\n + part = new SelectorPart(arg, [], arg.toString(), line, col);\n + } else {\n + part = new SelectorPart(null, [arg], arg.toString(), line, col);\n + }\n +\n + return part;\n + },\n +\n + _declaration: function(){\n +\n + /*\n + * declaration\n + * : property \':\' S* expr prio?\n + * | /( empty )/\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + property = null,\n + expr = null,\n + prio = null,\n + error = null,\n + invalid = null,\n + propertyName= "";\n +\n + property = this._property();\n + if (property !== null){\n +\n + tokenStream.mustMatch(Tokens.COLON);\n + this._readWhitespace();\n +\n + expr = this._expr();\n +\n + //if there\'s no parts for the value, it\'s an error\n + if (!expr || expr.length === 0){\n + this._unexpectedToken(tokenStream.LT(1));\n + }\n +\n + prio = this._prio();\n +\n + /*\n + * If hacks should be allowed, then only check the root\n + * property. If hacks should not be allowed, treat\n + * _property or *property as invalid properties.\n + */\n + propertyName = property.toString();\n + if (this.options.starHack && property.hack == "*" ||\n + this.options.underscoreHack && property.hack == "_") {\n +\n + propertyName = property.text;\n + }\n +\n + try {\n + this._validateProperty(propertyName, expr);\n + } catch (ex) {\n + invalid = ex;\n + }\n +\n + this.fire({\n + type: "property",\n + property: property,\n + value: expr,\n + important: prio,\n + line: property.line,\n + col: property.col,\n + invalid: invalid\n + });\n +\n + return true;\n + } else {\n + return false;\n + }\n + },\n +\n + _prio: function(){\n + /*\n + * prio\n + * : IMPORTANT_SYM S*\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + result = tokenStream.match(Tokens.IMPORTANT_SYM);\n +\n + this._readWhitespace();\n + return result;\n + },\n +\n + _expr: function(inFunction){\n + /*\n + * expr\n + * : term [ operator term ]*\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + values = [],\n + //valueParts = [],\n + value = null,\n + operator = null;\n +\n + value = this._term();\n + if (value !== null){\n +\n + values.push(value);\n +\n + do {\n + operator = this._operator(inFunction);\n +\n + //if there\'s an operator, keep building up the value parts\n + if (operator){\n + values.push(operator);\n + } /*else {\n + //if there\'s not an operator, you have a full value\n + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));\n + valueParts = [];\n + }*/\n +\n + value = this._term();\n +\n + if (value === null){\n + break;\n + } else {\n + values.push(value);\n + }\n + } while(true);\n + }\n +\n + //cleanup\n + /*if (valueParts.length){\n + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));\n + }*/\n +\n + return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null;\n + },\n +\n + _term: function(){\n +\n + /*\n + * term\n + * : unary_operator?\n + * [ NUMBER S* | PERCENTAGE S* | LENGTH S* | ANGLE S* |\n + * TIME S* | FREQ S* | function | ie_function ]\n + * | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + unary = null,\n + value = null,\n + token,\n + line,\n + col;\n +\n + //returns the operator or null\n + unary = this._unary_operator();\n + if (unary !== null){\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol;\n + }\n +\n + //exception for IE filters\n + if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){\n +\n + value = this._ie_function();\n + if (unary === null){\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol;\n + }\n +\n + //see if there\'s a simple match\n + } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH,\n + Tokens.ANGLE, Tokens.TIME,\n + Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){\n +\n + value = tokenStream.token().value;\n + if (unary === null){\n + line = tokenStream.token().startLine;\n + col = tokenStream.token().startCol;\n + }\n + this._readWhitespace();\n + } else {\n +\n + //see if it\'s a color\n + token = this._hexcolor();\n + if (token === null){\n +\n + //if there\'s no unary, get the start of the next token for line/col info\n + if (unary === null){\n + line = tokenStream.LT(1).startLine;\n + col = tokenStream.LT(1).startCol;\n + }\n +\n + //has to be a function\n + if (value === null){\n +\n + /*\n + * This checks for alpha(opacity=0) style of IE\n + * functions. IE_FUNCTION only presents progid: style.\n + */\n + if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){\n + value = this._ie_function();\n + } else {\n + value = this._function();\n + }\n + }\n +\n + /*if (value === null){\n + return null;\n + //throw new Error("Expected identifier at line " + tokenStream.token().startLine + ", character " + tokenStream.token().startCol + ".");\n + }*/\n +\n + } else {\n + value = token.value;\n + if (unary === null){\n + line = token.startLine;\n + col = token.startCol;\n + }\n + }\n +\n + }\n +\n + return value !== null ?\n + new PropertyValuePart(unary !== null ? unary + value : value, line, col) :\n + null;\n +\n + },\n +\n + _function: function(){\n +\n + /*\n + * function\n + * : FUNCTION S* expr \')\' S*\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + functionText = null,\n + expr = null,\n + lt;\n +\n + if (tokenStream.match(Tokens.FUNCTION)){\n + functionText = tokenStream.token().value;\n + this._readWhitespace();\n + expr = this._expr(true);\n + functionText += expr;\n +\n + //START: Horrible hack in case it\'s an IE filter\n + if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){\n + do {\n +\n + if (this._readWhitespace()){\n + functionText += tokenStream.token().value;\n + }\n +\n + //might be second time in the loop\n + if (tokenStream.LA(0) == Tokens.COMMA){\n + functionText += tokenStream.token().value;\n + }\n +\n + tokenStream.match(Tokens.IDENT);\n + functionText += tokenStream.token().value;\n +\n + tokenStream.match(Tokens.EQUALS);\n + functionText += tokenStream.token().value;\n +\n + //functionText += this._term();\n + lt = tokenStream.peek();\n + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){\n + tokenStream.get();\n + functionText += tokenStream.token().value;\n + lt = tokenStream.peek();\n + }\n + } while(tokenStream.match([Tokens.COMMA, Tokens.S]));\n + }\n +\n + //END: Horrible Hack\n +\n + tokenStream.match(Tokens.RPAREN);\n + functionText += ")";\n + this._readWhitespace();\n + }\n +\n + return functionText;\n + },\n +\n + _ie_function: function(){\n +\n + /* (My own extension)\n + * ie_function\n + * : IE_FUNCTION S* IDENT \'=\' term [S* \',\'? IDENT \'=\' term]+ \')\' S*\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + functionText = null,\n + expr = null,\n + lt;\n +\n + //IE function can begin like a regular function, too\n + if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){\n + functionText = tokenStream.token().value;\n +\n + do {\n +\n + if (this._readWhitespace()){\n + functionText += tokenStream.token().value;\n + }\n +\n + //might be second time in the loop\n + if (tokenStream.LA(0) == Tokens.COMMA){\n + functionText += tokenStream.token().value;\n + }\n +\n + tokenStream.match(Tokens.IDENT);\n + functionText += tokenStream.token().value;\n +\n + tokenStream.match(Tokens.EQUALS);\n + functionText += tokenStream.token().value;\n +\n + //functionText += this._term();\n + lt = tokenStream.peek();\n + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){\n + tokenStream.get();\n + functionText += tokenStream.token().value;\n + lt = tokenStream.peek();\n + }\n + } while(tokenStream.match([Tokens.COMMA, Tokens.S]));\n +\n + tokenStream.match(Tokens.RPAREN);\n + functionText += ")";\n + this._readWhitespace();\n + }\n +\n + return functionText;\n + },\n +\n + _hexcolor: function(){\n + /*\n + * There is a constraint on the color that it must\n + * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])\n + * after the "#"; e.g., "#000" is OK, but "#abcd" is not.\n + *\n + * hexcolor\n + * : HASH S*\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + token = null,\n + color;\n +\n + if(tokenStream.match(Tokens.HASH)){\n +\n + //need to do some validation here\n +\n + token = tokenStream.token();\n + color = token.value;\n + if (!/#[a-f0-9]{3,6}/i.test(color)){\n + throw new SyntaxError("Expected a hex color but found \'" + color + "\' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);\n + }\n + this._readWhitespace();\n + }\n +\n + return token;\n + },\n +\n + //-----------------------------------------------------------------\n + // Animations methods\n + //-----------------------------------------------------------------\n +\n + _keyframes: function(){\n +\n + /*\n + * keyframes:\n + * : KEYFRAMES_SYM S* keyframe_name S* \'{\' S* keyframe_rule* \'}\' {\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + token,\n + tt,\n + name,\n + prefix = "";\n +\n + tokenStream.mustMatch(Tokens.KEYFRAMES_SYM);\n + token = tokenStream.token();\n + if (/^@\\-([^\\-]+)\\-/.test(token.value)) {\n + prefix = RegExp.$1;\n + }\n +\n + this._readWhitespace();\n + name = this._keyframe_name();\n +\n + this._readWhitespace();\n + tokenStream.mustMatch(Tokens.LBRACE);\n +\n + this.fire({\n + type: "startkeyframes",\n + name: name,\n + prefix: prefix,\n + line: token.startLine,\n + col: token.startCol\n + });\n +\n + this._readWhitespace();\n + tt = tokenStream.peek();\n +\n + //check for key\n + while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) {\n + this._keyframe_rule();\n + this._readWhitespace();\n + tt = tokenStream.peek();\n + }\n +\n + this.fire({\n + type: "endkeyframes",\n + name: name,\n + prefix: prefix,\n + line: token.startLine,\n + col: token.startCol\n + });\n +\n + this._readWhitespace();\n + tokenStream.mustMatch(Tokens.RBRACE);\n +\n + },\n +\n + _keyframe_name: function(){\n +\n + /*\n + * keyframe_name:\n + * : IDENT\n + * | STRING\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + token;\n +\n + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);\n + return SyntaxUnit.fromToken(tokenStream.token());\n + },\n +\n + _keyframe_rule: function(){\n +\n + /*\n + * keyframe_rule:\n + * : key_list S*\n + * \'{\' S* declaration [ \';\' S* declaration ]* \'}\' S*\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + token,\n + keyList = this._key_list();\n +\n + this.fire({\n + type: "startkeyframerule",\n + keys: keyList,\n + line: keyList[0].line,\n + col: keyList[0].col\n + });\n +\n + this._readDeclarations(true);\n +\n + this.fire({\n + type: "endkeyframerule",\n + keys: keyList,\n + line: keyList[0].line,\n + col: keyList[0].col\n + });\n +\n + },\n +\n + _key_list: function(){\n +\n + /*\n + * key_list:\n + * : key [ S* \',\' S* key]*\n + * ;\n + */\n + var tokenStream = this._tokenStream,\n + token,\n + key,\n + keyList = [];\n +\n + //must be least one key\n + keyList.push(this._key());\n +\n + this._readWhitespace();\n +\n + while(tokenStream.match(Tokens.COMMA)){\n + this._readWhitespace();\n + keyList.push(this._key());\n + this._readWhitespace();\n + }\n +\n + return keyList;\n + },\n +\n + _key: function(){\n + /*\n + * There is a restriction that IDENT can be only "from" or "to".\n + *\n + * key\n + * : PERCENTAGE\n + * | IDENT\n + * ;\n + */\n +\n + var tokenStream = this._tokenStream,\n + token;\n +\n + if (tokenStream.match(Tokens.PERCENTAGE)){\n + return SyntaxUnit.fromToken(tokenStream.token());\n + } else if (tokenStream.match(Tokens.IDENT)){\n + token = tokenStream.token();\n +\n + if (/from|to/i.test(token.value)){\n + return SyntaxUnit.fromToken(token);\n + }\n +\n + tokenStream.unget();\n + }\n +\n + //if it gets here, there wasn\'t a valid token, so time to explode\n + this._unexpectedToken(tokenStream.LT(1));\n + },\n +\n + //-----------------------------------------------------------------\n + // Helper methods\n + //-----------------------------------------------------------------\n +\n + /**\n + * Not part of CSS grammar, but useful for skipping over\n + * combination of white space and HTML-style comments.\n + * @return {void}\n + * @method _skipCruft\n + * @private\n + */\n + _skipCruft: function(){\n + while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){\n + //noop\n + }\n + },\n +\n + /**\n + * Not part of CSS grammar, but this pattern occurs frequently\n + * in the official CSS grammar. Split out here to eliminate\n + * duplicate code.\n + * @param {Boolean} checkStart Indicates if the rule should check\n + * for the left brace at the beginning.\n + * @param {Boolean} readMargins Indicates if the rule should check\n + * for margin patterns.\n + * @return {void}\n + * @method _readDeclarations\n + * @private\n + */\n + _readDeclarations: function(checkStart, readMargins){\n + /*\n + * Reads the pattern\n + * S* \'{\' S* declaration [ \';\' S* declaration ]* \'}\' S*\n + * or\n + * S* \'{\' S* [ declaration | margin ]? [ \';\' S* [ declaration | margin ]? ]* \'}\' S*\n + * Note that this is how it is described in CSS3 Paged Media, but is actually incorrect.\n + * A semicolon is only necessary following a declaration is there\'s another declaration\n + * or margin afterwards.\n + */\n + var tokenStream = this._tokenStream,\n + tt;\n +\n +\n + this._readWhitespace();\n +\n + if (checkStart){\n + tokenStream.mustMatch(Tokens.LBRACE);\n + }\n +\n + this._readWhitespace();\n +\n + try {\n +\n + while(true){\n +\n + if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){\n + + +]]></string> </value> + </item> + <item> + <key> <string>next</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> + </value> + </item> + </dictionary> + </pickle> + </record> + <record id="3" aka="AAAAAAAAAAM="> + <pickle> + <global name="Pdata" module="OFS.Image"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>data</string> </key> + <value> <string encoding="cdata"><![CDATA[ + + //noop\n + } else if (this._declaration()){\n + if (!tokenStream.match(Tokens.SEMICOLON)){\n + break;\n + }\n + } else {\n + break;\n + }\n +\n + //if ((!this._margin() && !this._declaration()) || !tokenStream.match(Tokens.SEMICOLON)){\n + // break;\n + //}\n + this._readWhitespace();\n + }\n +\n + tokenStream.mustMatch(Tokens.RBRACE);\n + this._readWhitespace();\n +\n + } catch (ex) {\n + if (ex instanceof SyntaxError && !this.options.strict){\n +\n + //fire error event\n + this.fire({\n + type: "error",\n + error: ex,\n + message: ex.message,\n + line: ex.line,\n + col: ex.col\n + });\n +\n + //see if there\'s another declaration\n + tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]);\n + if (tt == Tokens.SEMICOLON){\n + //if there\'s a semicolon, then there might be another declaration\n + this._readDeclarations(false, readMargins);\n + } else if (tt != Tokens.RBRACE){\n + //if there\'s a right brace, the rule is finished so don\'t do anything\n + //otherwise, rethrow the error because it wasn\'t handled properly\n + throw ex;\n + }\n +\n + } else {\n + //not a syntax error, rethrow it\n + throw ex;\n + }\n + }\n +\n + },\n +\n + /**\n + * In some cases, you can end up with two white space tokens in a\n + * row. Instead of making a change in every function that looks for\n + * white space, this function is used to match as much white space\n + * as necessary.\n + * @method _readWhitespace\n + * @return {String} The white space if found, empty string if not.\n + * @private\n + */\n + _readWhitespace: function(){\n +\n + var tokenStream = this._tokenStream,\n + ws = "";\n +\n + while(tokenStream.match(Tokens.S)){\n + ws += tokenStream.token().value;\n + }\n +\n + return ws;\n + },\n +\n +\n + /**\n + * Throws an error when an unexpected token is found.\n + * @param {Object} token The token that was found.\n + * @method _unexpectedToken\n + * @return {void}\n + * @private\n + */\n + _unexpectedToken: function(token){\n + throw new SyntaxError("Unexpected token \'" + token.value + "\' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);\n + },\n +\n + /**\n + * Helper method used for parsing subparts of a style sheet.\n + * @return {void}\n + * @method _verifyEnd\n + * @private\n + */\n + _verifyEnd: function(){\n + if (this._tokenStream.LA(1) != Tokens.EOF){\n + this._unexpectedToken(this._tokenStream.LT(1));\n + }\n + },\n +\n + //-----------------------------------------------------------------\n + // Validation methods\n + //-----------------------------------------------------------------\n + _validateProperty: function(property, value){\n + Validation.validate(property, value);\n + },\n +\n + //-----------------------------------------------------------------\n + // Parsing methods\n + //-----------------------------------------------------------------\n +\n + parse: function(input){\n + this._tokenStream = new TokenStream(input, Tokens);\n + this._stylesheet();\n + },\n +\n + parseStyleSheet: function(input){\n + //just passthrough\n + return this.parse(input);\n + },\n +\n + parseMediaQuery: function(input){\n + this._tokenStream = new TokenStream(input, Tokens);\n + var result = this._media_query();\n +\n + //if there\'s anything more, then it\'s an invalid selector\n + this._verifyEnd();\n +\n + //otherwise return result\n + return result;\n + },\n +\n + /**\n + * Parses a property value (everything after the semicolon).\n + * @return {parserlib.css.PropertyValue} The property value.\n + * @throws parserlib.util.SyntaxError If an unexpected token is found.\n + * @method parserPropertyValue\n + */\n + parsePropertyValue: function(input){\n +\n + this._tokenStream = new TokenStream(input, Tokens);\n + this._readWhitespace();\n +\n + var result = this._expr();\n +\n + //okay to have a trailing white space\n + this._readWhitespace();\n +\n + //if there\'s anything more, then it\'s an invalid selector\n + this._verifyEnd();\n +\n + //otherwise return result\n + return result;\n + },\n +\n + /**\n + * Parses a complete CSS rule, including selectors and\n + * properties.\n + * @param {String} input The text to parser.\n + * @return {Boolean} True if the parse completed successfully, false if not.\n + * @method parseRule\n + */\n + parseRule: function(input){\n + this._tokenStream = new TokenStream(input, Tokens);\n +\n + //skip any leading white space\n + this._readWhitespace();\n +\n + var result = this._ruleset();\n +\n + //skip any trailing white space\n + this._readWhitespace();\n +\n + //if there\'s anything more, then it\'s an invalid selector\n + this._verifyEnd();\n +\n + //otherwise return result\n + return result;\n + },\n +\n + /**\n + * Parses a single CSS selector (no comma)\n + * @param {String} input The text to parse as a CSS selector.\n + * @return {Selector} An object representing the selector.\n + * @throws parserlib.util.SyntaxError If an unexpected token is found.\n + * @method parseSelector\n + */\n + parseSelector: function(input){\n +\n + this._tokenStream = new TokenStream(input, Tokens);\n +\n + //skip any leading white space\n + this._readWhitespace();\n +\n + var result = this._selector();\n +\n + //skip any trailing white space\n + this._readWhitespace();\n +\n + //if there\'s anything more, then it\'s an invalid selector\n + this._verifyEnd();\n +\n + //otherwise return result\n + return result;\n + },\n +\n + /**\n + * Parses an HTML style attribute: a set of CSS declarations\n + * separated by semicolons.\n + * @param {String} input The text to parse as a style attribute\n + * @return {void}\n + * @method parseStyleAttribute\n + */\n + parseStyleAttribute: function(input){\n + input += "}"; // for error recovery in _readDeclarations()\n + this._tokenStream = new TokenStream(input, Tokens);\n + this._readDeclarations();\n + }\n + };\n +\n + //copy over onto prototype\n + for (prop in additions){\n + if (additions.hasOwnProperty(prop)){\n + proto[prop] = additions[prop];\n + }\n + }\n +\n + return proto;\n +}();\n +\n +\n +/*\n +nth\n + : S* [ [\'-\'|\'+\']? INTEGER? {N} [ S* [\'-\'|\'+\'] S* INTEGER ]? |\n + [\'-\'|\'+\']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S*\n + ;\n +*/\n +\n +/*global Validation, ValidationTypes, ValidationError*/\n +var Properties = {\n +\n + //A\n + "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>",\n + "alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",\n + "animation" : 1,\n + "animation-delay" : { multi: "<time>", comma: true },\n + "animation-direction" : { multi: "normal | alternate", comma: true },\n + "animation-duration" : { multi: "<time>", comma: true },\n + "animation-iteration-count" : { multi: "<number> | infinite", comma: true },\n + "animation-name" : { multi: "none | <ident>", comma: true },\n + "animation-play-state" : { multi: "running | paused", comma: true },\n + "animation-timing-function" : 1,\n +\n + //vendor prefixed\n + "-moz-animation-delay" : { multi: "<time>", comma: true },\n + "-moz-animation-direction" : { multi: "normal | alternate", comma: true },\n + "-moz-animation-duration" : { multi: "<time>", comma: true },\n + "-moz-animation-iteration-count" : { multi: "<number> | infinite", comma: true },\n + "-moz-animation-name" : { multi: "none | <ident>", comma: true },\n + "-moz-animation-play-state" : { multi: "running | paused", comma: true },\n +\n + "-ms-animation-delay" : { multi: "<time>", comma: true },\n + "-ms-animation-direction" : { multi: "normal | alternate", comma: true },\n + "-ms-animation-duration" : { multi: "<time>", comma: true },\n + "-ms-animation-iteration-count" : { multi: "<number> | infinite", comma: true },\n + "-ms-animation-name" : { multi: "none | <ident>", comma: true },\n + "-ms-animation-play-state" : { multi: "running | paused", comma: true },\n +\n + "-webkit-animation-delay" : { multi: "<time>", comma: true },\n + "-webkit-animation-direction" : { multi: "normal | alternate", comma: true },\n + "-webkit-animation-duration" : { multi: "<time>", comma: true },\n + "-webkit-animation-iteration-count" : { multi: "<number> | infinite", comma: true },\n + "-webkit-animation-name" : { multi: "none | <ident>", comma: true },\n + "-webkit-animation-play-state" : { multi: "running | paused", comma: true },\n +\n + "-o-animation-delay" : { multi: "<time>", comma: true },\n + "-o-animation-direction" : { multi: "normal | alternate", comma: true },\n + "-o-animation-duration" : { multi: "<time>", comma: true },\n + "-o-animation-iteration-count" : { multi: "<number> | infinite", comma: true },\n + "-o-animation-name" : { multi: "none | <ident>", comma: true },\n + "-o-animation-play-state" : { multi: "running | paused", comma: true },\n +\n + "appearance" : "icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal | none | inherit",\n + "azimuth" : function (expression) {\n + var simple = "<angle> | leftwards | rightwards | inherit",\n + direction = "left-side | far-left | left | center-left | center | center-right | right | far-right | right-side",\n + behind = false,\n + valid = false,\n + part;\n +\n + if (!ValidationTypes.isAny(expression, simple)) {\n + if (ValidationTypes.isAny(expression, "behind")) {\n + behind = true;\n + valid = true;\n + }\n +\n + if (ValidationTypes.isAny(expression, direction)) {\n + valid = true;\n + if (!behind) {\n + ValidationTypes.isAny(expression, "behind");\n + }\n + }\n + }\n +\n + if (expression.hasNext()) {\n + part = expression.next();\n + if (valid) {\n + throw new ValidationError("Expected end of value but found \'" + part + "\'.", part.line, part.col);\n + } else {\n + throw new ValidationError("Expected (<\'azimuth\'>) but found \'" + part + "\'.", part.line, part.col);\n + }\n + }\n + },\n +\n + //B\n + "backface-visibility" : "visible | hidden",\n + "background" : 1,\n + "background-attachment" : { multi: "<attachment>", comma: true },\n + "background-clip" : { multi: "<box>", comma: true },\n + "background-color" : "<color> | inherit",\n + "background-image" : { multi: "<bg-image>", comma: true },\n + "background-origin" : { multi: "<box>", comma: true },\n + "background-position" : { multi: "<bg-position>", comma: true },\n + "background-repeat" : { multi: "<repeat-style>" },\n + "background-size" : { multi: "<bg-size>", comma: true },\n + "baseline-shift" : "baseline | sub | super | <percentage> | <length>",\n + "behavior" : 1,\n + "binding" : 1,\n + "bleed" : "<length>",\n + "bookmark-label" : "<content> | <attr> | <string>",\n + "bookmark-level" : "none | <integer>",\n + "bookmark-state" : "open | closed",\n + "bookmark-target" : "none | <uri> | <attr>",\n + "border" : "<border-width> || <border-style> || <color>",\n + "border-bottom" : "<border-width> || <border-style> || <color>",\n + "border-bottom-color" : "<color> | inherit",\n + "border-bottom-left-radius" : "<x-one-radius>",\n + "border-bottom-right-radius" : "<x-one-radius>",\n + "border-bottom-style" : "<border-style>",\n + "border-bottom-width" : "<border-width>",\n + "border-collapse" : "collapse | separate | inherit",\n + "border-color" : { multi: "<color> | inherit", max: 4 },\n + "border-image" : 1,\n + "border-image-outset" : { multi: "<length> | <number>", max: 4 },\n + "border-image-repeat" : { multi: "stretch | repeat | round", max: 2 },\n + "border-image-slice" : function(expression) {\n +\n + var valid = false,\n + numeric = "<number> | <percentage>",\n + fill = false,\n + count = 0,\n + max = 4,\n + part;\n +\n + if (ValidationTypes.isAny(expression, "fill")) {\n + fill = true;\n + valid = true;\n + }\n +\n + while (expression.hasNext() && count < max) {\n + valid = ValidationTypes.isAny(expression, numeric);\n + if (!valid) {\n + break;\n + }\n + count++;\n + }\n +\n +\n + if (!fill) {\n + ValidationTypes.isAny(expression, "fill");\n + } else {\n + valid = true;\n + }\n +\n + if (expression.hasNext()) {\n + part = expression.next();\n + if (valid) {\n + throw new ValidationError("Expected end of value but found \'" + part + "\'.", part.line, part.col);\n + } else {\n + throw new ValidationError("Expected ([<number> | <percentage>]{1,4} && fill?) but found \'" + part + "\'.", part.line, part.col);\n + }\n + }\n + },\n + "border-image-source" : "<image> | none",\n + "border-image-width" : { multi: "<length> | <percentage> | <number> | auto", max: 4 },\n + "border-left" : "<border-width> || <border-style> || <color>",\n + "border-left-color" : "<color> | inherit",\n + "border-left-style" : "<border-style>",\n + "border-left-width" : "<border-width>",\n + "border-radius" : function(expression) {\n +\n + var valid = false,\n + simple = "<length> | <percentage> | inherit",\n + slash = false,\n + fill = false,\n + count = 0,\n + max = 8,\n + part;\n +\n + while (expression.hasNext() && count < max) {\n + valid = ValidationTypes.isAny(expression, simple);\n + if (!valid) {\n +\n + if (expression.peek() == "/" && count > 0 && !slash) {\n + slash = true;\n + max = count + 5;\n + expression.next();\n + } else {\n + break;\n + }\n + }\n + count++;\n + }\n +\n + if (expression.hasNext()) {\n + part = expression.next();\n + if (valid) {\n + throw new ValidationError("Expected end of value but found \'" + part + "\'.", part.line, part.col);\n + } else {\n + throw new ValidationError("Expected (<\'border-radius\'>) but found \'" + part + "\'.", part.line, part.col);\n + }\n + }\n + },\n + "border-right" : "<border-width> || <border-style> || <color>",\n + "border-right-color" : "<color> | inherit",\n + "border-right-style" : "<border-style>",\n + "border-right-width" : "<border-width>",\n + "border-spacing" : { multi: "<length> | inherit", max: 2 },\n + "border-style" : { multi: "<border-style>", max: 4 },\n + "border-top" : "<border-width> || <border-style> || <color>",\n + "border-top-color" : "<color> | inherit",\n + "border-top-left-radius" : "<x-one-radius>",\n + "border-top-right-radius" : "<x-one-radius>",\n + "border-top-style" : "<border-style>",\n + "border-top-width" : "<border-width>",\n + "border-width" : { multi: "<border-width>", max: 4 },\n + "bottom" : "<margin-width> | inherit",\n + "box-align" : "start | end | center | baseline | stretch", //http://www.w3.org/TR/2009/WD-css3-flexbox-20090723/\n + "box-decoration-break" : "slice |clone",\n + "box-direction" : "normal | reverse | inherit",\n + "box-flex" : "<number>",\n + "box-flex-group" : "<integer>",\n + "box-lines" : "single | multiple",\n + "box-ordinal-group" : "<integer>",\n + "box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit",\n + "box-pack" : "start | end | center | justify",\n + "box-shadow" : function (expression) {\n + var result = false,\n + part;\n +\n + if (!ValidationTypes.isAny(expression, "none")) {\n + Validation.multiProperty("<shadow>", expression, true, Infinity);\n + } else {\n + if (expression.hasNext()) {\n + part = expression.next();\n + throw new ValidationError("Expected end of value but found \'" + part + "\'.", part.line, part.col);\n + }\n + }\n + },\n + "box-sizing" : "content-box | border-box | inherit",\n + "break-after" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",\n + "break-before" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",\n + "break-inside" : "auto | avoid | avoid-page | avoid-column",\n +\n + //C\n + "caption-side" : "top | bottom | inherit",\n + "clear" : "none | right | left | both | inherit",\n + "clip" : 1,\n + "color" : "<color> | inherit",\n + "color-profile" : 1,\n + "column-count" : "<integer> | auto", //http://www.w3.org/TR/css3-multicol/\n + "column-fill" : "auto | balance",\n + "column-gap" : "<length> | normal",\n + "column-rule" : "<border-width> || <border-style> || <color>",\n + "column-rule-color" : "<color>",\n + "column-rule-style" : "<border-style>",\n + "column-rule-width" : "<border-width>",\n + "column-span" : "none | all",\n + "column-width" : "<length> | auto",\n + "columns" : 1,\n + "content" : 1,\n + "counter-increment" : 1,\n + "counter-reset" : 1,\n + "crop" : "<shape> | auto",\n + "cue" : "cue-after | cue-before | inherit",\n + "cue-after" : 1,\n + "cue-before" : 1,\n + "cursor" : 1,\n +\n + //D\n + "direction" : "ltr | rtl | inherit",\n + "display" : "inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | box | inline-box | grid | inline-grid | none | inherit | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box",\n + "dominant-baseline" : 1,\n + "drop-initial-after-adjust" : "central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>",\n + "drop-initial-after-align" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",\n + "drop-initial-before-adjust" : "before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>",\n + "drop-initial-before-align" : "caps-height | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",\n + "drop-initial-size" : "auto | line | <length> | <percentage>",\n + "drop-initial-value" : "initial | <integer>",\n +\n + //E\n + "elevation" : "<angle> | below | level | above | higher | lower | inherit",\n + "empty-cells" : "show | hide | inherit",\n +\n + //F\n + "filter" : 1,\n + "fit" : "fill | hidden | meet | slice",\n + "fit-position" : 1,\n + "float" : "left | right | none | inherit",\n + "float-offset" : 1,\n + "font" : 1,\n + "font-family" : 1,\n + "font-size" : "<absolute-size> | <relative-size> | <length> | <percentage> | inherit",\n + "font-size-adjust" : "<number> | none | inherit",\n + "font-stretch" : "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit",\n + "font-style" : "normal | italic | oblique | inherit",\n + "font-variant" : "normal | small-caps | inherit",\n + "font-weight" : "normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit",\n +\n + //G\n + "grid-cell-stacking" : "columns | rows | layer",\n + "grid-column" : 1,\n + "grid-columns" : 1,\n + "grid-column-align" : "start | end | center | stretch",\n + "grid-column-sizing" : 1,\n + "grid-column-span" : "<integer>",\n + "grid-flow" : "none | rows | columns",\n + "grid-layer" : "<integer>",\n + "grid-row" : 1,\n + "grid-rows" : 1,\n + "grid-row-align" : "start | end | center | stretch",\n + "grid-row-span" : "<integer>",\n + "grid-row-sizing" : 1,\n +\n + //H\n + "hanging-punctuation" : 1,\n + "height" : "<margin-width> | inherit",\n + "hyphenate-after" : "<integer> | auto",\n + "hyphenate-before" : "<integer> | auto",\n + "hyphenate-character" : "<string> | auto",\n + "hyphenate-lines" : "no-limit | <integer>",\n + "hyphenate-resource" : 1,\n + "hyphens" : "none | manual | auto",\n +\n + //I\n + "icon" : 1,\n + "image-orientation" : "angle | auto",\n + "image-rendering" : 1,\n + "image-resolution" : 1,\n + "inline-box-align" : "initial | last | <integer>",\n +\n + //L\n + "left" : "<margin-width> | inherit",\n + "letter-spacing" : "<length> | normal | inherit",\n + "line-height" : "<number> | <length> | <percentage> | normal | inherit",\n + "line-break" : "auto | loose | normal | strict",\n + "line-stacking" : 1,\n + "line-stacking-ruby" : "exclude-ruby | include-ruby",\n + "line-stacking-shift" : "consider-shifts | disregard-shifts",\n + "line-stacking-strategy" : "inline-line-height | block-line-height | max-height | grid-height",\n + "list-style" : 1,\n + "list-style-image" : "<uri> | none | inherit",\n + "list-style-position" : "inside | outside | inherit",\n + "list-style-type" : "disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit",\n +\n + //M\n + "margin" : { multi: "<margin-width> | inherit", max: 4 },\n + "margin-bottom" : "<margin-width> | inherit",\n + "margin-left" : "<margin-width> | inherit",\n + "margin-right" : "<margin-width> | inherit",\n + "margin-top" : "<margin-width> | inherit",\n + "mark" : 1,\n + "mark-after" : 1,\n + "mark-before" : 1,\n + "marks" : 1,\n + "marquee-direction" : 1,\n + "marquee-play-count" : 1,\n + "marquee-speed" : 1,\n + "marquee-style" : 1,\n + "max-height" : "<length> | <percentage> | none | inherit",\n + "max-width" : "<length> | <percentage> | none | inherit",\n + "min-height" : "<length> | <percentage> | inherit",\n + "min-width" : "<length> | <percentage> | inherit",\n + "move-to" : 1,\n +\n + //N\n + "nav-down" : 1,\n + "nav-index" : 1,\n + "nav-left" : 1,\n + "nav-right" : 1,\n + "nav-up" : 1,\n +\n + //O\n + "opacity" : "<number> | inherit",\n + "orphans" : "<integer> | inherit",\n + "outline" : 1,\n + "outline-color" : "<color> | invert | inherit",\n + "outline-offset" : 1,\n + "outline-style" : "<border-style> | inherit",\n + "outline-width" : "<border-width> | inherit",\n + "overflow" : "visible | hidden | scroll | auto | inherit",\n + "overflow-style" : 1,\n + "overflow-x" : 1,\n + "overflow-y" : 1,\n +\n + //P\n + "padding" : { multi: "<padding-width> | inherit", max: 4 },\n + "padding-bottom" : "<padding-width> | inherit",\n + "padding-left" : "<padding-width> | inherit",\n + "padding-right" : "<padding-width> | inherit",\n + "padding-top" : "<padding-width> | inherit",\n + "page" : 1,\n + "page-break-after" : "auto | always | avoid | left | right | inherit",\n + "page-break-before" : "auto | always | avoid | left | right | inherit",\n + "page-break-inside" : "auto | avoid | inherit",\n + "page-policy" : 1,\n + "pause" : 1,\n + "pause-after" : 1,\n + "pause-before" : 1,\n + "perspective" : 1,\n + "perspective-origin" : 1,\n + "phonemes" : 1,\n + "pitch" : 1,\n + "pitch-range" : 1,\n + "play-during" : 1,\n + "pointer-events" : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit",\n + "position" : "static | relative | absolute | fixed | inherit",\n + "presentation-level" : 1,\n + "punctuation-trim" : 1,\n +\n + //Q\n + "quotes" : 1,\n +\n + //R\n + "rendering-intent" : 1,\n + "resize" : 1,\n + "rest" : 1,\n + "rest-after" : 1,\n + "rest-before" : 1,\n + "richness" : 1,\n + "right" : "<margin-width> | inherit",\n + "rotation" : 1,\n + "rotation-point" : 1,\n + "ruby-align" : 1,\n + "ruby-overhang" : 1,\n + "ruby-position" : 1,\n + "ruby-span" : 1,\n +\n + //S\n + "size" : 1,\n + "speak" : "normal | none | spell-out | inherit",\n + "speak-header" : "once | always | inherit",\n + "speak-numeral" : "digits | continuous | inherit",\n + "speak-punctuation" : "code | none | inherit",\n + "speech-rate" : 1,\n + "src" : 1,\n + "stress" : 1,\n + "string-set" : 1,\n +\n + "table-layout" : "auto | fixed | inherit",\n + "tab-size" : "<integer> | <length>",\n + "target" : 1,\n + "target-name" : 1,\n + "target-new" : 1,\n + "target-position" : 1,\n + "text-align" : "left | right | center | justify | inherit" ,\n + "text-align-last" : 1,\n + "text-decoration" : 1,\n + "text-emphasis" : 1,\n + "text-height" : 1,\n + "text-indent" : "<length> | <percentage> | inherit",\n + "text-justify" : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida",\n + "text-outline" : 1,\n + "text-overflow" : 1,\n + "text-rendering" : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit",\n + "text-shadow" : 1,\n + "text-transform" : "capitalize | uppercase | lowercase | none | inherit",\n + "text-wrap" : "normal | none | avoid",\n + "top" : "<margin-width> | inherit",\n + "transform" : 1,\n + "transform-origin" : 1,\n + "transform-style" : 1,\n + "transition" : 1,\n + "transition-delay" : 1,\n + "transition-duration" : 1,\n + "transition-property" : 1,\n + "transition-timing-function" : 1,\n +\n + //U\n + "unicode-bidi" : "normal | embed | bidi-override | inherit",\n + "user-modify" : "read-only | read-write | write-only | inherit",\n + "user-select" : "none | text | toggle | element | elements | all | inherit",\n +\n + //V\n + "vertical-align" : "auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length>",\n + "visibility" : "visible | hidden | collapse | inherit",\n + "voice-balance" : 1,\n + "voice-duration" : 1,\n + "voice-family" : 1,\n + "voice-pitch" : 1,\n + "voice-pitch-range" : 1,\n + "voice-rate" : 1,\n + "voice-stress" : 1,\n + "voice-volume" : 1,\n + "volume" : 1,\n +\n + //W\n + "white-space" : "normal | pre | nowrap | pre-wrap | pre-line | inherit | -pre-wrap | -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap", //http://perishablepress.com/wrapping-content/\n + "white-space-collapse" : 1,\n + "widows" : "<integer> | inherit",\n + "width" : "<length> | <percentage> | auto | inherit" ,\n + "word-break" : "normal | keep-all | break-all",\n + "word-spacing" : "<length> | normal | inherit",\n + "word-wrap" : 1,\n +\n + //Z\n + "z-index" : "<integer> | auto | inherit",\n + "zoom" : "<number> | <percentage> | normal"\n +};\n +\n +/*global SyntaxUnit, Parser*/\n +/**\n + * Represents a selector combinator (whitespace, +, >).\n + * @namespace parserlib.css\n + * @class PropertyName\n + * @extends parserlib.util.SyntaxUnit\n + * @constructor\n + * @param {String} text The text representation of the unit.\n + * @param {String} hack The type of IE hack applied ("*", "_", or null).\n + * @param {int} line The line of text on which the unit resides.\n + * @param {int} col The column of text on which the unit resides.\n + */\n +function PropertyName(text, hack, line, col){\n +\n + SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_NAME_TYPE);\n +\n + /**\n + * The type of IE hack applied ("*", "_", or null).\n + * @type String\n + * @property hack\n + */\n + this.hack = hack;\n +\n +}\n +\n +PropertyName.prototype = new SyntaxUnit();\n +PropertyName.prototype.constructor = PropertyName;\n +PropertyName.prototype.toString = function(){\n + return (this.hack ? this.hack : "") + this.text;\n +};\n +\n +/*global SyntaxUnit, Parser*/\n +/**\n + * Represents a single part of a CSS property value, meaning that it represents\n + * just everything single part between ":" and ";". If there are multiple values\n + * separated by commas, this type represents just one of the values.\n + * @param {String[]} parts An array of value parts making up this value.\n + * @param {int} line The line of text on which the unit resides.\n + * @param {int} col The column of text on which the unit resides.\n + * @namespace parserlib.css\n + * @class PropertyValue\n + * @extends parserlib.util.SyntaxUnit\n + * @constructor\n + */\n +function PropertyValue(parts, line, col){\n +\n + SyntaxUnit.call(this, parts.join(" "), line, col, Parser.PROPERTY_VALUE_TYPE);\n +\n + /**\n + * The parts that make up the selector.\n + * @type Array\n + * @property parts\n + */\n + this.parts = parts;\n +\n +}\n +\n +PropertyValue.prototype = new SyntaxUnit();\n +PropertyValue.prototype.constructor = PropertyValue;\n +\n +\n +/*global SyntaxUnit, Parser*/\n +/**\n + * A utility class that allows for easy iteration over the various parts of a\n + * property value.\n + * @param {parserlib.css.PropertyValue} value The property value to iterate over.\n + * @namespace parserlib.css\n + * @class PropertyValueIterator\n + * @constructor\n + */\n +function PropertyValueIterator(value){\n +\n + /**\n + * Iterator value\n + * @type int\n + * @property _i\n + * @private\n + */\n + this._i = 0;\n +\n + /**\n + * The parts that make up the value.\n + * @type Array\n + * @property _parts\n + * @private\n + */\n + this._parts = value.parts;\n +\n + /**\n + * Keeps track of bookmarks along the way.\n + * @type Array\n + * @property _marks\n + * @private\n + */\n + this._marks = [];\n +\n + /**\n + * Holds the original property value.\n + * @type parserlib.css.PropertyValue\n + * @property value\n + */\n + this.value = value;\n +\n +}\n +\n +/**\n + * Returns the total number of parts in the value.\n + * @return {int} The total number of parts in the value.\n + * @method count\n + */\n +PropertyValueIterator.prototype.count = function(){\n + return this._parts.length;\n +};\n +\n +/**\n + * Indicates if the iterator is positioned at the first item.\n + * @return {Boolean} True if positioned at first item, false if not.\n + * @method isFirst\n + */\n +PropertyValueIterator.prototype.isFirst = function(){\n + return this._i === 0;\n +};\n +\n +/**\n + * Indicates if there are more parts of the property value.\n + * @return {Boolean} True if there are more parts, false if not.\n + * @method hasNext\n + */\n +PropertyValueIterator.prototype.hasNext = function(){\n + return (this._i < this._parts.length);\n +};\n +\n +/**\n + * Marks the current spot in the iteration so it can be restored to\n + * later on.\n + * @return {void}\n + * @method mark\n + */\n +PropertyValueIterator.prototype.mark = function(){\n + this._marks.push(this._i);\n +};\n +\n +/**\n + * Returns the next part of the property value or null if there is no next\n + * part. Does not move the internal counter forward.\n + * @return {parserlib.css.PropertyValuePart} The next part of the property value or null if there is no next\n + * part.\n + * @method peek\n + */\n +PropertyValueIterator.prototype.peek = function(count){\n + return this.hasNext() ? this._parts[this._i + (count || 0)] : null;\n +};\n +\n +/**\n + * Returns the next part of the property value or null if there is no next\n + * part.\n + * @return {parserlib.css.PropertyValuePart} The next part of the property value or null if there is no next\n + * part.\n + * @method next\n + */\n +PropertyValueIterator.prototype.next = function(){\n + return this.hasNext() ? this._parts[this._i++] : null;\n +};\n +\n +/**\n + * Returns the previous part of the property value or null if there is no\n + * previous part.\n + * @return {parserlib.css.PropertyValuePart} The previous part of the\n + * property value or null if there is no next part.\n + * @method previous\n + */\n +PropertyValueIterator.prototype.previous = function(){\n + return this._i > 0 ? this._parts[--this._i] : null;\n +};\n +\n +/**\n + * Restores the last saved bookmark.\n + * @return {void}\n + * @method restore\n + */\n +PropertyValueIterator.prototype.restore = function(){\n + if (this._marks.length){\n + this._i = this._marks.pop();\n + }\n +};\n +\n +\n +/*global SyntaxUnit, Parser, Colors*/\n +/**\n + * Represents a single part of a CSS property value, meaning that it represents\n + * just one part of the data between ":" and ";".\n + * @param {String} text The text representation of the unit.\n + * @param {int} line The line of text on which the unit resides.\n + * @param {int} col The column of text on which the unit resides.\n + * @namespace parserlib.css\n + * @class PropertyValuePart\n + * @extends parserlib.util.SyntaxUnit\n + * @constructor\n + */\n +function PropertyValuePart(text, line, col){\n +\n + SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_VALUE_PART_TYPE);\n +\n + /**\n + * Indicates the type of value unit.\n + * @type String\n + * @property type\n + */\n + this.type = "unknown";\n +\n + //figure out what type of data it is\n +\n + var temp;\n +\n + //it is a measurement?\n + if (/^([+\\-]?[\\d\\.]+)([a-z]+)$/i.test(text)){ //dimension\n + this.type = "dimension";\n + this.value = +RegExp.$1;\n + this.units = RegExp.$2;\n +\n + //try to narrow down\n + switch(this.units.toLowerCase()){\n +\n + case "em":\n + case "rem":\n + case "ex":\n + case "px":\n + case "cm":\n + case "mm":\n + case "in":\n + case "pt":\n + case "pc":\n + case "ch":\n + case "vh":\n + case "vw":\n + case "vm":\n + this.type = "length";\n + break;\n +\n + case "deg":\n + case "rad":\n + case "grad":\n + this.type = "angle";\n + break;\n +\n + case "ms":\n + case "s":\n + this.type = "time";\n + break;\n +\n + case "hz":\n + case "khz":\n + this.type = "frequency";\n + break;\n +\n + case "dpi":\n + case "dpcm":\n + this.type = "resolution";\n + break;\n +\n + //default\n +\n + }\n +\n + } else if (/^([+\\-]?[\\d\\.]+)%$/i.test(text)){ //percentage\n + this.type = "percentage";\n + this.value = +RegExp.$1;\n + } else if (/^([+\\-]?[\\d\\.]+)%$/i.test(text)){ //percentage\n + this.type = "percentage";\n + this.value = +RegExp.$1;\n + } else if (/^([+\\-]?\\d+)$/i.test(text)){ //integer\n + this.type = "integer";\n + this.value = +RegExp.$1;\n + } else if (/^([+\\-]?[\\d\\.]+)$/i.test(text)){ //number\n + this.type = "number";\n + this.value = +RegExp.$1;\n +\n + } else if (/^#([a-f0-9]{3,6})/i.test(text)){ //hexcolor\n + this.type = "color";\n + temp = RegExp.$1;\n + if (temp.length == 3){\n + this.red = parseInt(temp.charAt(0)+temp.charAt(0),16);\n + this.green = parseInt(temp.charAt(1)+temp.charAt(1),16);\n + this.blue = parseInt(temp.charAt(2)+temp.charAt(2),16);\n + } else {\n + this.red = parseInt(temp.substring(0,2),16);\n + this.green = parseInt(temp.substring(2,4),16);\n + this.blue = parseInt(temp.substring(4,6),16);\n + }\n + } else if (/^rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)/i.test(text)){ //rgb() color with absolute numbers\n + this.type = "color";\n + this.red = +RegExp.$1;\n + this.green = +RegExp.$2;\n + this.blue = +RegExp.$3;\n + } else if (/^rgb\\(\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*\\)/i.test(text)){ //rgb() color with percentages\n + this.type = "color";\n + this.red = +RegExp.$1 * 255 / 100;\n + this.green = +RegExp.$2 * 255 / 100;\n + this.blue = +RegExp.$3 * 255 / 100;\n + } else if (/^rgba\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*([\\d\\.]+)\\s*\\)/i.test(text)){ //rgba() color with absolute numbers\n + this.type = "color";\n + this.red = +RegExp.$1;\n + this.green = +RegExp.$2;\n + this.blue = +RegExp.$3;\n + this.alpha = +RegExp.$4;\n + } else if (/^rgba\\(\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*,\\s*([\\d\\.]+)\\s*\\)/i.test(text)){ //rgba() color with percentages\n + this.type = "color";\n + this.red = +RegExp.$1 * 255 / 100;\n + this.green = +RegExp.$2 * 255 / 100;\n + this.blue = +RegExp.$3 * 255 / 100;\n + this.alpha = +RegExp.$4;\n + } else if (/^hsl\\(\\s*(\\d+)\\s*,\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*\\)/i.test(text)){ //hsl()\n + this.type = "color";\n + this.hue = +RegExp.$1;\n + this.saturation = +RegExp.$2 / 100;\n + this.lightness = +RegExp.$3 / 100;\n + } else if (/^hsla\\(\\s*(\\d+)\\s*,\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*,\\s*([\\d\\.]+)\\s*\\)/i.test(text)){ //hsla() color with percentages\n + this.type = "color";\n + this.hue = +RegExp.$1;\n + this.saturation = +RegExp.$2 / 100;\n + this.lightness = +RegExp.$3 / 100;\n + this.alpha = +RegExp.$4;\n + } else if (/^url\\(["\']?([^\\)"\']+)["\']?\\)/i.test(text)){ //URI\n + this.type = "uri";\n + this.uri = RegExp.$1;\n + } else if (/^([^\\(]+)\\(/i.test(text)){\n + this.type = "function";\n + this.name = RegExp.$1;\n + this.value = text;\n + } else if (/^["\'][^"\']*["\']/.test(text)){ //string\n + this.type = "string";\n + this.value = eval(text);\n + } else if (Colors[text.toLowerCase()]){ //named color\n + this.type = "color";\n + temp = Colors[text.toLowerCase()].substring(1);\n + this.red = parseInt(temp.substring(0,2),16);\n + this.green = parseInt(temp.substring(2,4),16);\n + this.blue = parseInt(temp.substring(4,6),16);\n + } else if (/^[\\,\\/]$/.test(text)){\n + this.type = "operator";\n + this.value = text;\n + } else if (/^[a-z\\-\\u0080-\\uFFFF][a-z0-9\\-\\u0080-\\uFFFF]*$/i.test(text)){\n + this.type = "identifier";\n + this.value = text;\n + }\n +\n +}\n +\n +PropertyValuePart.prototype = new SyntaxUnit();\n +PropertyValuePart.prototype.constructor = PropertyValuePart;\n +\n +/**\n + * Create a new syntax unit based solely on the given token.\n + * Convenience method for creating a new syntax unit when\n + * it represents a single token instead of multiple.\n + * @param {Object} token The token object to represent.\n + * @return {parserlib.css.PropertyValuePart} The object representing the token.\n + * @static\n + * @method fromToken\n + */\n +PropertyValuePart.fromToken = function(token){\n + return new PropertyValuePart(token.value, token.startLine, token.startCol);\n +};\n +var Pseudos = {\n + ":first-letter": 1,\n + ":first-line": 1,\n + ":before": 1,\n + ":after": 1\n +};\n +\n +Pseudos.ELEMENT = 1;\n +Pseudos.CLASS = 2;\n +\n +Pseudos.isElement = function(pseudo){\n + return pseudo.indexOf("::") === 0 || Pseudos[pseudo.toLowerCase()] == Pseudos.ELEMENT;\n +};\n +/*global SyntaxUnit, Parser, Specificity*/\n +/**\n + * Represents an entire single selector, including all parts but not\n + * including multiple selectors (those separated by commas).\n + * @namespace parserlib.css\n + * @class Selector\n + * @extends parserlib.util.SyntaxUnit\n + * @constructor\n + * @param {Array} parts Array of selectors parts making up this selector.\n + * @param {int} line The line of text on which the unit resides.\n + * @param {int} col The column of text on which the unit resides.\n + */\n +function Selector(parts, line, col){\n +\n + SyntaxUnit.call(this, parts.join(" "), line, col, Parser.SELECTOR_TYPE);\n +\n + /**\n + * The parts that make up the selector.\n + * @type Array\n + * @property parts\n + */\n + this.parts = parts;\n +\n + /**\n + * The specificity of the selector.\n + * @type parserlib.css.Specificity\n + * @property specificity\n + */\n + this.specificity = Specificity.calculate(this);\n +\n +}\n +\n +Selector.prototype = new SyntaxUnit();\n +Selector.prototype.constructor = Selector;\n +\n +\n +/*global SyntaxUnit, Parser*/\n +/**\n + * Represents a single part of a selector string, meaning a single set of\n + * element name and modifiers. This does not include combinators such as\n + * spaces, +, >, etc.\n + * @namespace parserlib.css\n + * @class SelectorPart\n + * @extends parserlib.util.SyntaxUnit\n + * @constructor\n + * @param {String} elementName The element name in the selector or null\n + * if there is no element name.\n + * @param {Array} modifiers Array of individual modifiers for the element.\n + * May be empty if there are none.\n + * @param {String} text The text representation of the unit.\n + * @param {int} line The line of text on which the unit resides.\n + * @param {int} col The column of text on which the unit resides.\n + */\n +function SelectorPart(elementName, modifiers, text, line, col){\n +\n + SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_PART_TYPE);\n +\n + /**\n + * The tag name of the element to which this part\n + * of the selector affects.\n + * @type String\n + * @property elementName\n + */\n + this.elementName = elementName;\n +\n + /**\n + * The parts that come after the element name, such as class names, IDs,\n + * pseudo classes/elements, etc.\n + * @type Array\n + * @property modifiers\n + */\n + this.modifiers = modifiers;\n +\n +}\n +\n +SelectorPart.prototype = new SyntaxUnit();\n +SelectorPart.prototype.constructor = SelectorPart;\n +\n +\n +/*global SyntaxUnit, Parser*/\n +/**\n + * Represents a selector modifier string, meaning a class name, element name,\n + * element ID, pseudo rule, etc.\n + * @namespace parserlib.css\n + * @class SelectorSubPart\n + * @extends parserlib.util.SyntaxUnit\n + * @constructor\n + * @param {String} text The text representation of the unit.\n + * @param {String} type The type of selector modifier.\n + * @param {int} line The line of text on which the unit resides.\n + * @param {int} col The column of text on which the unit resides.\n + */\n +function SelectorSubPart(text, type, line, col){\n +\n + SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_SUB_PART_TYPE);\n +\n + /**\n + * The type of modifier.\n + * @type String\n + * @property type\n + */\n + this.type = type;\n +\n + /**\n + * Some subparts have arguments, this represents them.\n + * @type Array\n + * @property args\n + */\n + this.args = [];\n +\n +}\n +\n +SelectorSubPart.prototype = new SyntaxUnit();\n +SelectorSubPart.prototype.constructor = SelectorSubPart;\n +\n +\n +/*global Pseudos, SelectorPart*/\n +/**\n + * Represents a selector\'s specificity.\n + * @namespace parserlib.css\n + * @class Specificity\n + * @constructor\n + * @param {int} a Should be 1 for inline styles, zero for stylesheet styles\n + * @param {int} b Number of ID selectors\n + * @param {int} c Number of classes and pseudo classes\n + * @param {int} d Number of element names and pseudo elements\n + */\n +function Specificity(a, b, c, d){\n + this.a = a;\n + this.b = b;\n + this.c = c;\n + this.d = d;\n +}\n +\n +Specificity.prototype = {\n + constructor: Specificity,\n +\n + /**\n + * Compare this specificity to another.\n + * @param {Specificity} other The other specificity to compare to.\n + * @return {int} -1 if the other specificity is larger, 1 if smaller, 0 if equal.\n + * @method compare\n + */\n + compare: function(other){\n + var comps = ["a", "b", "c", "d"],\n + i, len;\n +\n + for (i=0, len=comps.length; i < len; i++){\n + if (this[comps[i]] < other[comps[i]]){\n + return -1;\n + } else if (this[comps[i]] > other[comps[i]]){\n + return 1;\n + }\n + }\n +\n + return 0;\n + },\n +\n + /**\n + * Creates a numeric value for the specificity.\n + * @return {int} The numeric value for the specificity.\n + * @method valueOf\n + */\n + valueOf: function(){\n + return (this.a * 1000) + (this.b * 100) + (this.c * 10) + this.d;\n + },\n +\n + /**\n + * Returns a string representation for specificity.\n + * @return {String} The string representation of specificity.\n + * @method toString\n + */\n + toString: function(){\n + return this.a + "," + this.b + "," + this.c + "," + this.d;\n + }\n +\n +};\n +\n +/**\n + * Calculates the specificity of the given selector.\n + * @param {parserlib.css.Selector} The selector to calculate specificity for.\n + * @return {parserlib.css.Specificity} The specificity of the selector.\n + * @static\n + * @method calculate\n + */\n +Specificity.calculate = function(selector){\n +\n + var i, len,\n + part,\n + b=0, c=0, d=0;\n +\n + function updateValues(part){\n +\n + var i, j, len, num,\n + elementName = part.elementName ? part.elementName.text : "",\n + modifier;\n +\n + if (elementName && elementName.charAt(elementName.length-1) != "*") {\n + d++;\n + }\n +\n + for (i=0, len=part.modifiers.length; i < len; i++){\n + modifier = part.modifiers[i];\n + switch(modifier.type){\n + case "class":\n + case "attribute":\n + c++;\n + break;\n +\n + case "id":\n + b++;\n + break;\n +\n + case "pseudo":\n + if (Pseudos.isElement(modifier.text)){\n + d++;\n + } else {\n + c++;\n + }\n + break;\n +\n + case "not":\n + for (j=0, num=modifier.args.length; j < num; j++){\n + updateValues(modifier.args[j]);\n + }\n + }\n + }\n + }\n +\n + for (i=0, len=selector.parts.length; i < len; i++){\n + part = selector.parts[i];\n +\n + if (part instanceof SelectorPart){\n + updateValues(part);\n + }\n + }\n +\n + return new Specificity(0, b, c, d);\n +};\n +\n +/*global Tokens, TokenStreamBase*/\n +\n +var h = /^[0-9a-fA-F]$/,\n + nonascii = /^[\\u0080-\\uFFFF]$/,\n + nl = /\\n|\\r\\n|\\r|\\f/;\n +\n +//-----------------------------------------------------------------------------\n +// Helper functions\n +//-----------------------------------------------------------------------------\n +\n +\n +function isHexDigit(c){\n + return c !== null && h.test(c);\n +}\n +\n +function isDigit(c){\n + return c !== null && /\\d/.test(c);\n +}\n +\n +function isWhitespace(c){\n + return c !== null && /\\s/.test(c);\n +}\n +\n +function isNewLine(c){\n + return c !== null && nl.test(c);\n +}\n +\n +function isNameStart(c){\n + return c !== null && (/[a-z_\\u0080-\\uFFFF\\\\]/i.test(c));\n +}\n +\n +function isNameChar(c){\n + return c !== null && (isNameStart(c) || /[0-9\\-\\\\]/.test(c));\n +}\n +\n +function isIdentStart(c){\n + return c !== null && (isNameStart(c) || /\\-\\\\/.test(c));\n +}\n +\n +function mix(receiver, supplier){\n + for (var prop in supplier){\n + if (supplier.hasOwnProperty(prop)){\n + receiver[prop] = supplier[prop];\n + }\n + }\n + return receiver;\n +}\n +\n +//-----------------------------------------------------------------------------\n +// CSS Token Stream\n +//-----------------------------------------------------------------------------\n +\n +\n +/**\n + * A token stream that produces CSS tokens.\n + * @param {String|Reader} input The source of text to tokenize.\n + * @constructor\n + * @class TokenStream\n + * @namespace parserlib.css\n + */\n +function TokenStream(input){\n + TokenStreamBase.call(this, input, Tokens);\n +}\n +\n +TokenStream.prototype = mix(new TokenStreamBase(), {\n +\n + /**\n + * Overrides the TokenStreamBase method of the same name\n + * to produce CSS tokens.\n + * @param {variant} channel The name of the channel to use\n + * for the next token.\n + * @return {Object} A token object representing the next token.\n + * @method _getToken\n + * @private\n + */\n + _getToken: function(channel){\n +\n + var c,\n + reader = this._reader,\n + token = null,\n + startLine = reader.getLine(),\n + startCol = reader.getCol();\n +\n + c = reader.read();\n +\n +\n + while(c){\n + switch(c){\n +\n + /*\n + * Potential tokens:\n + * - COMMENT\n + * - SLASH\n + * - CHAR\n + */\n + case "/":\n +\n + if(reader.peek() == "*"){\n + token = this.commentToken(c, startLine, startCol);\n + } else {\n + token = this.charToken(c, startLine, startCol);\n + }\n + break;\n +\n + /*\n + * Potential tokens:\n + * - DASHMATCH\n + * - INCLUDES\n + * - PREFIXMATCH\n + * - SUFFIXMATCH\n + * - SUBSTRINGMATCH\n + * - CHAR\n + */\n + case "|":\n + case "~":\n + case "^":\n + case "$":\n + case "*":\n + if(reader.peek() == "="){\n + token = this.comparisonToken(c, startLine, startCol);\n + } else {\n + token = this.charToken(c, startLine, startCol);\n + }\n + break;\n +\n + /*\n + * Potential tokens:\n + * - STRING\n + * - INVALID\n + */\n + case "\\"":\n + case "\'":\n + token = this.stringToken(c, startLine, startCol);\n + break;\n +\n + /*\n + * Potential tokens:\n + * - HASH\n + * - CHAR\n + */\n + case "#":\n + if (isNameChar(reader.peek())){\n + token = this.hashToken(c, startLine, startCol);\n + } else {\n + token = this.charToken(c, startLine, startCol);\n + }\n + break;\n +\n + /*\n + * Potential tokens:\n + * - DOT\n + * - NUMBER\n + * - DIMENSION\n + * - PERCENTAGE\n + */\n + case ".":\n + if (isDigit(reader.peek())){\n + token = this.numberToken(c, startLine, startCol);\n + } else {\n + token = this.charToken(c, startLine, startCol);\n + }\n + break;\n +\n + /*\n + * Potential tokens:\n + * - CDC\n + * - MINUS\n + * - NUMBER\n + * - DIMENSION\n + * - PERCENTAGE\n + */\n + case "-":\n + if (reader.peek() == "-"){ //could be closing HTML-style comment\n + token = this.htmlCommentEndToken(c, startLine, startCol);\n + } else if (isNameStart(reader.peek())){\n + token = this.identOrFunctionToken(c, startLine, startCol);\n + } else {\n + token = this.charToken(c, startLine, startCol);\n + }\n + break;\n +\n + /*\n + * Potential tokens:\n + * - IMPORTANT_SYM\n + * - CHAR\n + */\n + case "!":\n + token = this.importantToken(c, startLine, startCol);\n + break;\n +\n + /*\n + * Any at-keyword or CHAR\n + */\n + case "@":\n + token = this.atRuleToken(c, startLine, startCol);\n + break;\n +\n + /*\n + * Potential tokens:\n + * - NOT\n + * - CHAR\n + */\n + case ":":\n + token = this.notToken(c, startLine, startCol);\n + break;\n +\n + /*\n + * Potential tokens:\n + * - CDO\n + * - CHAR\n + */\n + case "<":\n + token = this.htmlCommentStartToken(c, startLine, startCol);\n + break;\n +\n + /*\n + * Potential tokens:\n + * - UNICODE_RANGE\n + * - URL\n + * - CHAR\n + */\n + case "U":\n + case "u":\n + if (reader.peek() == "+"){\n + token = this.unicodeRangeToken(c, startLine, startCol);\n + break;\n + }\n + /* falls through */\n + default:\n +\n + /*\n + * Potential tokens:\n + * - NUMBER\n + * - DIMENSION\n + * - LENGTH\n + * - FREQ\n + * - TIME\n + * - EMS\n + * - EXS\n + * - ANGLE\n + */\n + if (isDigit(c)){\n + token = this.numberToken(c, startLine, startCol);\n + } else\n +\n + /*\n + * Potential tokens:\n + * - S\n + */\n + if (isWhitespace(c)){\n + token = this.whitespaceToken(c, startLine, startCol);\n + } else\n +\n + /*\n + * Potential tokens:\n + * - IDENT\n + */\n + if (isIdentStart(c)){\n + token = this.identOrFunctionToken(c, startLine, startCol);\n + } else\n +\n + /*\n + * Potential tokens:\n + * - CHAR\n + * - PLUS\n + */\n + {\n + token = this.charToken(c, startLine, startCol);\n + }\n +\n +\n +\n +\n +\n +\n + }\n +\n + //make sure this token is wanted\n + //TODO: check channel\n + break;\n + }\n +\n + if (!token && c === null){\n + token = this.createToken(Tokens.EOF,null,startLine,startCol);\n + }\n +\n + return token;\n + },\n +\n + //-------------------------------------------------------------------------\n + // Methods to create tokens\n + //-------------------------------------------------------------------------\n +\n + /**\n + * Produces a token based on available data and the current\n + * reader position information. This method is called by other\n + * private methods to create tokens and is never called directly.\n + * @param {int} tt The token type.\n + * @param {String} value The text value of the token.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @param {Object} options (Optional) Specifies a channel property\n + * to indicate that a different channel should be scanned\n + * and/or a hide property indicating that the token should\n + * be hidden.\n + * @return {Object} A token object.\n + * @method createToken\n + */\n + createToken: function(tt, value, startLine, startCol, options){\n + var reader = this._reader;\n + options = options || {};\n +\n + return {\n + value: value,\n + type: tt,\n + channel: options.channel,\n + hide: options.hide || false,\n + startLine: startLine,\n + startCol: startCol,\n + endLine: reader.getLine(),\n + endCol: reader.getCol()\n + };\n + },\n +\n + //-------------------------------------------------------------------------\n + // Methods to create specific tokens\n + //-------------------------------------------------------------------------\n +\n + /**\n + * Produces a token for any at-rule. If the at-rule is unknown, then\n + * the token is for a single "@" character.\n + * @param {String} first The first character for the token.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method atRuleToken\n + */\n + atRuleToken: function(first, startLine, startCol){\n + var rule = first,\n + reader = this._reader,\n + tt = Tokens.CHAR,\n + valid = false,\n + ident,\n + c;\n +\n + /*\n + * First, mark where we are. There are only four @ rules,\n + * so anything else is really just an invalid token.\n + * Basically, if this doesn\'t match one of the known @\n + * rules, just return \'@\' as an unknown token and allow\n + * parsing to continue after that point.\n + */\n + reader.mark();\n +\n + //try to find the at-keyword\n + ident = this.readName();\n + rule = first + ident;\n + tt = Tokens.type(rule.toLowerCase());\n +\n + //if it\'s not valid, use the first character only and reset the reader\n + if (tt == Tokens.CHAR || tt == Tokens.UNKNOWN){\n + if (rule.length > 1){\n + tt = Tokens.UNKNOWN_SYM;\n + } else {\n + tt = Tokens.CHAR;\n + rule = first;\n + reader.reset();\n + }\n + }\n +\n + return this.createToken(tt, rule, startLine, startCol);\n + },\n +\n + /**\n + * Produces a character token based on the given character\n + * and location in the stream. If there\'s a special (non-standard)\n + * token name, this is used; otherwise CHAR is used.\n + * @param {String} c The character for the token.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method charToken\n + */\n + charToken: function(c, startLine, startCol){\n + var tt = Tokens.type(c);\n +\n + if (tt == -1){\n + tt = Tokens.CHAR;\n + }\n +\n + return this.createToken(tt, c, startLine, startCol);\n + },\n +\n + /**\n + * Produces a character token based on the given character\n + * and location in the stream. If there\'s a special (non-standard)\n + * token name, this is used; otherwise CHAR is used.\n + * @param {String} first The first character for the token.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method commentToken\n + */\n + commentToken: function(first, startLine, startCol){\n + var reader = this._reader,\n + comment = this.readComment(first);\n +\n + return this.createToken(Tokens.COMMENT, comment, startLine, startCol);\n + },\n +\n + /**\n + * Produces a comparison token based on the given character\n + * and location in the stream. The next character must be\n + * read and is already known to be an equals sign.\n + * @param {String} c The character for the token.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method comparisonToken\n + */\n + comparisonToken: function(c, startLine, startCol){\n + var reader = this._reader,\n + comparison = c + reader.read(),\n + tt = Tokens.type(comparison) || Tokens.CHAR;\n +\n + return this.createToken(tt, comparison, startLine, startCol);\n + },\n +\n + /**\n + * Produces a hash token based on the specified information. The\n + * first character provided is the pound sign (#) and then this\n + * method reads a name afterward.\n + * @param {String} first The first character (#) in the hash nam + +]]></string> </value> + </item> + <item> + <key> <string>next</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> + </value> + </item> + </dictionary> + </pickle> + </record> + <record id="4" aka="AAAAAAAAAAQ="> + <pickle> + <global name="Pdata" module="OFS.Image"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>data</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +e.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method hashToken\n + */\n + hashToken: function(first, startLine, startCol){\n + var reader = this._reader,\n + name = this.readName(first);\n +\n + return this.createToken(Tokens.HASH, name, startLine, startCol);\n + },\n +\n + /**\n + * Produces a CDO or CHAR token based on the specified information. The\n + * first character is provided and the rest is read by the function to determine\n + * the correct token to create.\n + * @param {String} first The first character in the token.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method htmlCommentStartToken\n + */\n + htmlCommentStartToken: function(first, startLine, startCol){\n + var reader = this._reader,\n + text = first;\n +\n + reader.mark();\n + text += reader.readCount(3);\n +\n + if (text == "<!--"){\n + return this.createToken(Tokens.CDO, text, startLine, startCol);\n + } else {\n + reader.reset();\n + return this.charToken(first, startLine, startCol);\n + }\n + },\n +\n + /**\n + * Produces a CDC or CHAR token based on the specified information. The\n + * first character is provided and the rest is read by the function to determine\n + * the correct token to create.\n + * @param {String} first The first character in the token.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method htmlCommentEndToken\n + */\n + htmlCommentEndToken: function(first, startLine, startCol){\n + var reader = this._reader,\n + text = first;\n +\n + reader.mark();\n + text += reader.readCount(2);\n +\n + if (text == "-->"){\n + return this.createToken(Tokens.CDC, text, startLine, startCol);\n + } else {\n + reader.reset();\n + return this.charToken(first, startLine, startCol);\n + }\n + },\n +\n + /**\n + * Produces an IDENT or FUNCTION token based on the specified information. The\n + * first character is provided and the rest is read by the function to determine\n + * the correct token to create.\n + * @param {String} first The first character in the identifier.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method identOrFunctionToken\n + */\n + identOrFunctionToken: function(first, startLine, startCol){\n + var reader = this._reader,\n + ident = this.readName(first),\n + tt = Tokens.IDENT;\n +\n + //if there\'s a left paren immediately after, it\'s a URI or function\n + if (reader.peek() == "("){\n + ident += reader.read();\n + if (ident.toLowerCase() == "url("){\n + tt = Tokens.URI;\n + ident = this.readURI(ident);\n +\n + //didn\'t find a valid URL or there\'s no closing paren\n + if (ident.toLowerCase() == "url("){\n + tt = Tokens.FUNCTION;\n + }\n + } else {\n + tt = Tokens.FUNCTION;\n + }\n + } else if (reader.peek() == ":"){ //might be an IE function\n +\n + //IE-specific functions always being with progid:\n + if (ident.toLowerCase() == "progid"){\n + ident += reader.readTo("(");\n + tt = Tokens.IE_FUNCTION;\n + }\n + }\n +\n + return this.createToken(tt, ident, startLine, startCol);\n + },\n +\n + /**\n + * Produces an IMPORTANT_SYM or CHAR token based on the specified information. The\n + * first character is provided and the rest is read by the function to determine\n + * the correct token to create.\n + * @param {String} first The first character in the token.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method importantToken\n + */\n + importantToken: function(first, startLine, startCol){\n + var reader = this._reader,\n + important = first,\n + tt = Tokens.CHAR,\n + temp,\n + c;\n +\n + reader.mark();\n + c = reader.read();\n +\n + while(c){\n +\n + //there can be a comment in here\n + if (c == "/"){\n +\n + //if the next character isn\'t a star, then this isn\'t a valid !important token\n + if (reader.peek() != "*"){\n + break;\n + } else {\n + temp = this.readComment(c);\n + if (temp === ""){ //broken!\n + break;\n + }\n + }\n + } else if (isWhitespace(c)){\n + important += c + this.readWhitespace();\n + } else if (/i/i.test(c)){\n + temp = reader.readCount(8);\n + if (/mportant/i.test(temp)){\n + important += c + temp;\n + tt = Tokens.IMPORTANT_SYM;\n +\n + }\n + break; //we\'re done\n + } else {\n + break;\n + }\n +\n + c = reader.read();\n + }\n +\n + if (tt == Tokens.CHAR){\n + reader.reset();\n + return this.charToken(first, startLine, startCol);\n + } else {\n + return this.createToken(tt, important, startLine, startCol);\n + }\n +\n +\n + },\n +\n + /**\n + * Produces a NOT or CHAR token based on the specified information. The\n + * first character is provided and the rest is read by the function to determine\n + * the correct token to create.\n + * @param {String} first The first character in the token.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method notToken\n + */\n + notToken: function(first, startLine, startCol){\n + var reader = this._reader,\n + text = first;\n +\n + reader.mark();\n + text += reader.readCount(4);\n +\n + if (text.toLowerCase() == ":not("){\n + return this.createToken(Tokens.NOT, text, startLine, startCol);\n + } else {\n + reader.reset();\n + return this.charToken(first, startLine, startCol);\n + }\n + },\n +\n + /**\n + * Produces a number token based on the given character\n + * and location in the stream. This may return a token of\n + * NUMBER, EMS, EXS, LENGTH, ANGLE, TIME, FREQ, DIMENSION,\n + * or PERCENTAGE.\n + * @param {String} first The first character for the token.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method numberToken\n + */\n + numberToken: function(first, startLine, startCol){\n + var reader = this._reader,\n + value = this.readNumber(first),\n + ident,\n + tt = Tokens.NUMBER,\n + c = reader.peek();\n +\n + if (isIdentStart(c)){\n + ident = this.readName(reader.read());\n + value += ident;\n +\n + if (/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vm$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(ident)){\n + tt = Tokens.LENGTH;\n + } else if (/^deg|^rad$|^grad$/i.test(ident)){\n + tt = Tokens.ANGLE;\n + } else if (/^ms$|^s$/i.test(ident)){\n + tt = Tokens.TIME;\n + } else if (/^hz$|^khz$/i.test(ident)){\n + tt = Tokens.FREQ;\n + } else if (/^dpi$|^dpcm$/i.test(ident)){\n + tt = Tokens.RESOLUTION;\n + } else {\n + tt = Tokens.DIMENSION;\n + }\n +\n + } else if (c == "%"){\n + value += reader.read();\n + tt = Tokens.PERCENTAGE;\n + }\n +\n + return this.createToken(tt, value, startLine, startCol);\n + },\n +\n + /**\n + * Produces a string token based on the given character\n + * and location in the stream. Since strings may be indicated\n + * by single or double quotes, a failure to match starting\n + * and ending quotes results in an INVALID token being generated.\n + * The first character in the string is passed in and then\n + * the rest are read up to and including the final quotation mark.\n + * @param {String} first The first character in the string.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method stringToken\n + */\n + stringToken: function(first, startLine, startCol){\n + var delim = first,\n + string = first,\n + reader = this._reader,\n + prev = first,\n + tt = Tokens.STRING,\n + c = reader.read();\n +\n + while(c){\n + string += c;\n +\n + //if the delimiter is found with an escapement, we\'re done.\n + if (c == delim && prev != "\\\\"){\n + break;\n + }\n +\n + //if there\'s a newline without an escapement, it\'s an invalid string\n + if (isNewLine(reader.peek()) && c != "\\\\"){\n + tt = Tokens.INVALID;\n + break;\n + }\n +\n + //save previous and get next\n + prev = c;\n + c = reader.read();\n + }\n +\n + //if c is null, that means we\'re out of input and the string was never closed\n + if (c === null){\n + tt = Tokens.INVALID;\n + }\n +\n + return this.createToken(tt, string, startLine, startCol);\n + },\n +\n + unicodeRangeToken: function(first, startLine, startCol){\n + var reader = this._reader,\n + value = first,\n + temp,\n + tt = Tokens.CHAR;\n +\n + //then it should be a unicode range\n + if (reader.peek() == "+"){\n + reader.mark();\n + value += reader.read();\n + value += this.readUnicodeRangePart(true);\n +\n + //ensure there\'s an actual unicode range here\n + if (value.length == 2){\n + reader.reset();\n + } else {\n +\n + tt = Tokens.UNICODE_RANGE;\n +\n + //if there\'s a ? in the first part, there can\'t be a second part\n + if (value.indexOf("?") == -1){\n +\n + if (reader.peek() == "-"){\n + reader.mark();\n + temp = reader.read();\n + temp += this.readUnicodeRangePart(false);\n +\n + //if there\'s not another value, back up and just take the first\n + if (temp.length == 1){\n + reader.reset();\n + } else {\n + value += temp;\n + }\n + }\n +\n + }\n + }\n + }\n +\n + return this.createToken(tt, value, startLine, startCol);\n + },\n +\n + /**\n + * Produces a S token based on the specified information. Since whitespace\n + * may have multiple characters, this consumes all whitespace characters\n + * into a single token.\n + * @param {String} first The first character in the token.\n + * @param {int} startLine The beginning line for the character.\n + * @param {int} startCol The beginning column for the character.\n + * @return {Object} A token object.\n + * @method whitespaceToken\n + */\n + whitespaceToken: function(first, startLine, startCol){\n + var reader = this._reader,\n + value = first + this.readWhitespace();\n + return this.createToken(Tokens.S, value, startLine, startCol);\n + },\n +\n +\n +\n +\n + //-------------------------------------------------------------------------\n + // Methods to read values from the string stream\n + //-------------------------------------------------------------------------\n +\n + readUnicodeRangePart: function(allowQuestionMark){\n + var reader = this._reader,\n + part = "",\n + c = reader.peek();\n +\n + //first read hex digits\n + while(isHexDigit(c) && part.length < 6){\n + reader.read();\n + part += c;\n + c = reader.peek();\n + }\n +\n + //then read question marks if allowed\n + if (allowQuestionMark){\n + while(c == "?" && part.length < 6){\n + reader.read();\n + part += c;\n + c = reader.peek();\n + }\n + }\n +\n + //there can\'t be any other characters after this point\n +\n + return part;\n + },\n +\n + readWhitespace: function(){\n + var reader = this._reader,\n + whitespace = "",\n + c = reader.peek();\n +\n + while(isWhitespace(c)){\n + reader.read();\n + whitespace += c;\n + c = reader.peek();\n + }\n +\n + return whitespace;\n + },\n + readNumber: function(first){\n + var reader = this._reader,\n + number = first,\n + hasDot = (first == "."),\n + c = reader.peek();\n +\n +\n + while(c){\n + if (isDigit(c)){\n + number += reader.read();\n + } else if (c == "."){\n + if (hasDot){\n + break;\n + } else {\n + hasDot = true;\n + number += reader.read();\n + }\n + } else {\n + break;\n + }\n +\n + c = reader.peek();\n + }\n +\n + return number;\n + },\n + readString: function(){\n + var reader = this._reader,\n + delim = reader.read(),\n + string = delim,\n + prev = delim,\n + c = reader.peek();\n +\n + while(c){\n + c = reader.read();\n + string += c;\n +\n + //if the delimiter is found with an escapement, we\'re done.\n + if (c == delim && prev != "\\\\"){\n + break;\n + }\n +\n + //if there\'s a newline without an escapement, it\'s an invalid string\n + if (isNewLine(reader.peek()) && c != "\\\\"){\n + string = "";\n + break;\n + }\n +\n + //save previous and get next\n + prev = c;\n + c = reader.peek();\n + }\n +\n + //if c is null, that means we\'re out of input and the string was never closed\n + if (c === null){\n + string = "";\n + }\n +\n + return string;\n + },\n + readURI: function(first){\n + var reader = this._reader,\n + uri = first,\n + inner = "",\n + c = reader.peek();\n +\n + reader.mark();\n +\n + //skip whitespace before\n + while(c && isWhitespace(c)){\n + reader.read();\n + c = reader.peek();\n + }\n +\n + //it\'s a string\n + if (c == "\'" || c == "\\""){\n + inner = this.readString();\n + } else {\n + inner = this.readURL();\n + }\n +\n + c = reader.peek();\n +\n + //skip whitespace after\n + while(c && isWhitespace(c)){\n + reader.read();\n + c = reader.peek();\n + }\n +\n + //if there was no inner value or the next character isn\'t closing paren, it\'s not a URI\n + if (inner === "" || c != ")"){\n + uri = first;\n + reader.reset();\n + } else {\n + uri += inner + reader.read();\n + }\n +\n + return uri;\n + },\n + readURL: function(){\n + var reader = this._reader,\n + url = "",\n + c = reader.peek();\n +\n + //TODO: Check for escape and nonascii\n + while (/^[!#$%&\\\\*-~]$/.test(c)){\n + url += reader.read();\n + c = reader.peek();\n + }\n +\n + return url;\n +\n + },\n + readName: function(first){\n + var reader = this._reader,\n + ident = first || "",\n + c = reader.peek();\n +\n + while(true){\n + if (c == "\\\\"){\n + ident += this.readEscape(reader.read());\n + c = reader.peek();\n + } else if(c && isNameChar(c)){\n + ident += reader.read();\n + c = reader.peek();\n + } else {\n + break;\n + }\n + }\n +\n + return ident;\n + },\n +\n + readEscape: function(first){\n + var reader = this._reader,\n + cssEscape = first || "",\n + i = 0,\n + c = reader.peek();\n +\n + if (isHexDigit(c)){\n + do {\n + cssEscape += reader.read();\n + c = reader.peek();\n + } while(c && isHexDigit(c) && ++i < 6);\n + }\n +\n + if (cssEscape.length == 3 && /\\s/.test(c) ||\n + cssEscape.length == 7 || cssEscape.length == 1){\n + reader.read();\n + } else {\n + c = "";\n + }\n +\n + return cssEscape + c;\n + },\n +\n + readComment: function(first){\n + var reader = this._reader,\n + comment = first || "",\n + c = reader.read();\n +\n + if (c == "*"){\n + while(c){\n + comment += c;\n +\n + //look for end of comment\n + if (comment.length > 2 && c == "*" && reader.peek() == "/"){\n + comment += reader.read();\n + break;\n + }\n +\n + c = reader.read();\n + }\n +\n + return comment;\n + } else {\n + return "";\n + }\n +\n + }\n +});\n +\n +\n +var Tokens = [\n +\n + /*\n + * The following token names are defined in CSS3 Grammar: http://www.w3.org/TR/css3-syntax/#lexical\n + */\n +\n + //HTML-style comments\n + { name: "CDO"},\n + { name: "CDC"},\n +\n + //ignorables\n + { name: "S", whitespace: true/*, channel: "ws"*/},\n + { name: "COMMENT", comment: true, hide: true, channel: "comment" },\n +\n + //attribute equality\n + { name: "INCLUDES", text: "~="},\n + { name: "DASHMATCH", text: "|="},\n + { name: "PREFIXMATCH", text: "^="},\n + { name: "SUFFIXMATCH", text: "$="},\n + { name: "SUBSTRINGMATCH", text: "*="},\n +\n + //identifier types\n + { name: "STRING"},\n + { name: "IDENT"},\n + { name: "HASH"},\n +\n + //at-keywords\n + { name: "IMPORT_SYM", text: "@import"},\n + { name: "PAGE_SYM", text: "@page"},\n + { name: "MEDIA_SYM", text: "@media"},\n + { name: "FONT_FACE_SYM", text: "@font-face"},\n + { name: "CHARSET_SYM", text: "@charset"},\n + { name: "NAMESPACE_SYM", text: "@namespace"},\n + { name: "VIEWPORT_SYM", text: "@viewport"},\n + { name: "UNKNOWN_SYM" },\n + //{ name: "ATKEYWORD"},\n +\n + //CSS3 animations\n + { name: "KEYFRAMES_SYM", text: [ "@keyframes", "@-webkit-keyframes", "@-moz-keyframes", "@-o-keyframes" ] },\n +\n + //important symbol\n + { name: "IMPORTANT_SYM"},\n +\n + //measurements\n + { name: "LENGTH"},\n + { name: "ANGLE"},\n + { name: "TIME"},\n + { name: "FREQ"},\n + { name: "DIMENSION"},\n + { name: "PERCENTAGE"},\n + { name: "NUMBER"},\n +\n + //functions\n + { name: "URI"},\n + { name: "FUNCTION"},\n +\n + //Unicode ranges\n + { name: "UNICODE_RANGE"},\n +\n + /*\n + * The following token names are defined in CSS3 Selectors: http://www.w3.org/TR/css3-selectors/#selector-syntax\n + */\n +\n + //invalid string\n + { name: "INVALID"},\n +\n + //combinators\n + { name: "PLUS", text: "+" },\n + { name: "GREATER", text: ">"},\n + { name: "COMMA", text: ","},\n + { name: "TILDE", text: "~"},\n +\n + //modifier\n + { name: "NOT"},\n +\n + /*\n + * Defined in CSS3 Paged Media\n + */\n + { name: "TOPLEFTCORNER_SYM", text: "@top-left-corner"},\n + { name: "TOPLEFT_SYM", text: "@top-left"},\n + { name: "TOPCENTER_SYM", text: "@top-center"},\n + { name: "TOPRIGHT_SYM", text: "@top-right"},\n + { name: "TOPRIGHTCORNER_SYM", text: "@top-right-corner"},\n + { name: "BOTTOMLEFTCORNER_SYM", text: "@bottom-left-corner"},\n + { name: "BOTTOMLEFT_SYM", text: "@bottom-left"},\n + { name: "BOTTOMCENTER_SYM", text: "@bottom-center"},\n + { name: "BOTTOMRIGHT_SYM", text: "@bottom-right"},\n + { name: "BOTTOMRIGHTCORNER_SYM", text: "@bottom-right-corner"},\n + { name: "LEFTTOP_SYM", text: "@left-top"},\n + { name: "LEFTMIDDLE_SYM", text: "@left-middle"},\n + { name: "LEFTBOTTOM_SYM", text: "@left-bottom"},\n + { name: "RIGHTTOP_SYM", text: "@right-top"},\n + { name: "RIGHTMIDDLE_SYM", text: "@right-middle"},\n + { name: "RIGHTBOTTOM_SYM", text: "@right-bottom"},\n +\n + /*\n + * The following token names are defined in CSS3 Media Queries: http://www.w3.org/TR/css3-mediaqueries/#syntax\n + */\n + /*{ name: "MEDIA_ONLY", state: "media"},\n + { name: "MEDIA_NOT", state: "media"},\n + { name: "MEDIA_AND", state: "media"},*/\n + { name: "RESOLUTION", state: "media"},\n +\n + /*\n + * The following token names are not defined in any CSS specification but are used by the lexer.\n + */\n +\n + //not a real token, but useful for stupid IE filters\n + { name: "IE_FUNCTION" },\n +\n + //part of CSS3 grammar but not the Flex code\n + { name: "CHAR" },\n +\n + //TODO: Needed?\n + //Not defined as tokens, but might as well be\n + {\n + name: "PIPE",\n + text: "|"\n + },\n + {\n + name: "SLASH",\n + text: "/"\n + },\n + {\n + name: "MINUS",\n + text: "-"\n + },\n + {\n + name: "STAR",\n + text: "*"\n + },\n +\n + {\n + name: "LBRACE",\n + text: "{"\n + },\n + {\n + name: "RBRACE",\n + text: "}"\n + },\n + {\n + name: "LBRACKET",\n + text: "["\n + },\n + {\n + name: "RBRACKET",\n + text: "]"\n + },\n + {\n + name: "EQUALS",\n + text: "="\n + },\n + {\n + name: "COLON",\n + text: ":"\n + },\n + {\n + name: "SEMICOLON",\n + text: ";"\n + },\n +\n + {\n + name: "LPAREN",\n + text: "("\n + },\n + {\n + name: "RPAREN",\n + text: ")"\n + },\n + {\n + name: "DOT",\n + text: "."\n + }\n +];\n +\n +(function(){\n +\n + var nameMap = [],\n + typeMap = {};\n +\n + Tokens.UNKNOWN = -1;\n + Tokens.unshift({name:"EOF"});\n + for (var i=0, len = Tokens.length; i < len; i++){\n + nameMap.push(Tokens[i].name);\n + Tokens[Tokens[i].name] = i;\n + if (Tokens[i].text){\n + if (Tokens[i].text instanceof Array){\n + for (var j=0; j < Tokens[i].text.length; j++){\n + typeMap[Tokens[i].text[j]] = i;\n + }\n + } else {\n + typeMap[Tokens[i].text] = i;\n + }\n + }\n + }\n +\n + Tokens.name = function(tt){\n + return nameMap[tt];\n + };\n +\n + Tokens.type = function(c){\n + return typeMap[c] || -1;\n + };\n +\n +})();\n +\n +\n +\n +\n +//This file will likely change a lot! Very experimental!\n +/*global Properties, ValidationTypes, ValidationError, PropertyValueIterator */\n +var Validation = {\n +\n + validate: function(property, value){\n +\n + //normalize name\n + var name = property.toString().toLowerCase(),\n + parts = value.parts,\n + expression = new PropertyValueIterator(value),\n + spec = Properties[name],\n + part,\n + valid,\n + j, count,\n + msg,\n + types,\n + last,\n + literals,\n + max, multi, group;\n +\n + if (!spec) {\n + if (name.indexOf("-") !== 0){ //vendor prefixed are ok\n + throw new ValidationError("Unknown property \'" + property + "\'.", property.line, property.col);\n + }\n + } else if (typeof spec != "number"){\n +\n + //initialization\n + if (typeof spec == "string"){\n + if (spec.indexOf("||") > -1) {\n + this.groupProperty(spec, expression);\n + } else {\n + this.singleProperty(spec, expression, 1);\n + }\n +\n + } else if (spec.multi) {\n + this.multiProperty(spec.multi, expression, spec.comma, spec.max || Infinity);\n + } else if (typeof spec == "function") {\n + spec(expression);\n + }\n +\n + }\n +\n + },\n +\n + singleProperty: function(types, expression, max, partial) {\n +\n + var result = false,\n + value = expression.value,\n + count = 0,\n + part;\n +\n + while (expression.hasNext() && count < max) {\n + result = ValidationTypes.isAny(expression, types);\n + if (!result) {\n + break;\n + }\n + count++;\n + }\n +\n + if (!result) {\n + if (expression.hasNext() && !expression.isFirst()) {\n + part = expression.peek();\n + throw new ValidationError("Expected end of value but found \'" + part + "\'.", part.line, part.col);\n + } else {\n + throw new ValidationError("Expected (" + types + ") but found \'" + value + "\'.", value.line, value.col);\n + }\n + } else if (expression.hasNext()) {\n + part = expression.next();\n + throw new ValidationError("Expected end of value but found \'" + part + "\'.", part.line, part.col);\n + }\n +\n + },\n +\n + multiProperty: function (types, expression, comma, max) {\n +\n + var result = false,\n + value = expression.value,\n + count = 0,\n + sep = false,\n + part;\n +\n + while(expression.hasNext() && !result && count < max) {\n + if (ValidationTypes.isAny(expression, types)) {\n + count++;\n + if (!expression.hasNext()) {\n + result = true;\n +\n + } else if (comma) {\n + if (expression.peek() == ",") {\n + part = expression.next();\n + } else {\n + break;\n + }\n + }\n + } else {\n + break;\n +\n + }\n + }\n +\n + if (!result) {\n + if (expression.hasNext() && !expression.isFirst()) {\n + part = expression.peek();\n + throw new ValidationError("Expected end of value but found \'" + part + "\'.", part.line, part.col);\n + } else {\n + part = expression.previous();\n + if (comma && part == ",") {\n + throw new ValidationError("Expected end of value but found \'" + part + "\'.", part.line, part.col);\n + } else {\n + throw new ValidationError("Expected (" + types + ") but found \'" + value + "\'.", value.line, value.col);\n + }\n + }\n +\n + } else if (expression.hasNext()) {\n + part = expression.next();\n + throw new ValidationError("Expected end of value but found \'" + part + "\'.", part.line, part.col);\n + }\n +\n + },\n +\n + groupProperty: function (types, expression, comma) {\n +\n + var result = false,\n + value = expression.value,\n + typeCount = types.split("||").length,\n + groups = { count: 0 },\n + partial = false,\n + name,\n + part;\n +\n + while(expression.hasNext() && !result) {\n + name = ValidationTypes.isAnyOfGroup(expression, types);\n + if (name) {\n +\n + //no dupes\n + if (groups[name]) {\n + break;\n + } else {\n + groups[name] = 1;\n + groups.count++;\n + partial = true;\n +\n + if (groups.count == typeCount || !expression.hasNext()) {\n + result = true;\n + }\n + }\n + } else {\n + break;\n + }\n + }\n +\n + if (!result) {\n + if (partial && expression.hasNext()) {\n + part = expression.peek();\n + throw new ValidationError("Expected end of value but found \'" + part + "\'.", part.line, part.col);\n + } else {\n + throw new ValidationError("Expected (" + types + ") but found \'" + value + "\'.", value.line, value.col);\n + }\n + } else if (expression.hasNext()) {\n + part = expression.next();\n + throw new ValidationError("Expected end of value but found \'" + part + "\'.", part.line, part.col);\n + }\n + }\n +\n +\n +\n +};\n +/**\n + * Type to use when a validation error occurs.\n + * @class ValidationError\n + * @namespace parserlib.util\n + * @constructor\n + * @param {String} message The error message.\n + * @param {int} line The line at which the error occurred.\n + * @param {int} col The column at which the error occurred.\n + */\n +function ValidationError(message, line, col){\n +\n + /**\n + * The column at which the error occurred.\n + * @type int\n + * @property col\n + */\n + this.col = col;\n +\n + /**\n + * The line at which the error occurred.\n + * @type int\n + * @property line\n + */\n + this.line = line;\n +\n + /**\n + * The text representation of the unit.\n + * @type String\n + * @property text\n + */\n + this.message = message;\n +\n +}\n +\n +//inherit from Error\n +ValidationError.prototype = new Error();\n +//This file will likely change a lot! Very experimental!\n +/*global Properties, Validation, ValidationError, PropertyValueIterator, console*/\n +var ValidationTypes = {\n +\n + isLiteral: function (part, literals) {\n + var text = part.text.toString().toLowerCase(),\n + args = literals.split(" | "),\n + i, len, found = false;\n +\n + for (i=0,len=args.length; i < len && !found; i++){\n + if (text == args[i].toLowerCase()){\n + found = true;\n + }\n + }\n +\n + return found;\n + },\n +\n + isSimple: function(type) {\n + return !!this.simple[type];\n + },\n +\n + isComplex: function(type) {\n + return !!this.complex[type];\n + },\n +\n + /**\n + * Determines if the next part(s) of the given expression\n + * are any of the given types.\n + */\n + isAny: function (expression, types) {\n + var args = types.split(" | "),\n + i, len, found = false;\n +\n + for (i=0,len=args.length; i < len && !found && expression.hasNext(); i++){\n + found = this.isType(expression, args[i]);\n + }\n +\n + return found;\n + },\n +\n + /**\n + * Determines if the next part(s) of the given expression\n + * are one of a group.\n + */\n + isAnyOfGroup: function(expression, types) {\n + var args = types.split(" || "),\n + i, len, found = false;\n +\n + for (i=0,len=args.length; i < len && !found; i++){\n + found = this.isType(expression, args[i]);\n + }\n +\n + return found ? args[i-1] : false;\n + },\n +\n + /**\n + * Determines if the next part(s) of the given expression\n + * are of a given type.\n + */\n + isType: function (expression, type) {\n + var part = expression.peek(),\n + result = false;\n +\n + if (type.charAt(0) != "<") {\n + result = this.isLiteral(part, type);\n + if (result) {\n + expression.next();\n + }\n + } else if (this.simple[type]) {\n + result = this.simple[type](part);\n + if (result) {\n + expression.next();\n + }\n + } else {\n + result = this.complex[type](expression);\n + }\n +\n + return result;\n + },\n +\n +\n +\n + simple: {\n +\n + "<absolute-size>": function(part){\n + return ValidationTypes.isLiteral(part, "xx-small | x-small | small | medium | large | x-large | xx-large");\n + },\n +\n + "<attachment>": function(part){\n + return ValidationTypes.isLiteral(part, "scroll | fixed | local");\n + },\n +\n + "<attr>": function(part){\n + return part.type == "function" && part.name == "attr";\n + },\n +\n + "<bg-image>": function(part){\n + return this["<image>"](part) || this["<gradient>"](part) || part == "none";\n + },\n +\n + "<gradient>": function(part) {\n + return part.type == "function" && /^(?:\\-(?:ms|moz|o|webkit)\\-)?(?:repeating\\-)?(?:radial\\-|linear\\-)?gradient/i.test(part);\n + },\n +\n + "<box>": function(part){\n + return ValidationTypes.isLiteral(part, "padding-box | border-box | content-box");\n + },\n +\n + "<content>": function(part){\n + return part.type == "function" && part.name == "content";\n + },\n +\n + "<relative-size>": function(part){\n + return ValidationTypes.isLiteral(part, "smaller | larger");\n + },\n +\n + //any identifier\n + "<ident>": function(part){\n + return part.type == "identifier";\n + },\n +\n + "<length>": function(part){\n + if (part.type == "function" && /^(?:\\-(?:ms|moz|o|webkit)\\-)?calc/i.test(part)){\n + return true;\n + }else{\n + return part.type == "length" || part.type == "number" || part.type == "integer" || part == "0";\n + }\n + },\n +\n + "<color>": function(part){\n + return part.type == "color" || part == "transparent";\n + },\n +\n + "<number>": function(part){\n + return part.type == "number" || this["<integer>"](part);\n + },\n +\n + "<integer>": function(part){\n + return part.type == "integer";\n + },\n +\n + "<line>": function(part){\n + return part.type == "integer";\n + },\n +\n + "<angle>": function(part){\n + return part.type == "angle";\n + },\n +\n + "<uri>": function(part){\n + return part.type == "uri";\n + },\n +\n + "<image>": function(part){\n + return this["<uri>"](part);\n + },\n +\n + "<percentage>": function(part){\n + return part.type == "percentage" || part == "0";\n + },\n +\n + "<border-width>": function(part){\n + return this["<length>"](part) || ValidationTypes.isLiteral(part, "thin | medium | thick");\n + },\n +\n + "<border-style>": function(part){\n + return ValidationTypes.isLiteral(part, "none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset");\n + },\n +\n + "<margin-width>": function(part){\n + return this["<length>"](part) || this["<percentage>"](part) || ValidationTypes.isLiteral(part, "auto");\n + },\n +\n + "<padding-width>": function(part){\n + return this["<length>"](part) || this["<percentage>"](part);\n + },\n +\n + "<shape>": function(part){\n + return part.type == "function" && (part.name == "rect" || part.name == "inset-rect");\n + },\n +\n + "<time>": function(part) {\n + return part.type == "time";\n + }\n + },\n +\n + complex: {\n +\n + "<bg-position>": function(expression){\n + var types = this,\n + result = false,\n + numeric = "<percentage> | <length>",\n + xDir = "left | right",\n + yDir = "top | bottom",\n + count = 0,\n + hasNext = function() {\n + return expression.hasNext() && expression.peek() != ",";\n + };\n +\n + while (expression.peek(count) && expression.peek(count) != ",") {\n + count++;\n + }\n +\n +/*\n +<position> = [\n + [ left | center | right | top | bottom | <percentage> | <length> ]\n +|\n + [ left | center | right | <percentage> | <length> ]\n + [ top | center | bottom | <percentage> | <length> ]\n +|\n + [ center | [ left | right ] [ <percentage> | <length> ]? ] &&\n + [ center | [ top | bottom ] [ <percentage> | <length> ]? ]\n +]\n +*/\n +\n + if (count < 3) {\n + if (ValidationTypes.isAny(expression, xDir + " | center | " + numeric)) {\n + result = true;\n + ValidationTypes.isAny(expression, yDir + " | center | " + numeric);\n + } else if (ValidationTypes.isAny(expression, yDir)) {\n + result = true;\n + ValidationTypes.isAny(expression, xDir + " | center");\n + }\n + } else {\n + if (ValidationTypes.isAny(expression, xDir)) {\n + if (ValidationTypes.isAny(expression, yDir)) {\n + result = true;\n + ValidationTypes.isAny(expression, numeric);\n + } else if (ValidationTypes.isAny(expression, numeric)) {\n + if (ValidationTypes.isAny(expression, yDir)) {\n + result = true;\n + ValidationTypes.isAny(expression, numeric);\n + } else if (ValidationTypes.isAny(expression, "center")) {\n + result = true;\n + }\n + }\n + } else if (ValidationTypes.isAny(expression, yDir)) {\n + if (ValidationTypes.isAny(expression, xDir)) {\n + result = true;\n + ValidationTypes.isAny(expression, numeric);\n + } else if (ValidationTypes.isAny(expression, numeric)) {\n + if (ValidationTypes.isAny(expression, xDir)) {\n + result = true;\n + ValidationTypes.isAny(expression, numeric);\n + } else if (ValidationTypes.isAny(expression, "center")) {\n + result = true;\n + }\n + }\n + } else if (ValidationTypes.isAny(expression, "center")) {\n + if (ValidationTypes.isAny(expression, xDir + " | " + yDir)) {\n + result = true;\n + ValidationTypes.isAny(expression, numeric);\n + }\n + }\n + }\n +\n + return result;\n + },\n +\n + "<bg-size>": function(expression){\n + //<bg-size> = [ <length> | <percentage> | auto ]{1,2} | cover | contain\n + var types = this,\n + result = false,\n + numeric = "<percentage> | <length> | auto",\n + part,\n + i, len;\n +\n + if (ValidationTypes.isAny(expression, "cover | contain")) {\n + result = true;\n + } else if (ValidationTypes.isAny(expression, numeric)) {\n + result = true;\n + ValidationTypes.isAny(expression, numeric);\n + }\n +\n + return result;\n + },\n +\n + "<repeat-style>": function(expression){\n + //repeat-x | repeat-y | [repeat | space | round | no-repeat]{1,2}\n + var result = false,\n + values = "repeat | space | round | no-repeat",\n + part;\n +\n + if (expression.hasNext()){\n + part = expression.next();\n +\n + if (ValidationTypes.isLiteral(part, "repeat-x | repeat-y")) {\n + result = true;\n + } else if (ValidationTypes.isLiteral(part, values)) {\n + result = true;\n +\n + if (expression.hasNext() && ValidationTypes.isLiteral(expression.peek(), values)) {\n + expression.next();\n + }\n + }\n + }\n +\n + return result;\n +\n + },\n +\n + "<shadow>": function(expression) {\n + //inset? && [ <length>{2,4} && <color>? ]\n + var result = false,\n + count = 0,\n + inset = false,\n + color = false,\n + part;\n +\n + if (expression.hasNext()) {\n +\n + if (ValidationTypes.isAny(expression, "inset")){\n + inset = true;\n + }\n +\n + if (ValidationTypes.isAny(expression, "<color>")) {\n + color = true;\n + }\n +\n + while (ValidationTypes.isAny(expression, "<length>") && count < 4) {\n + count++;\n + }\n +\n +\n + if (expression.hasNext()) {\n + if (!color) {\n + ValidationTypes.isAny(expression, "<color>");\n + }\n +\n + if (!inset) {\n + ValidationTypes.isAny(expression, "inset");\n + }\n +\n + }\n +\n + result = (count >= 2 && count <= 4);\n +\n + }\n +\n + return result;\n + },\n +\n + "<x-one-radius>": function(expression) {\n + //[ <length> | <percentage> ] [ <length> | <percentage> ]?\n + var result = false,\n + simple = "<length> | <percentage> | inherit";\n +\n + if (ValidationTypes.isAny(expression, simple)){\n + result = true;\n + ValidationTypes.isAny(expression, simple);\n + }\n +\n + return result;\n + }\n + }\n +};\n +\n +\n +\n +parserlib.css = {\n +Colors :Colors,\n +Combinator :Combinator,\n +Parser :Parser,\n +PropertyName :PropertyName,\n +PropertyValue :PropertyValue,\n +PropertyValuePart :PropertyValuePart,\n +MediaFeature :MediaFeature,\n +MediaQuery :MediaQuery,\n +Selector :Selector,\n +SelectorPart :SelectorPart,\n +SelectorSubPart :SelectorSubPart,\n +Specificity :Specificity,\n +TokenStream :TokenStream,\n +Tokens :Tokens,\n +ValidationError :ValidationError\n +};\n +})();\n +\n +\n +\n +\n +(function(){\n +for(var prop in parserlib){\n +exports[prop] = parserlib[prop];\n +}\n +})();\n +\n +\n +/**\n + * Main CSSLint object.\n + * @class CSSLint\n + * @static\n + * @extends parserlib.util.EventTarget\n + */\n +/*global parserlib, Reporter*/\n +var CSSLint = (function(){\n +\n + var rules = [],\n + formatters = [],\n + embeddedRuleset = /\\/\\*csslint([^\\*]*)\\*\\//,\n + api = new parserlib.util.EventTarget();\n +\n + api.version = "0.10.0";\n +\n + //-------------------------------------------------------------------------\n + // Rule Management\n + //-------------------------------------------------------------------------\n +\n + /**\n + * Adds a new rule to the engine.\n + * @param {Object} rule The rule to add.\n + * @method addRule\n + */\n + api.addRule = function(rule){\n + rules.push(rule);\n + rules[rule.id] = rule;\n + };\n +\n + /**\n + * Clears all rule from the engine.\n + * @method clearRules\n + */\n + api.clearRules = function(){\n + rules = [];\n + };\n +\n + /**\n + * Returns the rule objects.\n + * @return An array of rule objects.\n + * @method getRules\n + */\n + api.getRules = function(){\n + return [].concat(rules).sort(function(a,b){\n + return a.id > b.id ? 1 : 0;\n + });\n + };\n +\n + /**\n + * Returns a ruleset configuration object with all current rules.\n + * @return A ruleset object.\n + * @method getRuleset\n + */\n + api.getRuleset = function() {\n + var ruleset = {},\n + i = 0,\n + len = rules.length;\n +\n + while (i < len){\n + ruleset[rules[i++].id] = 1; //by default, everything is a warning\n + }\n +\n + return ruleset;\n + };\n +\n + /**\n + * Returns a ruleset object based on embedded rules.\n + * @param {String} text A string of css containing embedded rules.\n + * @param {Object} ruleset A ruleset object to modify.\n + * @return {Object} A ruleset object.\n + * @method getEmbeddedRuleset\n + */\n + function applyEmbeddedRuleset(text, ruleset){\n + var valueMap,\n + embedded = text && text.match(embeddedRuleset),\n + rules = embedded && embedded[1];\n +\n + if (rules) {\n + valueMap = {\n + "true": 2, // true is error\n + "": 1, // blank is warning\n + "false": 0, // false is ignore\n +\n + "2": 2, // explicit error\n + "1": 1, // explicit warning\n + "0": 0 // explicit ignore\n + };\n +\n + rules.toLowerCase().split(",").forEach(function(rule){\n + var pair = rule.split(":"),\n + property = pair[0] || "",\n + value = pair[1] || "";\n +\n + ruleset[property.trim()] = valueMap[value.trim()];\n + });\n + }\n +\n + return ruleset;\n + }\n +\n + //-------------------------------------------------------------------------\n + // Formatters\n + //-------------------------------------------------------------------------\n +\n + /**\n + * Adds a new formatter to the engine.\n + * @param {Object} formatter The formatter to add.\n + * @method addFormatter\n + */\n + api.addFormatter = function(formatter) {\n + // formatters.push(formatter);\n + formatters[formatter.id] = formatter;\n + };\n +\n + /**\n + * Retrieves a formatter for use.\n + * @param {String} formatId The name of the format to retrieve.\n + * @return {Object} The formatter or undefined.\n + * @method getFormatter\n + */\n + api.getFormatter = function(formatId){\n + return formatters[formatId];\n + };\n +\n + /**\n + * Formats the results in a particular format for a single file.\n + * @param {Object} result The results returned from CSSLint.verify().\n + * @param {String} filename The filename for which the results apply.\n + * @param {String} formatId The name of the formatter to use.\n + * @param {Object} options (Optional) for special output handling.\n + * @return {String} A formatted string for the results.\n + * @method format\n + */\n + api.format = function(results, filename, formatId, options) {\n + var formatter = this.getFormatter(formatId),\n + result = null;\n +\n + if (formatter){\n + result = formatter.startFormat();\n + result += formatter.formatResults(results, filename, options || {});\n + result += formatter.endFormat();\n + }\n +\n + return result;\n + };\n +\n + /**\n + * Indicates if the given format is supported.\n + * @param {String} formatId The ID of the format to check.\n + * @return {Boolean} True if the format exists, false if not.\n + * @method hasFormat\n + */\n + api.hasFormat = function(formatId){\n + return formatters.hasOwnProperty(formatId);\n + };\n +\n + //-------------------------------------------------------------------------\n + // Verification\n + //-------------------------------------------------------------------------\n +\n + /**\n + * Starts the verification process for the given CSS text.\n + * @param {String} text The CSS text to verify.\n + * @param {Object} ruleset (Optional) List of rules to apply. If null, then\n + * all rules are used. If a rule has a value of 1 then it\'s a warning,\n + * a value of 2 means it\'s an error.\n + * @return {Object} Results of the verification.\n + * @method verify\n + */\n + api.verify = function(text, ruleset){\n +\n + var i = 0,\n + len = rules.length,\n + reporter,\n + lines,\n + report,\n + parser = new parserlib.css.Parser({ starHack: true, ieFilters: true,\n + underscoreHack: true, strict: false });\n +\n + // normalize line endings\n + lines = text.replace(/\\n\\r?/g, "$split$").split(\'$split$\');\n +\n + if (!ruleset){\n + ruleset = this.getRuleset();\n + }\n +\n + if (embeddedRuleset.test(text)){\n + ruleset = applyEmbeddedRuleset(text, ruleset);\n + }\n +\n + reporter = new Reporter(lines, ruleset);\n +\n + ruleset.errors = 2; //always report parsing errors as errors\n + for (i in ruleset){\n + if(ruleset.hasOwnProperty(i) && ruleset[i]){\n + if (rules[i]){\n + rules[i].init(parser, reporter);\n + }\n + }\n + }\n +\n +\n + //capture most horrible error type\n + try {\n + parser.parse(text);\n + } catch (ex) {\n + reporter.error("Fatal error, cannot continue: " + ex.message, ex.line, ex.col, {});\n + }\n +\n + report = {\n + messages : reporter.messages,\n + stats : reporter.stats,\n + ruleset : reporter.ruleset\n + };\n +\n + //sort by line numbers, rollups at the bottom\n + report.messages.sort(function (a, b){\n + if (a.rollup && !b.rollup){\n + return 1;\n + } else if (!a.rollup && b.rollup){\n + return -1;\n + } else {\n + return a.line - b.line;\n + }\n + });\n +\n + return report;\n + };\n +\n + //-------------------------------------------------------------------------\n + // Publish the API\n + //-------------------------------------------------------------------------\n +\n + return api;\n +\n +})();\n +\n +/*global CSSLint*/\n +/**\n + * An instance of Report is used to report results of the\n + * verification back to the main API.\n + * @class Reporter\n + * @constructor\n + * @param {String[]} lines The text lines of the source.\n + * @param {Object} ruleset The set of rules to work with, including if\n + * they are errors or warnings.\n + */\n +function Reporter(lines, ruleset){\n +\n + /**\n + * List of messages being reported.\n + * @property messages\n + * @type String[]\n + */\n + this.messages = [];\n +\n + /**\n + * List of statistics being reported.\n + * @property stats\n + * @type String[]\n + */\n + this.stats = [];\n +\n + /**\n + * Lines of code being reported on. Used to provide contextual information\n + * for messages.\n + * @property lines\n + * @type String[]\n + */\n + this.lines = lines;\n +\n + /**\n + * Information about the rules. Used to determine whether an issue is an\n + * error or warning.\n + * @property ruleset\n + * @type Object\n + */\n + this.ruleset = ruleset;\n +}\n +\n +Reporter.prototype = {\n +\n + //restore constructor\n + constructor: Reporter,\n +\n + /**\n + * Report an error.\n + * @param {String} message The message to store.\n + * @param {int} line The line number.\n + * @param {int} col The column number.\n + * @param {Object} rule The rule this message relates to.\n + * @method error\n + */\n + error: function(message, line, col, rule){\n + this.messages.push({\n + type : "error",\n + line : line,\n + col : col,\n + message : message,\n + evidence: this.lines[line-1],\n + rule : rule || {}\n + });\n + },\n +\n + /**\n + * Report an warning.\n + * @param {String} message The message to store.\n + * @param {int} line The line number.\n + * @param {int} col The column number.\n + * @param {Object} rule The rule this message relates to.\n + * @method warn\n + * @deprecated Use report instead.\n + */\n + warn: function(message, line, col, rule){\n + this.report(message, line, col, rule);\n + },\n +\n + /**\n + * Report an issue.\n + * @param {String} message The message to store.\n + * @param {int} line The line number.\n + * @param {int} col The column number.\n + * @param {Object} rule The rule this message relates to.\n + * @method report\n + */\n + report: function(message, line, col, rule){\n + this.messages.push({\n + type : this.ruleset[rule.id] == 2 ? "error" : "warning",\n + line : line,\n + col : col,\n + message : message,\n + evidence: this.lines[line-1],\n + rule : rule\n + });\n + },\n +\n + /**\n + * Report some informational text.\n + * @param {String} message The message to store.\n + * @param {int} line The line number.\n + * @param {int} col The column number.\n + * @param {Object} rule The rule this message relates to.\n + * @method info\n + */\n + info: function(message, line, col, rule){\n + this.messages.push({\n + type : "info",\n + line : line,\n + col : col,\n + message : message,\n + evidence: this.lines[line-1],\n + rule : rule\n + });\n + },\n +\n + /**\n + * Report some rollup error information.\n + * @param {String} message The message to store.\n + * @param {Object} rule The rule this message relates to.\n + * @method rollupError\n + */\n + rollupError: function(message, rule){\n + this.messages.push({\n + type : "error",\n + rollup : true,\n + message : message,\n + rule : rule\n + });\n + },\n +\n + /**\n + * Report some rollup warning information.\n + * @param {String} message The message to store.\n + * @param {Object} rule The rule this message relates to.\n + * @method rollupWarn\n + */\n + rollupWarn: function(message, rule){\n + this.messages.push({\n + type : "warning",\n + rollup : true,\n + message : message,\n + rule : rule\n + });\n + },\n +\n + /**\n + * Report a statistic.\n + * @param {String} name The name of the stat to store.\n + * @param {Variant} value The value of the stat.\n + * @method stat\n + */\n + stat: function(name, value){\n + this.stats[name] = value;\n + }\n +};\n +\n +//expose for testing purposes\n +CSSLint._Reporter = Reporter;\n +\n +/*global CSSLint*/\n +\n +/*\n + * Utility functions that make life easier.\n + */\n +CSSLint.Util = {\n + /*\n + * Adds all properties from supplier onto receiver,\n + * overwriting if the same name already exists on\n + * reciever.\n + * @param {Object} The object to receive the properties.\n + * @param {Object} The object to provide the properties.\n + * @return {Object} The receiver\n + */\n + mix: function(receiver, supplier){\n + var prop;\n +\n + for (prop in supplier){\n + if (supplier.hasOwnProperty(prop)){\n + receiver[prop] = supplier[prop];\n + }\n + }\n +\n + return prop;\n + },\n +\n + /*\n + * Polyfill for array indexOf() method.\n + * @param {Array} values The array to search.\n + * @param {Variant} value The value to search for.\n + * @return {int} The index of the value if found, -1 if not.\n + */\n + indexOf: function(values, value){\n + if (values.indexOf){\n + return values.indexOf(value);\n + } else {\n + for (var i=0, len=values.length; i < len; i++){\n + if (values[i] === value){\n + return i;\n + }\n + }\n + return -1;\n + }\n + },\n +\n + /*\n + * Polyfill for array forEach() method.\n + * @param {Array} values The array to operate on.\n + * @param {Function} func The function to call on each item.\n + * @return {void}\n + */\n + forEach: function(values, func) {\n + if (values.forEach){\n + return values.forEach(func);\n + } else {\n + for (var i=0, len=values.length; i < len; i++){\n + func(values[i], i, values);\n + }\n + }\n + }\n +};\n +/*global CSSLint*/\n +/*\n + * Rule: Don\'t use adjoining classes (.foo.bar).\n + */\n +CSSLint.addRule({\n +\n + //rule information\n + id: "adjoining-classes",\n + name: "Disallow adjoining classes",\n + desc: "Don\'t use adjoining classes.",\n + browsers: "IE6",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n + parser.addListener("startrule", function(event){\n + var selectors = event.selectors,\n + selector,\n + part,\n + modifier,\n + classCount,\n + i, j, k;\n +\n + for (i=0; i < selectors.length; i++){\n + selector = selectors[i];\n + for (j=0; j < selector.parts.length; j++){\n + part = selector.parts[j];\n + if (part.type == parser.SELECTOR_PART_TYPE){\n + classCount = 0;\n + for (k=0; k < part.modifiers.length; k++){\n + modifier = part.modifiers[k];\n + if (modifier.type == "class"){\n + classCount++;\n + }\n + if (classCount > 1){\n + reporter.report("Don\'t use adjoining classes.", part.line, part.col, rule);\n + }\n + }\n + }\n + }\n + }\n + });\n + }\n +\n +});\n +/*global CSSLint*/\n +\n +/*\n + * Rule: Don\'t use width or height when using padding or border.\n + */\n +CSSLint.addRule({\n +\n + //rule information\n + id: "box-model",\n + name: "Beware of broken box size",\n + desc: "Don\'t use width or height when using padding or border.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + widthProperties = {\n + border: 1,\n + "border-left": 1,\n + "border-right": 1,\n + padding: 1,\n + "padding-left": 1,\n + "padding-right": 1\n + },\n + heightProperties = {\n + border: 1,\n + "border-bottom": 1,\n + "border-top": 1,\n + padding: 1,\n + "padding-bottom": 1,\n + "padding-top": 1\n + },\n + properties,\n + boxSizing = false;\n +\n + function startRule(){\n + properties = {};\n + boxSizing = false;\n + }\n +\n + function endRule(){\n + var prop, value;\n +\n + if (!boxSizing) {\n + if (properties.height){\n + for (prop in heightProperties){\n + if (heightProperties.hasOwnProperty(prop) && properties[prop]){\n + value = properties[prop].value;\n + //special case for padding\n + if (!(prop == "padding" && value.parts.length === 2 && value.parts[0].value === 0)){\n + reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);\n + }\n + }\n + }\n + }\n +\n + if (properties.width){\n + for (prop in widthProperties){\n + if (widthProperties.hasOwnProperty(prop) && properties[prop]){\n + value = properties[prop].value;\n +\n + if (!(prop == "padding" && value.parts.length === 2 && value.parts[1].value === 0)){\n + reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);\n + }\n + }\n + }\n + }\n + }\n + }\n +\n + parser.addListener("startrule", startRule);\n + parser.addListener("startfontface", startRule);\n + parser.addListener("startpage", startRule);\n + parser.addListener("startpagemargin", startRule);\n + parser.addListener("startkeyframerule", startRule);\n +\n + parser.addListener("property", function(event){\n + var name = event.property.text.toLowerCase();\n +\n + if (heightProperties[name] || widthProperties[name]){\n + if (!/^0\\S*$/.test(event.value) && !(name == "border" && event.value == "none")){\n + properties[name] = { line: event.property.line, col: event.property.col, value: event.value };\n + }\n + } else {\n + if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)){\n + properties[name] = 1;\n + } else if (name == "box-sizing") {\n + boxSizing = true;\n + }\n + }\n +\n + });\n +\n + parser.addListener("endrule", endRule);\n + parser.addListener("endfontface", endRule);\n + parser.addListener("endpage", endRule);\n + parser.addListener("endpagemargin", endRule);\n + parser.addListener("endkeyframerule", endRule);\n + }\n +\n +});\n +/*global CSSLint*/\n +\n +/*\n + * Rule: box-sizing doesn\'t work in IE6 and IE7.\n + */\n +CSSLint.addRule({\n +\n + //rule information\n + id: "box-sizing",\n + name: "Disallow use of box-sizing",\n + desc: "The box-sizing properties isn\'t supported in IE6 and IE7.",\n + browsers: "IE6, IE7",\n + tags: ["Compatibility"],\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + parser.addListener("property", function(event){\n + var name = event.property.text.toLowerCase();\n +\n + if (name == "box-sizing"){\n + reporter.report("The box-sizing property isn\'t supported in IE6 and IE7.", event.line, event.col, rule);\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: Use the bulletproof @font-face syntax to avoid 404\'s in old IE\n + * (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax)\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "bulletproof-font-face",\n + name: "Use the bulletproof @font-face syntax",\n + desc: "Use the bulletproof @font-face syntax to avoid 404\'s in old IE (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax).",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + count = 0,\n + fontFaceRule = false,\n + firstSrc = true,\n + ruleFailed = false,\n + line, col;\n +\n + // Mark the start of a @font-face declaration so we only test properties inside it\n + parser.addListener("startfontface", function(event){\n + fontFaceRule = true;\n + });\n +\n + parser.addListener("property", function(event){\n + // If we aren\'t inside an @font-face declaration then just return\n + if (!fontFaceRule) {\n + return;\n + }\n +\n + var propertyName = event.property.toString().toLowerCase(),\n + value = event.value.toString();\n +\n + // Set the line and col numbers for use in the endfontface listener\n + line = event.line;\n + col = event.col;\n +\n + // This is the property that we care about, we can ignore the rest\n + if (propertyName === \'src\') {\n + var regex = /^\\s?url\\([\'"].+\\.eot\\?.*[\'"]\\)\\s*format\\([\'"]embedded-opentype[\'"]\\).*$/i;\n +\n + // We need to handle the advanced syntax with two src properties\n + if (!value.match(regex) && firstSrc) {\n + ruleFailed = true;\n + firstSrc = false;\n + } else if (value.match(regex) && !firstSrc) {\n + ruleFailed = false;\n + }\n + }\n +\n +\n + });\n +\n + // Back to normal rules that we don\'t need to test\n + parser.addListener("endfontface", function(event){\n + fontFaceRule = false;\n +\n + if (ruleFailed) {\n + reporter.report("@font-face declaration doesn\'t follow the fontspring bulletproof syntax.", line, col, rule);\n + }\n + });\n + }\n +});\n +/*\n + * Rule: Include all compatible vendor prefixes to reach a wider\n + * range of users.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "compatible-vendor-prefixes",\n + name: "Require compatible vendor prefixes",\n + desc: "Include all compatible vendor prefixes to reach a wider range of users.",\n + browsers: "All",\n +\n + //initialization\n + init: function (parser, reporter) {\n + var rule = this,\n + compatiblePrefixes,\n + properties,\n + prop,\n + variations,\n + prefixed,\n + i,\n + len,\n + inKeyFrame = false,\n + arrayPush = Array.prototype.push,\n + applyTo = [];\n +\n + // See http://peter.sh/experiments/vendor-prefixed-css-property-overview/ for details\n + compatiblePrefixes = {\n + "animation" : "webkit moz",\n + "animation-delay" : "webkit moz",\n + "animation-direction" : "webkit moz",\n + "animation-duration" : "webkit moz",\n + "animation-fill-mode" : "webkit moz",\n + "animation-iteration-count" : "webkit moz",\n + "animation-name" : "webkit moz",\n + "animation-play-state" : "webkit moz",\n + "animation-timing-function" : "webkit moz",\n + "appearance" : "webkit moz",\n + "border-end" : "webkit moz",\n + "border-end-color" : "webkit moz",\n + "border-end-style" : "webkit moz",\n + "border-end-width" : "webkit moz",\n + "border-image" : "webkit moz o",\n + "border-radius" : "webkit",\n + "border-start" : "webkit moz",\n + "border-start-color" : "webkit moz",\n + "border-start-style" : "webkit moz",\n + "border-start-width" : "webkit moz",\n + "box-align" : "webkit moz ms",\n + "box-direction" : "webkit moz ms",\n + "box-flex" : "webkit moz ms",\n + "box-lines" : "webkit ms",\n + "box-ordinal-group" : "webkit moz ms",\n + "box-orient" : "webkit moz ms",\n + "box-pack" : "webkit moz ms",\n + "box-sizing" : "webkit moz",\n + "box-shadow" : "webkit moz",\n + "column-count" : "webkit moz ms",\n + "column-gap" : "webkit moz ms",\n + "column-rule" : "webkit moz ms",\n + "column-rule-color" : "webkit moz ms",\n + "column-rule-style" : "webkit moz ms",\n + "column-rule-width" : "webkit moz ms",\n + "column-width" : "webkit moz ms",\n + "hyphens" : "epub moz",\n + "line-break" : "webkit ms",\n + "margin-end" : "webkit moz",\n + "margin-start" : "webkit moz",\n + "marquee-speed" : "webkit wap",\n + "marquee-style" : "webkit wap",\n + "padding-end" : "webkit moz",\n + "padding-start" : "webkit moz",\n + "tab-size" : "moz o",\n + "text-size-adjust" : "webkit ms",\n + "transform" + +]]></string> </value> + </item> + <item> + <key> <string>next</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent> + </value> + </item> + </dictionary> + </pickle> + </record> + <record id="5" aka="AAAAAAAAAAU="> + <pickle> + <global name="Pdata" module="OFS.Image"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>data</string> </key> + <value> <string>: "webkit moz ms o",\n + "transform-origin" : "webkit moz ms o",\n + "transition" : "webkit moz o",\n + "transition-delay" : "webkit moz o",\n + "transition-duration" : "webkit moz o",\n + "transition-property" : "webkit moz o",\n + "transition-timing-function" : "webkit moz o",\n + "user-modify" : "webkit moz",\n + "user-select" : "webkit moz ms",\n + "word-break" : "epub ms",\n + "writing-mode" : "epub ms"\n + };\n +\n +\n + for (prop in compatiblePrefixes) {\n + if (compatiblePrefixes.hasOwnProperty(prop)) {\n + variations = [];\n + prefixed = compatiblePrefixes[prop].split(\' \');\n + for (i = 0, len = prefixed.length; i \074 len; i++) {\n + variations.push(\'-\' + prefixed[i] + \'-\' + prop);\n + }\n + compatiblePrefixes[prop] = variations;\n + arrayPush.apply(applyTo, variations);\n + }\n + }\n +\n + parser.addListener("startrule", function () {\n + properties = [];\n + });\n +\n + parser.addListener("startkeyframes", function (event) {\n + inKeyFrame = event.prefix || true;\n + });\n +\n + parser.addListener("endkeyframes", function (event) {\n + inKeyFrame = false;\n + });\n +\n + parser.addListener("property", function (event) {\n + var name = event.property;\n + if (CSSLint.Util.indexOf(applyTo, name.text) \076 -1) {\n +\n + // e.g., -moz-transform is okay to be alone in @-moz-keyframes\n + if (!inKeyFrame || typeof inKeyFrame != "string" ||\n + name.text.indexOf("-" + inKeyFrame + "-") !== 0) {\n + properties.push(name);\n + }\n + }\n + });\n +\n + parser.addListener("endrule", function (event) {\n + if (!properties.length) {\n + return;\n + }\n +\n + var propertyGroups = {},\n + i,\n + len,\n + name,\n + prop,\n + variations,\n + value,\n + full,\n + actual,\n + item,\n + propertiesSpecified;\n +\n + for (i = 0, len = properties.length; i \074 len; i++) {\n + name = properties[i];\n +\n + for (prop in compatiblePrefixes) {\n + if (compatiblePrefixes.hasOwnProperty(prop)) {\n + variations = compatiblePrefixes[prop];\n + if (CSSLint.Util.indexOf(variations, name.text) \076 -1) {\n + if (!propertyGroups[prop]) {\n + propertyGroups[prop] = {\n + full : variations.slice(0),\n + actual : [],\n + actualNodes: []\n + };\n + }\n + if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) {\n + propertyGroups[prop].actual.push(name.text);\n + propertyGroups[prop].actualNodes.push(name);\n + }\n + }\n + }\n + }\n + }\n +\n + for (prop in propertyGroups) {\n + if (propertyGroups.hasOwnProperty(prop)) {\n + value = propertyGroups[prop];\n + full = value.full;\n + actual = value.actual;\n +\n + if (full.length \076 actual.length) {\n + for (i = 0, len = full.length; i \074 len; i++) {\n + item = full[i];\n + if (CSSLint.Util.indexOf(actual, item) === -1) {\n + propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length == 2) ? actual.join(" and ") : actual.join(", ");\n + reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule);\n + }\n + }\n +\n + }\n + }\n + }\n + });\n + }\n +});\n +/*\n + * Rule: Certain properties don\'t play well with certain display values.\n + * - float should not be used with inline-block\n + * - height, width, margin-top, margin-bottom, float should not be used with inline\n + * - vertical-align should not be used with block\n + * - margin, float should not be used with table-*\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "display-property-grouping",\n + name: "Require properties appropriate for display",\n + desc: "Certain properties shouldn\'t be used with certain display property values.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + var propertiesToCheck = {\n + display: 1,\n + "float": "none",\n + height: 1,\n + width: 1,\n + margin: 1,\n + "margin-left": 1,\n + "margin-right": 1,\n + "margin-bottom": 1,\n + "margin-top": 1,\n + padding: 1,\n + "padding-left": 1,\n + "padding-right": 1,\n + "padding-bottom": 1,\n + "padding-top": 1,\n + "vertical-align": 1\n + },\n + properties;\n +\n + function reportProperty(name, display, msg){\n + if (properties[name]){\n + if (typeof propertiesToCheck[name] != "string" || properties[name].value.toLowerCase() != propertiesToCheck[name]){\n + reporter.report(msg || name + " can\'t be used with display: " + display + ".", properties[name].line, properties[name].col, rule);\n + }\n + }\n + }\n +\n + function startRule(){\n + properties = {};\n + }\n +\n + function endRule(){\n +\n + var display = properties.display ? properties.display.value : null;\n + if (display){\n + switch(display){\n +\n + case "inline":\n + //height, width, margin-top, margin-bottom, float should not be used with inline\n + reportProperty("height", display);\n + reportProperty("width", display);\n + reportProperty("margin", display);\n + reportProperty("margin-top", display);\n + reportProperty("margin-bottom", display);\n + reportProperty("float", display, "display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug).");\n + break;\n +\n + case "block":\n + //vertical-align should not be used with block\n + reportProperty("vertical-align", display);\n + break;\n +\n + case "inline-block":\n + //float should not be used with inline-block\n + reportProperty("float", display);\n + break;\n +\n + default:\n + //margin, float should not be used with table\n + if (display.indexOf("table-") === 0){\n + reportProperty("margin", display);\n + reportProperty("margin-left", display);\n + reportProperty("margin-right", display);\n + reportProperty("margin-top", display);\n + reportProperty("margin-bottom", display);\n + reportProperty("float", display);\n + }\n +\n + //otherwise do nothing\n + }\n + }\n +\n + }\n +\n + parser.addListener("startrule", startRule);\n + parser.addListener("startfontface", startRule);\n + parser.addListener("startkeyframerule", startRule);\n + parser.addListener("startpagemargin", startRule);\n + parser.addListener("startpage", startRule);\n +\n + parser.addListener("property", function(event){\n + var name = event.property.text.toLowerCase();\n +\n + if (propertiesToCheck[name]){\n + properties[name] = { value: event.value.text, line: event.property.line, col: event.property.col };\n + }\n + });\n +\n + parser.addListener("endrule", endRule);\n + parser.addListener("endfontface", endRule);\n + parser.addListener("endkeyframerule", endRule);\n + parser.addListener("endpagemargin", endRule);\n + parser.addListener("endpage", endRule);\n +\n + }\n +\n +});\n +/*\n + * Rule: Disallow duplicate background-images (using url).\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "duplicate-background-images",\n + name: "Disallow duplicate background images",\n + desc: "Every background-image should be unique. Use a common class for e.g. sprites.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + stack = {};\n +\n + parser.addListener("property", function(event){\n + var name = event.property.text,\n + value = event.value,\n + i, len;\n +\n + if (name.match(/background/i)) {\n + for (i=0, len=value.parts.length; i \074 len; i++) {\n + if (value.parts[i].type == \'uri\') {\n + if (typeof stack[value.parts[i].uri] === \'undefined\') {\n + stack[value.parts[i].uri] = event;\n + }\n + else {\n + reporter.report("Background image \'" + value.parts[i].uri + "\' was used multiple times, first declared at line " + stack[value.parts[i].uri].line + ", col " + stack[value.parts[i].uri].col + ".", event.line, event.col, rule);\n + }\n + }\n + }\n + }\n + });\n + }\n +});\n +/*\n + * Rule: Duplicate properties must appear one after the other. If an already-defined\n + * property appears somewhere else in the rule, then it\'s likely an error.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "duplicate-properties",\n + name: "Disallow duplicate properties",\n + desc: "Duplicate properties must appear one after the other.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + properties,\n + lastProperty;\n +\n + function startRule(event){\n + properties = {};\n + }\n +\n + parser.addListener("startrule", startRule);\n + parser.addListener("startfontface", startRule);\n + parser.addListener("startpage", startRule);\n + parser.addListener("startpagemargin", startRule);\n + parser.addListener("startkeyframerule", startRule);\n +\n + parser.addListener("property", function(event){\n + var property = event.property,\n + name = property.text.toLowerCase();\n +\n + if (properties[name] \046\046 (lastProperty != name || properties[name] == event.value.text)){\n + reporter.report("Duplicate property \'" + event.property + "\' found.", event.line, event.col, rule);\n + }\n +\n + properties[name] = event.value.text;\n + lastProperty = name;\n +\n + });\n +\n +\n + }\n +\n +});\n +/*\n + * Rule: Style rules without any properties defined should be removed.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "empty-rules",\n + name: "Disallow empty rules",\n + desc: "Rules without any properties specified should be removed.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + count = 0;\n +\n + parser.addListener("startrule", function(){\n + count=0;\n + });\n +\n + parser.addListener("property", function(){\n + count++;\n + });\n +\n + parser.addListener("endrule", function(event){\n + var selectors = event.selectors;\n + if (count === 0){\n + reporter.report("Rule is empty.", selectors[0].line, selectors[0].col, rule);\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: There should be no syntax errors. (Duh.)\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "errors",\n + name: "Parsing Errors",\n + desc: "This rule looks for recoverable syntax errors.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + parser.addListener("error", function(event){\n + reporter.error(event.message, event.line, event.col, rule);\n + });\n +\n + }\n +\n +});\n +\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "fallback-colors",\n + name: "Require fallback colors",\n + desc: "For older browsers that don\'t support RGBA, HSL, or HSLA, provide a fallback color.",\n + browsers: "IE6,IE7,IE8",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + lastProperty,\n + propertiesToCheck = {\n + color: 1,\n + background: 1,\n + "border-color": 1,\n + "border-top-color": 1,\n + "border-right-color": 1,\n + "border-bottom-color": 1,\n + "border-left-color": 1,\n + border: 1,\n + "border-top": 1,\n + "border-right": 1,\n + "border-bottom": 1,\n + "border-left": 1,\n + "background-color": 1\n + },\n + properties;\n +\n + function startRule(event){\n + properties = {};\n + lastProperty = null;\n + }\n +\n + parser.addListener("startrule", startRule);\n + parser.addListener("startfontface", startRule);\n + parser.addListener("startpage", startRule);\n + parser.addListener("startpagemargin", startRule);\n + parser.addListener("startkeyframerule", startRule);\n +\n + parser.addListener("property", function(event){\n + var property = event.property,\n + name = property.text.toLowerCase(),\n + parts = event.value.parts,\n + i = 0,\n + colorType = "",\n + len = parts.length;\n +\n + if(propertiesToCheck[name]){\n + while(i \074 len){\n + if (parts[i].type == "color"){\n + if ("alpha" in parts[i] || "hue" in parts[i]){\n +\n + if (/([^\\)]+)\\(/.test(parts[i])){\n + colorType = RegExp.$1.toUpperCase();\n + }\n +\n + if (!lastProperty || (lastProperty.property.text.toLowerCase() != name || lastProperty.colorType != "compat")){\n + reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule);\n + }\n + } else {\n + event.colorType = "compat";\n + }\n + }\n +\n + i++;\n + }\n + }\n +\n + lastProperty = event;\n + });\n +\n + }\n +\n +});\n +/*\n + * Rule: You shouldn\'t use more than 10 floats. If you do, there\'s probably\n + * room for some abstraction.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "floats",\n + name: "Disallow too many floats",\n + desc: "This rule tests if the float property is used too many times",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n + var count = 0;\n +\n + //count how many times "float" is used\n + parser.addListener("property", function(event){\n + if (event.property.text.toLowerCase() == "float" \046\046\n + event.value.text.toLowerCase() != "none"){\n + count++;\n + }\n + });\n +\n + //report the results\n + parser.addListener("endstylesheet", function(){\n + reporter.stat("floats", count);\n + if (count \076= 10){\n + reporter.rollupWarn("Too many floats (" + count + "), you\'re probably using them for layout. Consider using a grid system instead.", rule);\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: Avoid too many @font-face declarations in the same stylesheet.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "font-faces",\n + name: "Don\'t use too many web fonts",\n + desc: "Too many different web fonts in the same stylesheet.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + count = 0;\n +\n +\n + parser.addListener("startfontface", function(){\n + count++;\n + });\n +\n + parser.addListener("endstylesheet", function(){\n + if (count \076 5){\n + reporter.rollupWarn("Too many @font-face declarations (" + count + ").", rule);\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: You shouldn\'t need more than 9 font-size declarations.\n + */\n +\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "font-sizes",\n + name: "Disallow too many font sizes",\n + desc: "Checks the number of font-size declarations.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + count = 0;\n +\n + //check for use of "font-size"\n + parser.addListener("property", function(event){\n + if (event.property == "font-size"){\n + count++;\n + }\n + });\n +\n + //report the results\n + parser.addListener("endstylesheet", function(){\n + reporter.stat("font-sizes", count);\n + if (count \076= 10){\n + reporter.rollupWarn("Too many font-size declarations (" + count + "), abstraction needed.", rule);\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: When using a vendor-prefixed gradient, make sure to use them all.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "gradients",\n + name: "Require all gradient definitions",\n + desc: "When using a vendor-prefixed gradient, make sure to use them all.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + gradients;\n +\n + parser.addListener("startrule", function(){\n + gradients = {\n + moz: 0,\n + webkit: 0,\n + oldWebkit: 0,\n + o: 0\n + };\n + });\n +\n + parser.addListener("property", function(event){\n +\n + if (/\\-(moz|o|webkit)(?:\\-(?:linear|radial))\\-gradient/i.test(event.value)){\n + gradients[RegExp.$1] = 1;\n + } else if (/\\-webkit\\-gradient/i.test(event.value)){\n + gradients.oldWebkit = 1;\n + }\n +\n + });\n +\n + parser.addListener("endrule", function(event){\n + var missing = [];\n +\n + if (!gradients.moz){\n + missing.push("Firefox 3.6+");\n + }\n +\n + if (!gradients.webkit){\n + missing.push("Webkit (Safari 5+, Chrome)");\n + }\n +\n + if (!gradients.oldWebkit){\n + missing.push("Old Webkit (Safari 4+, Chrome)");\n + }\n +\n + if (!gradients.o){\n + missing.push("Opera 11.1+");\n + }\n +\n + if (missing.length \046\046 missing.length \074 4){\n + reporter.report("Missing vendor-prefixed CSS gradients for " + missing.join(", ") + ".", event.selectors[0].line, event.selectors[0].col, rule);\n + }\n +\n + });\n +\n + }\n +\n +});\n +\n +/*\n + * Rule: Don\'t use IDs for selectors.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "ids",\n + name: "Disallow IDs in selectors",\n + desc: "Selectors should not contain IDs.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n + parser.addListener("startrule", function(event){\n + var selectors = event.selectors,\n + selector,\n + part,\n + modifier,\n + idCount,\n + i, j, k;\n +\n + for (i=0; i \074 selectors.length; i++){\n + selector = selectors[i];\n + idCount = 0;\n +\n + for (j=0; j \074 selector.parts.length; j++){\n + part = selector.parts[j];\n + if (part.type == parser.SELECTOR_PART_TYPE){\n + for (k=0; k \074 part.modifiers.length; k++){\n + modifier = part.modifiers[k];\n + if (modifier.type == "id"){\n + idCount++;\n + }\n + }\n + }\n + }\n +\n + if (idCount == 1){\n + reporter.report("Don\'t use IDs in selectors.", selector.line, selector.col, rule);\n + } else if (idCount \076 1){\n + reporter.report(idCount + " IDs in the selector, really?", selector.line, selector.col, rule);\n + }\n + }\n +\n + });\n + }\n +\n +});\n +/*\n + * Rule: Don\'t use @import, use \074link\076 instead.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "import",\n + name: "Disallow @import",\n + desc: "Don\'t use @import, use \074link\076 instead.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + parser.addListener("import", function(event){\n + reporter.report("@import prevents parallel downloads, use \074link\076 instead.", event.line, event.col, rule);\n + });\n +\n + }\n +\n +});\n +/*\n + * Rule: Make sure !important is not overused, this could lead to specificity\n + * war. Display a warning on !important declarations, an error if it\'s\n + * used more at least 10 times.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "important",\n + name: "Disallow !important",\n + desc: "Be careful when using !important declaration",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + count = 0;\n +\n + //warn that important is used and increment the declaration counter\n + parser.addListener("property", function(event){\n + if (event.important === true){\n + count++;\n + reporter.report("Use of !important", event.line, event.col, rule);\n + }\n + });\n +\n + //if there are more than 10, show an error\n + parser.addListener("endstylesheet", function(){\n + reporter.stat("important", count);\n + if (count \076= 10){\n + reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule);\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: Properties should be known (listed in CSS3 specification) or\n + * be a vendor-prefixed property.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "known-properties",\n + name: "Require use of known properties",\n + desc: "Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + parser.addListener("property", function(event){\n + var name = event.property.text.toLowerCase();\n +\n + // the check is handled entirely by the parser-lib (https://github.com/nzakas/parser-lib)\n + if (event.invalid) {\n + reporter.report(event.invalid.message, event.line, event.col, rule);\n + }\n +\n + });\n + }\n +\n +});\n +/*\n + * Rule: outline: none or outline: 0 should only be used in a :focus rule\n + * and only if there are other properties in the same rule.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "outline-none",\n + name: "Disallow outline: none",\n + desc: "Use of outline: none or outline: 0 should be limited to :focus rules.",\n + browsers: "All",\n + tags: ["Accessibility"],\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + lastRule;\n +\n + function startRule(event){\n + if (event.selectors){\n + lastRule = {\n + line: event.line,\n + col: event.col,\n + selectors: event.selectors,\n + propCount: 0,\n + outline: false\n + };\n + } else {\n + lastRule = null;\n + }\n + }\n +\n + function endRule(event){\n + if (lastRule){\n + if (lastRule.outline){\n + if (lastRule.selectors.toString().toLowerCase().indexOf(":focus") == -1){\n + reporter.report("Outlines should only be modified using :focus.", lastRule.line, lastRule.col, rule);\n + } else if (lastRule.propCount == 1) {\n + reporter.report("Outlines shouldn\'t be hidden unless other visual changes are made.", lastRule.line, lastRule.col, rule);\n + }\n + }\n + }\n + }\n +\n + parser.addListener("startrule", startRule);\n + parser.addListener("startfontface", startRule);\n + parser.addListener("startpage", startRule);\n + parser.addListener("startpagemargin", startRule);\n + parser.addListener("startkeyframerule", startRule);\n +\n + parser.addListener("property", function(event){\n + var name = event.property.text.toLowerCase(),\n + value = event.value;\n +\n + if (lastRule){\n + lastRule.propCount++;\n + if (name == "outline" \046\046 (value == "none" || value == "0")){\n + lastRule.outline = true;\n + }\n + }\n +\n + });\n +\n + parser.addListener("endrule", endRule);\n + parser.addListener("endfontface", endRule);\n + parser.addListener("endpage", endRule);\n + parser.addListener("endpagemargin", endRule);\n + parser.addListener("endkeyframerule", endRule);\n +\n + }\n +\n +});\n +/*\n + * Rule: Don\'t use classes or IDs with elements (a.foo or a#foo).\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "overqualified-elements",\n + name: "Disallow overqualified elements",\n + desc: "Don\'t use classes or IDs with elements (a.foo or a#foo).",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + classes = {};\n +\n + parser.addListener("startrule", function(event){\n + var selectors = event.selectors,\n + selector,\n + part,\n + modifier,\n + i, j, k;\n +\n + for (i=0; i \074 selectors.length; i++){\n + selector = selectors[i];\n +\n + for (j=0; j \074 selector.parts.length; j++){\n + part = selector.parts[j];\n + if (part.type == parser.SELECTOR_PART_TYPE){\n + for (k=0; k \074 part.modifiers.length; k++){\n + modifier = part.modifiers[k];\n + if (part.elementName \046\046 modifier.type == "id"){\n + reporter.report("Element (" + part + ") is overqualified, just use " + modifier + " without element name.", part.line, part.col, rule);\n + } else if (modifier.type == "class"){\n +\n + if (!classes[modifier]){\n + classes[modifier] = [];\n + }\n + classes[modifier].push({ modifier: modifier, part: part });\n + }\n + }\n + }\n + }\n + }\n + });\n +\n + parser.addListener("endstylesheet", function(){\n +\n + var prop;\n + for (prop in classes){\n + if (classes.hasOwnProperty(prop)){\n +\n + //one use means that this is overqualified\n + if (classes[prop].length == 1 \046\046 classes[prop][0].part.elementName){\n + reporter.report("Element (" + classes[prop][0].part + ") is overqualified, just use " + classes[prop][0].modifier + " without element name.", classes[prop][0].part.line, classes[prop][0].part.col, rule);\n + }\n + }\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: Headings (h1-h6) should not be qualified (namespaced).\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "qualified-headings",\n + name: "Disallow qualified headings",\n + desc: "Headings should not be qualified (namespaced).",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + parser.addListener("startrule", function(event){\n + var selectors = event.selectors,\n + selector,\n + part,\n + i, j;\n +\n + for (i=0; i \074 selectors.length; i++){\n + selector = selectors[i];\n +\n + for (j=0; j \074 selector.parts.length; j++){\n + part = selector.parts[j];\n + if (part.type == parser.SELECTOR_PART_TYPE){\n + if (part.elementName \046\046 /h[1-6]/.test(part.elementName.toString()) \046\046 j \076 0){\n + reporter.report("Heading (" + part.elementName + ") should not be qualified.", part.line, part.col, rule);\n + }\n + }\n + }\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: Selectors that look like regular expressions are slow and should be avoided.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "regex-selectors",\n + name: "Disallow selectors that look like regexs",\n + desc: "Selectors that look like regular expressions are slow and should be avoided.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + parser.addListener("startrule", function(event){\n + var selectors = event.selectors,\n + selector,\n + part,\n + modifier,\n + i, j, k;\n +\n + for (i=0; i \074 selectors.length; i++){\n + selector = selectors[i];\n + for (j=0; j \074 selector.parts.length; j++){\n + part = selector.parts[j];\n + if (part.type == parser.SELECTOR_PART_TYPE){\n + for (k=0; k \074 part.modifiers.length; k++){\n + modifier = part.modifiers[k];\n + if (modifier.type == "attribute"){\n + if (/([\\~\\|\\^\\$\\*]=)/.test(modifier)){\n + reporter.report("Attribute selectors with " + RegExp.$1 + " are slow!", modifier.line, modifier.col, rule);\n + }\n + }\n +\n + }\n + }\n + }\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: Total number of rules should not exceed x.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "rules-count",\n + name: "Rules Count",\n + desc: "Track how many rules there are.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + count = 0;\n +\n + //count each rule\n + parser.addListener("startrule", function(){\n + count++;\n + });\n +\n + parser.addListener("endstylesheet", function(){\n + reporter.stat("rule-count", count);\n + });\n + }\n +\n +});\n +/*\n + * Rule: Warn people with approaching the IE 4095 limit\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "selector-max-approaching",\n + name: "Warn when approaching the 4095 selector limit for IE",\n + desc: "Will warn when selector count is \076= 3800 selectors.",\n + browsers: "IE",\n +\n + //initialization\n + init: function(parser, reporter) {\n + var rule = this, count = 0;\n +\n + parser.addListener(\'startrule\', function(event) {\n + count += event.selectors.length;\n + });\n +\n + parser.addListener("endstylesheet", function() {\n + if (count \076= 3800) {\n + reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule);\n + }\n + });\n + }\n +\n +});\n +\n +/*\n + * Rule: Warn people past the IE 4095 limit\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "selector-max",\n + name: "Error when past the 4095 selector limit for IE",\n + desc: "Will error when selector count is \076 4095.",\n + browsers: "IE",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this, count = 0;\n +\n + parser.addListener(\'startrule\',function(event) {\n + count += event.selectors.length;\n + });\n +\n + parser.addListener("endstylesheet", function() {\n + if (count \076 4095) {\n + reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule);\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: Use shorthand properties where possible.\n + *\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "shorthand",\n + name: "Require shorthand properties",\n + desc: "Use shorthand properties where possible.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + prop, i, len,\n + propertiesToCheck = {},\n + properties,\n + mapping = {\n + "margin": [\n + "margin-top",\n + "margin-bottom",\n + "margin-left",\n + "margin-right"\n + ],\n + "padding": [\n + "padding-top",\n + "padding-bottom",\n + "padding-left",\n + "padding-right"\n + ]\n + };\n +\n + //initialize propertiesToCheck\n + for (prop in mapping){\n + if (mapping.hasOwnProperty(prop)){\n + for (i=0, len=mapping[prop].length; i \074 len; i++){\n + propertiesToCheck[mapping[prop][i]] = prop;\n + }\n + }\n + }\n +\n + function startRule(event){\n + properties = {};\n + }\n +\n + //event handler for end of rules\n + function endRule(event){\n +\n + var prop, i, len, total;\n +\n + //check which properties this rule has\n + for (prop in mapping){\n + if (mapping.hasOwnProperty(prop)){\n + total=0;\n +\n + for (i=0, len=mapping[prop].length; i \074 len; i++){\n + total += properties[mapping[prop][i]] ? 1 : 0;\n + }\n +\n + if (total == mapping[prop].length){\n + reporter.report("The properties " + mapping[prop].join(", ") + " can be replaced by " + prop + ".", event.line, event.col, rule);\n + }\n + }\n + }\n + }\n +\n + parser.addListener("startrule", startRule);\n + parser.addListener("startfontface", startRule);\n +\n + //check for use of "font-size"\n + parser.addListener("property", function(event){\n + var name = event.property.toString().toLowerCase(),\n + value = event.value.parts[0].value;\n +\n + if (propertiesToCheck[name]){\n + properties[name] = 1;\n + }\n + });\n +\n + parser.addListener("endrule", endRule);\n + parser.addListener("endfontface", endRule);\n +\n + }\n +\n +});\n +/*\n + * Rule: Don\'t use properties with a star prefix.\n + *\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "star-property-hack",\n + name: "Disallow properties with a star prefix",\n + desc: "Checks for the star property hack (targets IE6/7)",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + //check if property name starts with "*"\n + parser.addListener("property", function(event){\n + var property = event.property;\n +\n + if (property.hack == "*") {\n + reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule);\n + }\n + });\n + }\n +});\n +/*\n + * Rule: Don\'t use text-indent for image replacement if you need to support rtl.\n + *\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "text-indent",\n + name: "Disallow negative text-indent",\n + desc: "Checks for text indent less than -99px",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + textIndent,\n + direction;\n +\n +\n + function startRule(event){\n + textIndent = false;\n + direction = "inherit";\n + }\n +\n + //event handler for end of rules\n + function endRule(event){\n + if (textIndent \046\046 direction != "ltr"){\n + reporter.report("Negative text-indent doesn\'t work well with RTL. If you use text-indent for image replacement explicitly set direction for that item to ltr.", textIndent.line, textIndent.col, rule);\n + }\n + }\n +\n + parser.addListener("startrule", startRule);\n + parser.addListener("startfontface", startRule);\n +\n + //check for use of "font-size"\n + parser.addListener("property", function(event){\n + var name = event.property.toString().toLowerCase(),\n + value = event.value;\n +\n + if (name == "text-indent" \046\046 value.parts[0].value \074 -99){\n + textIndent = event.property;\n + } else if (name == "direction" \046\046 value == "ltr"){\n + direction = "ltr";\n + }\n + });\n +\n + parser.addListener("endrule", endRule);\n + parser.addListener("endfontface", endRule);\n +\n + }\n +\n +});\n +/*\n + * Rule: Don\'t use properties with a underscore prefix.\n + *\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "underscore-property-hack",\n + name: "Disallow properties with an underscore prefix",\n + desc: "Checks for the underscore property hack (targets IE6)",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + //check if property name starts with "_"\n + parser.addListener("property", function(event){\n + var property = event.property;\n +\n + if (property.hack == "_") {\n + reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule);\n + }\n + });\n + }\n +});\n +/*\n + * Rule: Headings (h1-h6) should be defined only once.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "unique-headings",\n + name: "Headings should only be defined once",\n + desc: "Headings should be defined only once.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + var headings = {\n + h1: 0,\n + h2: 0,\n + h3: 0,\n + h4: 0,\n + h5: 0,\n + h6: 0\n + };\n +\n + parser.addListener("startrule", function(event){\n + var selectors = event.selectors,\n + selector,\n + part,\n + pseudo,\n + i, j;\n +\n + for (i=0; i \074 selectors.length; i++){\n + selector = selectors[i];\n + part = selector.parts[selector.parts.length-1];\n +\n + if (part.elementName \046\046 /(h[1-6])/i.test(part.elementName.toString())){\n +\n + for (j=0; j \074 part.modifiers.length; j++){\n + if (part.modifiers[j].type == "pseudo"){\n + pseudo = true;\n + break;\n + }\n + }\n +\n + if (!pseudo){\n + headings[RegExp.$1]++;\n + if (headings[RegExp.$1] \076 1) {\n + reporter.report("Heading (" + part.elementName + ") has already been defined.", part.line, part.col, rule);\n + }\n + }\n + }\n + }\n + });\n +\n + parser.addListener("endstylesheet", function(event){\n + var prop,\n + messages = [];\n +\n + for (prop in headings){\n + if (headings.hasOwnProperty(prop)){\n + if (headings[prop] \076 1){\n + messages.push(headings[prop] + " " + prop + "s");\n + }\n + }\n + }\n +\n + if (messages.length){\n + reporter.rollupWarn("You have " + messages.join(", ") + " defined in this stylesheet.", rule);\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: Don\'t use universal selector because it\'s slow.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "universal-selector",\n + name: "Disallow universal selector",\n + desc: "The universal selector (*) is known to be slow.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + parser.addListener("startrule", function(event){\n + var selectors = event.selectors,\n + selector,\n + part,\n + modifier,\n + i, j, k;\n +\n + for (i=0; i \074 selectors.length; i++){\n + selector = selectors[i];\n +\n + part = selector.parts[selector.parts.length-1];\n + if (part.elementName == "*"){\n + reporter.report(rule.desc, part.line, part.col, rule);\n + }\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: Don\'t use unqualified attribute selectors because they\'re just like universal selectors.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "unqualified-attributes",\n + name: "Disallow unqualified attribute selectors",\n + desc: "Unqualified attribute selectors are known to be slow.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + parser.addListener("startrule", function(event){\n +\n + var selectors = event.selectors,\n + selector,\n + part,\n + modifier,\n + i, j, k;\n +\n + for (i=0; i \074 selectors.length; i++){\n + selector = selectors[i];\n +\n + part = selector.parts[selector.parts.length-1];\n + if (part.type == parser.SELECTOR_PART_TYPE){\n + for (k=0; k \074 part.modifiers.length; k++){\n + modifier = part.modifiers[k];\n + if (modifier.type == "attribute" \046\046 (!part.elementName || part.elementName == "*")){\n + reporter.report(rule.desc, part.line, part.col, rule);\n + }\n + }\n + }\n +\n + }\n + });\n + }\n +\n +});\n +/*\n + * Rule: When using a vendor-prefixed property, make sure to\n + * include the standard one.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "vendor-prefix",\n + name: "Require standard property with vendor prefix",\n + desc: "When using a vendor-prefixed property, make sure to include the standard one.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this,\n + properties,\n + num,\n + propertiesToCheck = {\n + "-webkit-border-radius": "border-radius",\n + "-webkit-border-top-left-radius": "border-top-left-radius",\n + "-webkit-border-top-right-radius": "border-top-right-radius",\n + "-webkit-border-bottom-left-radius": "border-bottom-left-radius",\n + "-webkit-border-bottom-right-radius": "border-bottom-right-radius",\n +\n + "-o-border-radius": "border-radius",\n + "-o-border-top-left-radius": "border-top-left-radius",\n + "-o-border-top-right-radius": "border-top-right-radius",\n + "-o-border-bottom-left-radius": "border-bottom-left-radius",\n + "-o-border-bottom-right-radius": "border-bottom-right-radius",\n +\n + "-moz-border-radius": "border-radius",\n + "-moz-border-radius-topleft": "border-top-left-radius",\n + "-moz-border-radius-topright": "border-top-right-radius",\n + "-moz-border-radius-bottomleft": "border-bottom-left-radius",\n + "-moz-border-radius-bottomright": "border-bottom-right-radius",\n +\n + "-moz-column-count": "column-count",\n + "-webkit-column-count": "column-count",\n +\n + "-moz-column-gap": "column-gap",\n + "-webkit-column-gap": "column-gap",\n +\n + "-moz-column-rule": "column-rule",\n + "-webkit-column-rule": "column-rule",\n +\n + "-moz-column-rule-style": "column-rule-style",\n + "-webkit-column-rule-style": "column-rule-style",\n +\n + "-moz-column-rule-color": "column-rule-color",\n + "-webkit-column-rule-color": "column-rule-color",\n +\n + "-moz-column-rule-width": "column-rule-width",\n + "-webkit-column-rule-width": "column-rule-width",\n +\n + "-moz-column-width": "column-width",\n + "-webkit-column-width": "column-width",\n +\n + "-webkit-column-span": "column-span",\n + "-webkit-columns": "columns",\n +\n + "-moz-box-shadow": "box-shadow",\n + "-webkit-box-shadow": "box-shadow",\n +\n + "-moz-transform" : "transform",\n + "-webkit-transform" : "transform",\n + "-o-transform" : "transform",\n + "-ms-transform" : "transform",\n +\n + "-moz-transform-origin" : "transform-origin",\n + "-webkit-transform-origin" : "transform-origin",\n + "-o-transform-origin" : "transform-origin",\n + "-ms-transform-origin" : "transform-origin",\n +\n + "-moz-box-sizing" : "box-sizing",\n + "-webkit-box-sizing" : "box-sizing",\n +\n + "-moz-user-select" : "user-select",\n + "-khtml-user-select" : "user-select",\n + "-webkit-user-select" : "user-select"\n + };\n +\n + //event handler for beginning of rules\n + function startRule(){\n + properties = {};\n + num=1;\n + }\n +\n + //event handler for end of rules\n + function endRule(event){\n + var prop,\n + i, len,\n + standard,\n + needed,\n + actual,\n + needsStandard = [];\n +\n + for (prop in properties){\n + if (propertiesToCheck[prop]){\n + needsStandard.push({ actual: prop, needed: propertiesToCheck[prop]});\n + }\n + }\n +\n + for (i=0, len=needsStandard.length; i \074 len; i++){\n + needed = needsStandard[i].needed;\n + actual = needsStandard[i].actual;\n +\n + if (!properties[needed]){\n + reporter.report("Missing standard property \'" + needed + "\' to go along with \'" + actual + "\'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);\n + } else {\n + //make sure standard property is last\n + if (properties[needed][0].pos \074 properties[actual][0].pos){\n + reporter.report("Standard property \'" + needed + "\' should come after vendor-prefixed property \'" + actual + "\'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);\n + }\n + }\n + }\n +\n + }\n +\n + parser.addListener("startrule", startRule);\n + parser.addListener("startfontface", startRule);\n + parser.addListener("startpage", startRule);\n + parser.addListener("startpagemargin", startRule);\n + parser.addListener("startkeyframerule", startRule);\n +\n + parser.addListener("property", function(event){\n + var name = event.property.text.toLowerCase();\n +\n + if (!properties[name]){\n + properties[name] = [];\n + }\n +\n + properties[name].push({ name: event.property, value : event.value, pos:num++ });\n + });\n +\n + parser.addListener("endrule", endRule);\n + parser.addListener("endfontface", endRule);\n + parser.addListener("endpage", endRule);\n + parser.addListener("endpagemargin", endRule);\n + parser.addListener("endkeyframerule", endRule);\n + }\n +\n +});\n +/*\n + * Rule: You don\'t need to specify units when a value is 0.\n + */\n +/*global CSSLint*/\n +CSSLint.addRule({\n +\n + //rule information\n + id: "zero-units",\n + name: "Disallow units for 0 values",\n + desc: "You don\'t need to specify units when a value is 0.",\n + browsers: "All",\n +\n + //initialization\n + init: function(parser, reporter){\n + var rule = this;\n +\n + //count how many times "float" is used\n + parser.addListener("property", function(event){\n + var parts = event.value.parts,\n + i = 0,\n + len = parts.length;\n +\n + while(i \074 len){\n + if ((parts[i].units || parts[i].type == "percentage") \046\046 parts[i].value === 0 \046\046 parts[i].type != "time"){\n + reporter.report("Values of 0 shouldn\'t have units specified.", parts[i].line, parts[i].col, rule);\n + }\n + i++;\n + }\n +\n + });\n +\n + }\n +\n +});\n +/*global CSSLint*/\n +(function() {\n +\n + /**\n + * Replace special characters before write to output.\n + *\n + * Rules:\n + * - single quotes is the escape sequence for double-quotes\n + * - \046amp; is the escape sequence for \046\n + * - \046lt; is the escape sequence for \074\n + * - \046gt; is the escape sequence for \076\n + *\n + * @param {String} message to escape\n + * @return escaped message as {String}\n + */\n + var xmlEscape = function(str) {\n + if (!str || str.constructor !== String) {\n + return "";\n + }\n +\n + return str.replace(/[\\"\046\076\074]/g, function(match) {\n + switch (match) {\n + case "\\"":\n + return "\046quot;";\n + case "\046":\n + return "\046amp;";\n + case "\074":\n + return "\046lt;";\n + case "\076":\n + return "\046gt;";\n + }\n + });\n + };\n +\n + CSSLint.addFormatter({\n + //format information\n + id: "checkstyle-xml",\n + name: "Checkstyle XML format",\n +\n + /**\n + * Return opening root XML tag.\n + * @return {String} to prepend before all results\n + */\n + startFormat: function(){\n + return "\074?xml version=\\"1.0\\" encoding=\\"utf-8\\"?\076\074checkstyle\076";\n + },\n +\n + /**\n + * Return closing root XML tag.\n + * @return {String} to append after all results\n + */\n + endFormat: function(){\n + return "\074/checkstyle\076";\n + },\n +\n + /**\n + * Returns message when there is a file read error.\n + * @param {String} filename The name of the file that caused the error.\n + * @param {String} message The error message\n + * @return {String} The error message.\n + */\n + readError: function(filename, message) {\n + return "\074file name=\\"" + xmlEscape(filename) + "\\"\076\074error line=\\"0\\" column=\\"0\\" severty=\\"error\\" message=\\"" + xmlEscape(message) + "\\"\076\074/error\076\074/file\076";\n + },\n +\n + /**\n + * Given CSS Lint results for a file, return output for this format.\n + * @param results {Object} with error and warning messages\n + * @param filename {String} relative file path\n + * @param options {Object} (UNUSED for now) specifies special handling of output\n + * @return {String} output for results\n + */\n + formatResults: function(results, filename, options) {\n + var messages = results.messages,\n + output = [];\n +\n + /**\n + * Generate a source string for a rule.\n + * Checkstyle source strings usually resemble Java class names e.g\n + * net.csslint.SomeRuleName\n + * @param {Object} rule\n + * @return rule source as {String}\n + */\n + var generateSource = function(rule) {\n + if (!rule || !(\'name\' in rule)) {\n + return "";\n + }\n + return \'net.csslint.\' + rule.name.replace(/\\s/g,\'\');\n + };\n +\n +\n +\n + if (messages.length \076 0) {\n + output.push("\074file name=\\""+filename+"\\"\076");\n + CSSLint.Util.forEach(messages, function (message, i) {\n + //ignore rollups for now\n + if (!message.rollup) {\n + output.push("\074error line=\\"" + message.line + "\\" column=\\"" + message.col + "\\" severity=\\"" + message.type + "\\"" +\n + " message=\\"" + xmlEscape(message.message) + "\\" source=\\"" + generateSource(message.rule) +"\\"/\076");\n + }\n + });\n + output.push("\074/file\076");\n + }\n +\n + return output.join("");\n + }\n + });\n +\n +}());\n +/*global CSSLint*/\n +CSSLint.addFormatter({\n + //format information\n + id: "compact",\n + name: "Compact, \'porcelain\' format",\n +\n + /**\n + * Return content to be printed before all file results.\n + * @return {String} to prepend before all results\n + */\n + startFormat: function() {\n + return "";\n + },\n +\n + /**\n + * Return content to be printed after all file results.\n + * @return {String} to append after all results\n + */\n + endFormat: function() {\n + return "";\n + },\n +\n + /**\n + * Given CSS Lint results for a file, return output for this format.\n + * @param results {Object} with error and warning messages\n + * @param filename {String} relative file path\n + * @param options {Object} (Optional) specifies special handling of output\n + * @return {String} output for results\n + */\n + formatResults: function(results, filename, options) {\n + var messages = results.messages,\n + output = "";\n + options = options || {};\n +\n + /**\n + * Capitalize and return given string.\n + * @param str {String} to capitalize\n + * @return {String} capitalized\n + */\n + var capitalize = function(str) {\n + return str.charAt(0).toUpperCase() + str.slice(1);\n + };\n +\n + if (messages.length === 0) {\n + return options.quiet ? "" : filename + ": Lint Free!";\n + }\n +\n + CSSLint.Util.forEach(messages, function(message, i) {\n + if (message.rollup) {\n + output += filename + ": " + capitalize(message.type) + " - " + message.message + "\\n";\n + } else {\n + output += filename + ": " + "line " + message.line +\n + ", col " + message.col + ", " + capitalize(message.type) + " - " + message.message + "\\n";\n + }\n + });\n +\n + return output;\n + }\n +});\n +/*global CSSLint*/\n +CSSLint.addFormatter({\n + //format information\n + id: "csslint-xml",\n + name: "CSSLint XML format",\n +\n + /**\n + * Return opening root XML tag.\n + * @return {String} to prepend before all results\n + */\n + startFormat: function(){\n + return "\074?xml version=\\"1.0\\" encoding=\\"utf-8\\"?\076\074csslint\076";\n + },\n +\n + /**\n + * Return closing root XML tag.\n + * @return {String} to append after all results\n + */\n + endFormat: function(){\n + return "\074/csslint\076";\n + },\n +\n + /**\n + * Given CSS Lint results for a file, return output for this format.\n + * @param results {Object} with error and warning messages\n + * @param filename {String} relative file path\n + * @param options {Object} (UNUSED for now) specifies special handling of output\n + * @return {String} output for results\n + */\n + formatResults: function(results, filename, options) {\n + var messages = results.messages,\n + output = [];\n +\n + /**\n + * Replace special characters before write to output.\n + *\n + * Rules:\n + * - single quotes is the escape sequence for double-quotes\n + * - \046amp; is the escape sequence for \046\n + * - \046lt; is the escape sequence for \074\n + * - \046gt; is the escape sequence for \076\n + *\n + * @param {String} message to escape\n + * @return escaped message as {String}\n + */\n + var escapeSpecialCharacters = function(str) {\n + if (!str || str.constructor !== String) {\n + return "";\n + }\n + return str.replace(/\\"/g, "\'").replace(/\046/g, "\046amp;").replace(/\074/g, "\046lt;").replace(/\076/g, "\046gt;");\n + };\n +\n + if (messages.length \076 0) {\n + output.push("\074file name=\\""+filename+"\\"\076");\n + CSSLint.Util.forEach(messages, function (message, i) {\n + if (message.rollup) {\n + output.push("\074issue severity=\\"" + message.type + "\\" reason=\\"" + escapeSpecialCharacters(message.message) + "\\" evidence=\\"" + escapeSpecialCharacters(message.evidence) + "\\"/\076");\n + } else {\n + output.push("\074issue line=\\"" + message.line + "\\" char=\\"" + message.col + "\\" severity=\\"" + message.type + "\\"" +\n + " reason=\\"" + escapeSpecialCharacters(message.message) + "\\" evidence=\\"" + escapeSpecialCharacters(message.evidence) + "\\"/\076");\n + }\n + });\n + output.push("\074/file\076");\n + }\n +\n + return output.join("");\n + }\n +});\n +/*global CSSLint*/\n +CSSLint.addFormatter({\n + //format information\n + id: "junit-xml",\n + name: "JUNIT XML format",\n +\n + /**\n + * Return opening root XML tag.\n + * @return {String} to prepend before all results\n + */\n + startFormat: function(){\n + return "\074?xml version=\\"1.0\\" encoding=\\"utf-8\\"?\076\074testsuites\076";\n + },\n +\n + /**\n + * Return closing root XML tag.\n + * @return {String} to append after all results\n + */\n + endFormat: function() {\n + return "\074/testsuites\076";\n + },\n +\n + /**\n + * Given CSS Lint results for a file, return output for this format.\n + * @param results {Object} with error and warning messages\n + * @param filename {String} relative file path\n + * @param options {Object} (UNUSED for now) specifies special handling of output\n + * @return {String} output for results\n + */\n + formatResults: function(results, filename, options) {\n +\n + var messages = results.messages,\n + output = [],\n + tests = {\n + \'error\': 0,\n + \'failure\': 0\n + };\n +\n + /**\n + * Generate a source string for a rule.\n + * JUNIT source strings usually resemble Java class names e.g\n + * net.csslint.SomeRuleName\n + * @param {Object} rule\n + * @return rule source as {String}\n + */\n + var generateSource = function(rule) {\n + if (!rule || !(\'name\' in rule)) {\n + return "";\n + }\n + return \'net.csslint.\' + rule.name.replace(/\\s/g,\'\');\n + };\n +\n + /**\n + * Replace special characters before write to output.\n + *\n + * Rules:\n + * - single quotes is the escape sequence for double-quotes\n + * - \046lt; is the escape sequence for \074\n + * - \046gt; is the escape sequence for \076\n + *\n + * @param {String} message to escape\n + * @return escaped message as {String}\n + */\n + var escapeSpecialCharacters = function(str) {\n +\n + if (!str || str.constructor !== String) {\n + return "";\n + }\n +\n + return str.replace(/\\"/g, "\'").replace(/\074/g, "\046lt;").replace(/\076/g, "\046gt;");\n +\n + };\n +\n + if (messages.length \076 0) {\n +\n + messages.forEach(function (message, i) {\n +\n + // since junit has no warning class\n + // all issues as errors\n + var type = message.type === \'warning\' ? \'error\' : message.type;\n +\n + //ignore rollups for now\n + if (!message.rollup) {\n +\n + // build the test case seperately, once joined\n + // we\'ll add it to a custom array filtered by type\n + output.push("\074testcase time=\\"0\\" name=\\"" + generateSource(message.rule) + "\\"\076");\n + output.push("\074" + type + " message=\\"" + escapeSpecialCharacters(message.message) + "\\"\076\074![CDATA[" + message.line + \':\' + message.col + \':\' + escapeSpecialCharacters(message.evidence) + "]]\076\074/" + type + "\076");\n + output.push("\074/testcase\076");\n +\n + tests[type] += 1;\n +\n + }\n +\n + });\n +\n + output.unshift("\074testsuite time=\\"0\\" tests=\\"" + messages.length + "\\" skipped=\\"0\\" errors=\\"" + tests.error + "\\" failures=\\"" + tests.failure + "\\" package=\\"net.csslint\\" name=\\"" + filename + "\\"\076");\n + output.push("\074/testsuite\076");\n +\n + }\n +\n + return output.join("");\n +\n + }\n +});\n +/*global CSSLint*/\n +CSSLint.addFormatter({\n + //format information\n + id: "lint-xml",\n + name: "Lint XML format",\n +\n + /**\n + * Return opening root XML tag.\n + * @return {String} to prepend before all results\n + */\n + startFormat: function(){\n + return "\074?xml version=\\"1.0\\" encoding=\\"utf-8\\"?\076\074lint\076";\n + },\n +\n + /**\n + * Return closing root XML tag.\n + * @return {String} to append after all results\n + */\n + endFormat: function(){\n + return "\074/lint\076";\n + },\n +\n + /**\n + * Given CSS Lint results for a file, return output for this format.\n + * @param results {Object} with error and warning messages\n + * @param filename {String} relative file path\n + * @param options {Object} (UNUSED for now) specifies special handling of output\n + * @return {String} output for results\n + */\n + formatResults: function(results, filename, options) {\n + var messages = results.messages,\n + output = [];\n +\n + /**\n + * Replace special characters before write to output.\n + *\n + * Rules:\n + * - single quotes is the escape sequence for double-quotes\n + * - \046amp; is the escape sequence for \046\n + * - \046lt; is the escape sequence for \074\n + * - \046gt; is the escape sequence for \076\n + *\n + * @param {String} message to escape\n + * @return escaped message as {String}\n + */\n + var escapeSpecialCharacters = function(str) {\n + if (!str || str.constructor !== String) {\n + return "";\n + }\n + return str.replace(/\\"/g, "\'").replace(/\046/g, "\046amp;").replace(/\074/g, "\046lt;").replace(/\076/g, "\046gt;");\n + };\n +\n + if (messages.length \076 0) {\n +\n + output.push("\074file name=\\""+filename+"\\"\076");\n + CSSLint.Util.forEach(messages, function (message, i) {\n + if (message.rollup) {\n + output.push("\074issue severity=\\"" + message.type + "\\" reason=\\"" + escapeSpecialCharacters(message.message) + "\\" evidence=\\"" + escapeSpecialCharacters(message.evidence) + "\\"/\076");\n + } else {\n + output.push("\074issue line=\\"" + message.line + "\\" char=\\"" + message.col + "\\" severity=\\"" + message.type + "\\"" +\n + " reason=\\"" + escapeSpecialCharacters(message.message) + "\\" evidence=\\"" + escapeSpecialCharacters(message.evidence) + "\\"/\076");\n + }\n + });\n + output.push("\074/file\076");\n + }\n +\n + return output.join("");\n + }\n +});\n +/*global CSSLint*/\n +CSSLint.addFormatter({\n + //format information\n + id: "text",\n + name: "Plain Text",\n +\n + /**\n + * Return content to be printed before all file results.\n + * @return {String} to prepend before all results\n + */\n + startFormat: function() {\n + return "";\n + },\n +\n + /**\n + * Return content to be printed after all file results.\n + * @return {String} to append after all results\n + */\n + endFormat: function() {\n + return "";\n + },\n +\n + /**\n + * Given CSS Lint results for a file, return output for this format.\n + * @param results {Object} with error and warning messages\n + * @param filename {String} relative file path\n + * @param options {Object} (Optional) specifies special handling of output\n + * @return {String} output for results\n + */\n + formatResults: function(results, filename, options) {\n + var messages = results.messages,\n + output = "";\n + options = options || {};\n +\n + if (messages.length === 0) {\n + return options.quiet ? "" : "\\n\\ncsslint: No errors in " + filename + ".";\n + }\n +\n + output = "\\n\\ncsslint: There are " + messages.length + " problems in " + filename + ".";\n + var pos = filename.lastIndexOf("/"),\n + shortFilename = filename;\n +\n + if (pos === -1){\n + pos = filename.lastIndexOf("\\\\");\n + }\n + if (pos \076 -1){\n + shortFilename = filename.substring(pos+1);\n + }\n +\n + CSSLint.Util.forEach(messages, function (message, i) {\n + output = output + "\\n\\n" + shortFilename;\n + if (message.rollup) {\n + output += "\\n" + (i+1) + ": " + message.type;\n + output += "\\n" + message.message;\n + } else {\n + output += "\\n" + (i+1) + ": " + message.type + " at line " + message.line + ", col " + message.col;\n + output += "\\n" + message.message;\n + output += "\\n" + message.evidence;\n + }\n + });\n +\n + return output;\n + }\n +});\n +return CSSLint;\n +})();</string> </value> + </item> + <item> + <key> <string>next</string> </key> + <value> + <none/> + </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/jshint.js.xml b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/jshint.js.xml new file mode 100644 index 0000000000000000000000000000000000000000..5f56eccccb9e205471257cd26ebde0452ceabcb1 --- /dev/null +++ b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/jshint.js.xml @@ -0,0 +1,4611 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="File" module="OFS.Image"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_EtagSupport__etag</string> </key> + <value> <string>ts29784793.18</string> </value> + </item> + <item> + <key> <string>__name__</string> </key> + <value> <string>jshint.js</string> </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>application/javascript</string> </value> + </item> + <item> + <key> <string>data</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> + </value> + </item> + <item> + <key> <string>precondition</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>size</string> </key> + <value> <int>163537</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> + <record id="2" aka="AAAAAAAAAAI="> + <pickle> + <global name="Pdata" module="OFS.Image"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>data</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +/*!\n + * JSHint, by JSHint Community.\n + *\n + * Licensed under the same slightly modified MIT license that JSLint is.\n + * It stops evil-doers everywhere.\n + *\n + * JSHint is a derivative work of JSLint:\n + *\n + * Copyright (c) 2002 Douglas Crockford (www.JSLint.com)\n + *\n + * Permission is hereby granted, free of charge, to any person obtaining\n + * a copy of this software and associated documentation files (the "Software"),\n + * to deal in the Software without restriction, including without limitation\n + * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n + * and/or sell copies of the Software, and to permit persons to whom\n + * the Software is furnished to do so, subject to the following conditions:\n + *\n + * The above copyright notice and this permission notice shall be included\n + * in all copies or substantial portions of the Software.\n + *\n + * The Software shall be used for Good, not Evil.\n + *\n + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n + * DEALINGS IN THE SOFTWARE.\n + *\n + * JSHint was forked from 2010-12-16 edition of JSLint.\n + *\n + */\n +\n +/*\n + JSHINT is a global function. It takes two parameters.\n +\n + var myResult = JSHINT(source, option);\n +\n + The first parameter is either a string or an array of strings. If it is a\n + string, it will be split on \'\\n\' or \'\\r\'. If it is an array of strings, it\n + is assumed that each string represents one line. The source can be a\n + JavaScript text or a JSON text.\n +\n + The second parameter is an optional object of options which control the\n + operation of JSHINT. Most of the options are booleans: They are all\n + optional and have a default value of false. One of the options, predef,\n + can be an array of names, which will be used to declare global variables,\n + or an object whose keys are used as global names, with a boolean value\n + that determines if they are assignable.\n +\n + If it checks out, JSHINT returns true. Otherwise, it returns false.\n +\n + If false, you can inspect JSHINT.errors to find out the problems.\n + JSHINT.errors is an array of objects containing these members:\n +\n + {\n + line : The line (relative to 0) at which the lint was found\n + character : The character (relative to 0) at which the lint was found\n + reason : The problem\n + evidence : The text line in which the problem occurred\n + raw : The raw message before the details were inserted\n + a : The first detail\n + b : The second detail\n + c : The third detail\n + d : The fourth detail\n + }\n +\n + If a fatal error was found, a null will be the last element of the\n + JSHINT.errors array.\n +\n + You can request a Function Report, which shows all of the functions\n + and the parameters and vars that they use. This can be used to find\n + implied global variables and other problems. The report is in HTML and\n + can be inserted in an HTML <body>.\n +\n + var myReport = JSHINT.report(limited);\n +\n + If limited is true, then the report will be limited to only errors.\n +\n + You can request a data structure which contains JSHint\'s results.\n +\n + var myData = JSHINT.data();\n +\n + It returns a structure with this form:\n +\n + {\n + errors: [\n + {\n + line: NUMBER,\n + character: NUMBER,\n + reason: STRING,\n + evidence: STRING\n + }\n + ],\n + functions: [\n + name: STRING,\n + line: NUMBER,\n + last: NUMBER,\n + param: [\n + STRING\n + ],\n + closure: [\n + STRING\n + ],\n + var: [\n + STRING\n + ],\n + exception: [\n + STRING\n + ],\n + outer: [\n + STRING\n + ],\n + unused: [\n + STRING\n + ],\n + global: [\n + STRING\n + ],\n + label: [\n + STRING\n + ]\n + ],\n + globals: [\n + STRING\n + ],\n + member: {\n + STRING: NUMBER\n + },\n + unused: [\n + {\n + name: STRING,\n + line: NUMBER\n + }\n + ],\n + implieds: [\n + {\n + name: STRING,\n + line: NUMBER\n + }\n + ],\n + urls: [\n + STRING\n + ],\n + json: BOOLEAN\n + }\n +\n + Empty arrays will not be included.\n +\n +*/\n +\n +/*jshint\n + evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true,\n + undef: true, maxlen: 100, indent:4\n +*/\n +\n +/*members "\\b", "\\t", "\\n", "\\f", "\\r", "!=", "!==", "\\"", "%", "(begin)",\n + "(breakage)", "(context)", "(error)", "(global)", "(identifier)", "(last)",\n + "(line)", "(loopage)", "(name)", "(onevar)", "(params)", "(scope)",\n + "(statement)", "(verb)", "*", "+", "++", "-", "--", "\\/", "<", "<=", "==",\n + "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax,\n + __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView, Audio,\n + Autocompleter, Assets, Boolean, Builder, Buffer, Browser, COM, CScript, Canvas,\n + CustomAnimation, Class, Control, Chain, Color, Cookie, Core, DataView, Date,\n + Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMReady, DOMParser, Drag,\n + E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event,\n + Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form,\n + FormField, Frame, FormData, Function, Fx, GetObject, Group, Hash, HotKey,\n + HTMLElement, HTMLAnchorElement, HTMLBaseElement, HTMLBlockquoteElement,\n + HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLDirectoryElement,\n + HTMLDivElement, HTMLDListElement, HTMLFieldSetElement,\n + HTMLFontElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement,\n + HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement,\n + HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLIsIndexElement,\n + HTMLLabelElement, HTMLLayerElement, HTMLLegendElement, HTMLLIElement,\n + HTMLLinkElement, HTMLMapElement, HTMLMenuElement, HTMLMetaElement,\n + HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement,\n + HTMLOptionElement, HTMLParagraphElement, HTMLParamElement, HTMLPreElement,\n + HTMLQuoteElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement,\n + HtmlTable, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement,\n + HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement,\n + HTMLTextAreaElement, HTMLTitleElement, HTMLUListElement, HTMLVideoElement,\n + Iframe, IframeShim, Image, Int16Array, Int32Array, Int8Array,\n + Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E,\n + MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem, MessageChannel, MessageEvent, MessagePort,\n + MoveAnimation, MooTools, Native, NEGATIVE_INFINITY, Number, Object, ObjectRange, Option,\n + Options, OverText, PI, POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype,\n + RangeError, Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation,\n + SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion,\n + ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller,\n + Slick, Slider, Selector, SharedWorker, String, Style, SyntaxError, Sortable, Sortables,\n + SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template,\n + Timer, Tips, Type, TypeError, Toggle, Try, "use strict", unescape, URI, URIError, URL,\n + VBArray, WSH, WScript, XDomainRequest, Web, Window, XMLDOM, XMLHttpRequest, XMLSerializer,\n + XPathEvaluator, XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult,\n + "\\\\", a, addEventListener, address, alert, apply, applicationCache, arguments, arity, asi, atob,\n + b, basic, basicToken, bitwise, block, blur, boolOptions, boss, browser, btoa, c, call, callee,\n + caller, cases, charAt, charCodeAt, character, clearInterval, clearTimeout,\n + close, closed, closure, comment, condition, confirm, console, constructor,\n + content, couch, create, css, curly, d, data, datalist, dd, debug, decodeURI,\n + decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document,\n + dojo, dijit, dojox, define, else, emit, encodeURI, encodeURIComponent,\n + entityify, eqeq, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil,\n + ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus,\n + forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions,\n + g, gc, getComputedStyle, getRow, getter, getterToken, GLOBAL, global, globals, globalstrict,\n + hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include,\n + indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray,\n + isDigit, isFinite, isNaN, iterator, java, join, jshint,\n + JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastsemic, laxbreak, laxcomma,\n + latedef, lbp, led, left, length, line, load, loadClass, localStorage, location,\n + log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy,\n + moveTo, mootools, multistr, name, navigator, new, newcap, noarg, node, noempty, nomen,\n + nonew, nonstandard, nud, onbeforeunload, onblur, onerror, onevar, onecase, onfocus,\n + onload, onresize, onunload, open, openDatabase, openURL, opener, opera, options, outer, param,\n + parent, parseFloat, parseInt, passfail, plusplus, predef, print, process, prompt,\n + proto, prototype, prototypejs, provides, push, quit, range, raw, reach, reason, regexp,\n + readFile, readUrl, regexdash, removeEventListener, replace, report, require,\n + reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right,\n + runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal,\n + send, serialize, sessionStorage, setInterval, setTimeout, setter, setterToken, shift, slice,\n + smarttabs, sort, spawn, split, stack, status, start, strict, sub, substr, supernew, shadow,\n + supplant, sum, sync, test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing,\n + type, typeOf, Uint16Array, Uint32Array, Uint8Array, undef, undefs, unused, urls, validthis,\n + value, valueOf, var, vars, version, WebSocket, withstmt, white, window, windows, Worker, wsh*/\n +\n +/*global exports: false */\n +\n +// We build the application inside a function so that we produce only a single\n +// global variable. That function will be invoked immediately, and its return\n +// value is the JSHINT function itself.\n +\n +var JSHINT = (function () {\n + "use strict";\n +\n + var anonname, // The guessed name for anonymous functions.\n +\n +// These are operators that should not be used with the ! operator.\n +\n + bang = {\n + \'<\' : true,\n + \'<=\' : true,\n + \'==\' : true,\n + \'===\': true,\n + \'!==\': true,\n + \'!=\' : true,\n + \'>\' : true,\n + \'>=\' : true,\n + \'+\' : true,\n + \'-\' : true,\n + \'*\' : true,\n + \'/\' : true,\n + \'%\' : true\n + },\n +\n + // These are the JSHint boolean options.\n + boolOptions = {\n + asi : true, // if automatic semicolon insertion should be tolerated\n + bitwise : true, // if bitwise operators should not be allowed\n + boss : true, // if advanced usage of assignments should be allowed\n + browser : true, // if the standard browser globals should be predefined\n + couch : true, // if CouchDB globals should be predefined\n + curly : true, // if curly braces around all blocks should be required\n + debug : true, // if debugger statements should be allowed\n + devel : true, // if logging globals should be predefined (console,\n + // alert, etc.)\n + dojo : true, // if Dojo Toolkit globals should be predefined\n + eqeqeq : true, // if === should be required\n + eqnull : true, // if == null comparisons should be tolerated\n + es5 : true, // if ES5 syntax should be allowed\n + esnext : true, // if es.next specific syntax should be allowed\n + evil : true, // if eval should be allowed\n + expr : true, // if ExpressionStatement should be allowed as Programs\n + forin : true, // if for in statements must filter\n + funcscope : true, // if only function scope should be used for scope tests\n + globalstrict: true, // if global "use strict"; should be allowed (also\n + // enables \'strict\')\n + immed : true, // if immediate invocations must be wrapped in parens\n + iterator : true, // if the `__iterator__` property should be allowed\n + jquery : true, // if jQuery globals should be predefined\n + lastsemic : true, // if semicolons may be ommitted for the trailing\n + // statements inside of a one-line blocks.\n + latedef : true, // if the use before definition should not be tolerated\n + laxbreak : true, // if line breaks should not be checked\n + laxcomma : true, // if line breaks should not be checked around commas\n + loopfunc : true, // if functions should be allowed to be defined within\n + // loops\n + mootools : true, // if MooTools globals should be predefined\n + multistr : true, // allow multiline strings\n + newcap : true, // if constructor names must be capitalized\n + noarg : true, // if arguments.caller and arguments.callee should be\n + // disallowed\n + node : true, // if the Node.js environment globals should be\n + // predefined\n + noempty : true, // if empty blocks should be disallowed\n + nonew : true, // if using `new` for side-effects should be disallowed\n + nonstandard : true, // if non-standard (but widely adopted) globals should\n + // be predefined\n + nomen : true, // if names should be checked\n + onevar : true, // if only one var statement per function should be\n + // allowed\n + onecase : true, // if one case switch statements should be allowed\n + passfail : true, // if the scan should stop on first error\n + plusplus : true, // if increment/decrement should not be allowed\n + proto : true, // if the `__proto__` property should be allowed\n + prototypejs : true, // if Prototype and Scriptaculous globals should be\n + // predefined\n + regexdash : true, // if unescaped first/last dash (-) inside brackets\n + // should be tolerated\n + regexp : true, // if the . should not be allowed in regexp literals\n + rhino : true, // if the Rhino environment globals should be predefined\n + undef : true, // if variables should be declared before used\n + scripturl : true, // if script-targeted URLs should be tolerated\n + shadow : true, // if variable shadowing should be tolerated\n + smarttabs : true, // if smarttabs should be tolerated\n + // (http://www.emacswiki.org/emacs/SmartTabs)\n + strict : true, // require the "use strict"; pragma\n + sub : true, // if all forms of subscript notation are tolerated\n + supernew : true, // if `new function () { ... };` and `new Object;`\n + // should be tolerated\n + trailing : true, // if trailing whitespace rules apply\n + validthis : true, // if \'this\' inside a non-constructor function is valid.\n + // This is a function scoped option only.\n + withstmt : true, // if with statements should be allowed\n + white : true, // if strict whitespace rules apply\n + wsh : true // if the Windows Scripting Host environment globals\n + // should be predefined\n + },\n +\n + // These are the JSHint options that can take any value\n + // (we use this object to detect invalid options)\n + valOptions = {\n + maxlen: false,\n + indent: false,\n + maxerr: false,\n + predef: false\n + },\n +\n + // These are JSHint boolean options which are shared with JSLint\n + // where the definition in JSHint is opposite JSLint\n + invertedOptions = {\n + bitwise : true,\n + forin : true,\n + newcap : true,\n + nomen : true,\n + plusplus : true,\n + regexp : true,\n + undef : true,\n + white : true,\n +\n + // Inverted and renamed, use JSHint name here\n + eqeqeq : true,\n + onevar : true\n + },\n +\n + // These are JSHint boolean options which are shared with JSLint\n + // where the name has been changed but the effect is unchanged\n + renamedOptions = {\n + eqeq : "eqeqeq",\n + vars : "onevar",\n + windows : "wsh"\n + },\n +\n +\n + // browser contains a set of global names which are commonly provided by a\n + // web browser environment.\n + browser = {\n + ArrayBuffer : false,\n + ArrayBufferView : false,\n + Audio : false,\n + addEventListener : false,\n + applicationCache : false,\n + atob : false,\n + blur : false,\n + btoa : false,\n + clearInterval : false,\n + clearTimeout : false,\n + close : false,\n + closed : false,\n + DataView : false,\n + DOMParser : false,\n + defaultStatus : false,\n + document : false,\n + event : false,\n + FileReader : false,\n + Float32Array : false,\n + Float64Array : false,\n + FormData : false,\n + focus : false,\n + frames : false,\n + getComputedStyle : false,\n + HTMLElement : false,\n + HTMLAnchorElement : false,\n + HTMLBaseElement : false,\n + HTMLBlockquoteElement : false,\n + HTMLBodyElement : false,\n + HTMLBRElement : false,\n + HTMLButtonElement : false,\n + HTMLCanvasElement : false,\n + HTMLDirectoryElement : false,\n + HTMLDivElement : false,\n + HTMLDListElement : false,\n + HTMLFieldSetElement : false,\n + HTMLFontElement : false,\n + HTMLFormElement : false,\n + HTMLFrameElement : false,\n + HTMLFrameSetElement : false,\n + HTMLHeadElement : false,\n + HTMLHeadingElement : false,\n + HTMLHRElement : false,\n + HTMLHtmlElement : false,\n + HTMLIFrameElement : false,\n + HTMLImageElement : false,\n + HTMLInputElement : false,\n + HTMLIsIndexElement : false,\n + HTMLLabelElement : false,\n + HTMLLayerElement : false,\n + HTMLLegendElement : false,\n + HTMLLIElement : false,\n + HTMLLinkElement : false,\n + HTMLMapElement : false,\n + HTMLMenuElement : false,\n + HTMLMetaElement : false,\n + HTMLModElement : false,\n + HTMLObjectElement : false,\n + HTMLOListElement : false,\n + HTMLOptGroupElement : false,\n + HTMLOptionElement : false,\n + HTMLParagraphElement : false,\n + HTMLParamElement : false,\n + HTMLPreElement : false,\n + HTMLQuoteElement : false,\n + HTMLScriptElement : false,\n + HTMLSelectElement : false,\n + HTMLStyleElement : false,\n + HTMLTableCaptionElement : false,\n + HTMLTableCellElement : false,\n + HTMLTableColElement : false,\n + HTMLTableElement : false,\n + HTMLTableRowElement : false,\n + HTMLTableSectionElement : false,\n + HTMLTextAreaElement : false,\n + HTMLTitleElement : false,\n + HTMLUListElement : false,\n + HTMLVideoElement : false,\n + history : false,\n + Int16Array : false,\n + Int32Array : false,\n + Int8Array : false,\n + Image : false,\n + length : false,\n + localStorage : false,\n + location : false,\n + MessageChannel : false,\n + MessageEvent : false,\n + MessagePort : false,\n + moveBy : false,\n + moveTo : false,\n + name : false,\n + navigator : false,\n + onbeforeunload : true,\n + onblur : true,\n + onerror : true,\n + onfocus : true,\n + onload : true,\n + onresize : true,\n + onunload : true,\n + open : false,\n + openDatabase : false,\n + opener : false,\n + Option : false,\n + parent : false,\n + print : false,\n + removeEventListener : false,\n + resizeBy : false,\n + resizeTo : false,\n + screen : false,\n + scroll : false,\n + scrollBy : false,\n + scrollTo : false,\n + sessionStorage : false,\n + setInterval : false,\n + setTimeout : false,\n + SharedWorker : false,\n + status : false,\n + top : false,\n + Uint16Array : false,\n + Uint32Array : false,\n + Uint8Array : false,\n + WebSocket : false,\n + window : false,\n + Worker : false,\n + XMLHttpRequest : false,\n + XMLSerializer : false,\n + XPathEvaluator : false,\n + XPathException : false,\n + XPathExpression : false,\n + XPathNamespace : false,\n + XPathNSResolver : false,\n + XPathResult : false\n + },\n +\n + couch = {\n + "require" : false,\n + respond : false,\n + getRow : false,\n + emit : false,\n + send : false,\n + start : false,\n + sum : false,\n + log : false,\n + exports : false,\n + module : false,\n + provides : false\n + },\n +\n + devel = {\n + alert : false,\n + confirm : false,\n + console : false,\n + Debug : false,\n + opera : false,\n + prompt : false\n + },\n +\n + dojo = {\n + dojo : false,\n + dijit : false,\n + dojox : false,\n + define : false,\n + "require" : false\n + },\n +\n + escapes = {\n + \'\\b\': \'\\\\b\',\n + \'\\t\': \'\\\\t\',\n + \'\\n\': \'\\\\n\',\n + \'\\f\': \'\\\\f\',\n + \'\\r\': \'\\\\r\',\n + \'"\' : \'\\\\"\',\n + \'/\' : \'\\\\/\',\n + \'\\\\\': \'\\\\\\\\\'\n + },\n +\n + funct, // The current function\n +\n + functionicity = [\n + \'closure\', \'exception\', \'global\', \'label\',\n + \'outer\', \'unused\', \'var\'\n + ],\n +\n + functions, // All of the functions\n +\n + global, // The global scope\n + implied, // Implied globals\n + inblock,\n + indent,\n + jsonmode,\n +\n + jquery = {\n + \'$\' : false,\n + jQuery : false\n + },\n +\n + lines,\n + lookahead,\n + member,\n + membersOnly,\n +\n + mootools = {\n + \'$\' : false,\n + \'$$\' : false,\n + Assets : false,\n + Browser : false,\n + Chain : false,\n + Class : false,\n + Color : false,\n + Cookie : false,\n + Core : false,\n + Document : false,\n + DomReady : false,\n + DOMReady : false,\n + Drag : false,\n + Element : false,\n + Elements : false,\n + Event : false,\n + Events : false,\n + Fx : false,\n + Group : false,\n + Hash : false,\n + HtmlTable : false,\n + Iframe : false,\n + IframeShim : false,\n + InputValidator : false,\n + instanceOf : false,\n + Keyboard : false,\n + Locale : false,\n + Mask : false,\n + MooTools : false,\n + Native : false,\n + Options : false,\n + OverText : false,\n + Request : false,\n + Scroller : false,\n + Slick : false,\n + Slider : false,\n + Sortables : false,\n + Spinner : false,\n + Swiff : false,\n + Tips : false,\n + Type : false,\n + typeOf : false,\n + URI : false,\n + Window : false\n + },\n +\n + nexttoken,\n +\n + node = {\n + __filename : false,\n + __dirname : false,\n + Buffer : false,\n + console : false,\n + exports : false,\n + GLOBAL : false,\n + global : false,\n + module : false,\n + process : false,\n + require : false,\n + setTimeout : false,\n + clearTimeout : false,\n + setInterval : false,\n + clearInterval : false\n + },\n +\n + noreach,\n + option,\n + predefined, // Global variables defined by option\n + prereg,\n + prevtoken,\n +\n + prototypejs = {\n + \'$\' : false,\n + \'$$\' : false,\n + \'$A\' : false,\n + \'$F\' : false,\n + \'$H\' : false,\n + \'$R\' : false,\n + \'$break\' : false,\n + \'$continue\' : false,\n + \'$w\' : false,\n + Abstract : false,\n + Ajax : false,\n + Class : false,\n + Enumerable : false,\n + Element : false,\n + Event : false,\n + Field : false,\n + Form : false,\n + Hash : false,\n + Insertion : false,\n + ObjectRange : false,\n + PeriodicalExecuter: false,\n + Position : false,\n + Prototype : false,\n + Selector : false,\n + Template : false,\n + Toggle : false,\n + Try : false,\n + Autocompleter : false,\n + Builder : false,\n + Control : false,\n + Draggable : false,\n + Draggables : false,\n + Droppables : false,\n + Effect : false,\n + Sortable : false,\n + SortableObserver : false,\n + Sound : false,\n + Scriptaculous : false\n + },\n +\n + rhino = {\n + defineClass : false,\n + deserialize : false,\n + gc : false,\n + help : false,\n + importPackage: false,\n + "java" : false,\n + load : false,\n + loadClass : false,\n + print : false,\n + quit : false,\n + readFile : false,\n + readUrl : false,\n + runCommand : false,\n + seal : false,\n + serialize : false,\n + spawn : false,\n + sync : false,\n + toint32 : false,\n + version : false\n + },\n +\n + scope, // The current scope\n + stack,\n +\n + // standard contains the global names that are provided by the\n + // ECMAScript standard.\n + standard = {\n + Array : false,\n + Boolean : false,\n + Date : false,\n + decodeURI : false,\n + decodeURIComponent : false,\n + encodeURI : false,\n + encodeURIComponent : false,\n + Error : false,\n + \'eval\' : false,\n + EvalError : false,\n + Function : false,\n + hasOwnProperty : false,\n + isFinite : false,\n + isNaN : false,\n + JSON : false,\n + Math : false,\n + Number : false,\n + Object : false,\n + parseInt : false,\n + parseFloat : false,\n + RangeError : false,\n + ReferenceError : false,\n + RegExp : false,\n + String : false,\n + SyntaxError : false,\n + TypeError : false,\n + URIError : false\n + },\n +\n + // widely adopted global names that are not part of ECMAScript standard\n + nonstandard = {\n + escape : false,\n + unescape : false\n + },\n +\n + standard_member = {\n + E : true,\n + LN2 : true,\n + LN10 : true,\n + LOG2E : true,\n + LOG10E : true,\n + MAX_VALUE : true,\n + MIN_VALUE : true,\n + NEGATIVE_INFINITY : true,\n + PI : true,\n + POSITIVE_INFINITY : true,\n + SQRT1_2 : true,\n + SQRT2 : true\n + },\n +\n + directive,\n + syntax = {},\n + tab,\n + token,\n + urls,\n + useESNextSyntax,\n + warnings,\n +\n + wsh = {\n + ActiveXObject : true,\n + Enumerator : true,\n + GetObject : true,\n + ScriptEngine : true,\n + ScriptEngineBuildVersion : true,\n + ScriptEngineMajorVersion : true,\n + ScriptEngineMinorVersion : true,\n + VBArray : true,\n + WSH : true,\n + WScript : true,\n + XDomainRequest : true\n + };\n +\n + // Regular expressions. Some of these are stupidly long.\n + var ax, cx, tx, nx, nxg, lx, ix, jx, ft;\n + (function () {\n + /*jshint maxlen:300 */\n +\n + // unsafe comment or string\n + ax = /@cc|<\\/?|script|\\]\\s*\\]|<\\s*!|</i;\n +\n + // unsafe characters that are silently deleted by one or more browsers\n + cx = /[\\u0000-\\u001f\\u007f-\\u009f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/;\n +\n + // token\n + tx = /^\\s*([(){}\\[.,:;\'"~\\?\\]#@]|==?=?|\\/(\\*(jshint|jslint|members?|global)?|=|\\/)?|\\*[\\/=]?|\\+(?:=|\\++)?|-(?:=|-+)?|%=?|&[&=]?|\\|[|=]?|>>?>?=?|<([\\/=!]|\\!(\\[|--)?|<=?)?|\\^=?|\\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\\.[0-9]*)?([eE][+\\-]?[0-9]+)?)/;\n +\n + // characters in strings that need escapement\n + nx = /[\\u0000-\\u001f&<"\\/\\\\\\u007f-\\u009f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/;\n + nxg = /[\\u0000-\\u001f&<"\\/\\\\\\u007f-\\u009f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g;\n +\n + // star slash\n + lx = /\\*\\/|\\/\\*/;\n +\n + // identifier\n + ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;\n +\n + // javascript url\n + jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\\s*:/i;\n +\n + // catches /* falls through */ comments\n + ft = /^\\s*\\/\\*\\s*falls\\sthrough\\s*\\*\\/\\s*$/;\n + }());\n +\n + function F() {} // Used by Object.create\n +\n + function is_own(object, name) {\n +\n +// The object.hasOwnProperty method fails when the property under consideration\n +// is named \'hasOwnProperty\'. So we have to use this more convoluted form.\n +\n + return Object.prototype.hasOwnProperty.call(object, name);\n + }\n +\n + function checkOption(name, t) {\n + if (valOptions[name] === undefined && boolOptions[name] === undefined) {\n + warning("Bad option: \'" + name + "\'.", t);\n + }\n + }\n +\n +// Provide critical ES5 functions to ES3.\n +\n + if (typeof Array.isArray !== \'function\') {\n + Array.isArray = function (o) {\n + return Object.prototype.toString.apply(o) === \'[object Array]\';\n + };\n + }\n +\n + if (typeof Object.create !== \'function\') {\n + Object.create = function (o) {\n + F.prototype = o;\n + return new F();\n + };\n + }\n +\n + if (typeof Object.keys !== \'function\') {\n + Object.keys = function (o) {\n + var a = [], k;\n + for (k in o) {\n + if (is_own(o, k)) {\n + a.push(k);\n + }\n + }\n + return a;\n + };\n + }\n +\n +// Non standard methods\n +\n + if (typeof String.prototype.entityify !== \'function\') {\n + String.prototype.entityify = function () {\n + return this\n + .replace(/&/g, \'&\')\n + .replace(/</g, \'<\')\n + .replace(/>/g, \'>\');\n + };\n + }\n +\n + if (typeof String.prototype.isAlpha !== \'function\') {\n + String.prototype.isAlpha = function () {\n + return (this >= \'a\' && this <= \'z\\uffff\') ||\n + (this >= \'A\' && this <= \'Z\\uffff\');\n + };\n + }\n +\n + if (typeof String.prototype.isDigit !== \'function\') {\n + String.prototype.isDigit = function () {\n + return (this >= \'0\' && this <= \'9\');\n + };\n + }\n +\n + if (typeof String.prototype.supplant !== \'function\') {\n + String.prototype.supplant = function (o) {\n + return this.replace(/\\{([^{}]*)\\}/g, function (a, b) {\n + var r = o[b];\n + return typeof r === \'string\' || typeof r === \'number\' ? r : a;\n + });\n + };\n + }\n +\n + if (typeof String.prototype.name !== \'function\') {\n + String.prototype.name = function () {\n +\n +// If the string looks like an identifier, then we can return it as is.\n +// If the string contains no control characters, no quote characters, and no\n +// backslash characters, then we can simply slap some quotes around it.\n +// Otherwise we must also replace the offending characters with safe\n +// sequences.\n +\n + if (ix.test(this)) {\n + return this;\n + }\n + if (nx.test(this)) {\n + return \'"\' + this.replace(nxg, function (a) {\n + var c = escapes[a];\n + if (c) {\n + return c;\n + }\n + return \'\\\\u\' + (\'0000\' + a.charCodeAt().toString(16)).slice(-4);\n + }) + \'"\';\n + }\n + return \'"\' + this + \'"\';\n + };\n + }\n +\n +\n + function combine(t, o) {\n + var n;\n + for (n in o) {\n + if (is_own(o, n)) {\n + t[n] = o[n];\n + }\n + }\n + }\n +\n + function assume() {\n + if (option.couch) {\n + combine(predefined, couch);\n + }\n +\n + if (option.rhino) {\n + combine(predefined, rhino);\n + }\n +\n + if (option.prototypejs) {\n + combine(predefined, prototypejs);\n + }\n +\n + if (option.node) {\n + combine(predefined, node);\n + option.globalstrict = true;\n + }\n +\n + if (option.devel) {\n + combine(predefined, devel);\n + }\n +\n + if (option.dojo) {\n + combine(predefined, dojo);\n + }\n +\n + if (option.browser) {\n + combine(predefined, browser);\n + }\n +\n + if (option.nonstandard) {\n + combine(predefined, nonstandard);\n + }\n +\n + if (option.jquery) {\n + combine(predefined, jquery);\n + }\n +\n + if (option.mootools) {\n + combine(predefined, mootools);\n + }\n +\n + if (option.wsh) {\n + combine(predefined, wsh);\n + }\n +\n + if (option.esnext) {\n + useESNextSyntax();\n + }\n +\n + if (option.globalstrict && option.strict !== false) {\n + option.strict = true;\n + }\n + }\n +\n +\n + // Produce an error warning.\n + function quit(message, line, chr) {\n + var percentage = Math.floor((line / lines.length) * 100);\n +\n + throw {\n + name: \'JSHintError\',\n + line: line,\n + character: chr,\n + message: message + " (" + percentage + "% scanned).",\n + raw: message\n + };\n + }\n +\n + function isundef(scope, m, t, a) {\n + return JSHINT.undefs.push([scope, m, t, a]);\n + }\n +\n + function warning(m, t, a, b, c, d) {\n + var ch, l, w;\n + t = t || nexttoken;\n + if (t.id === \'(end)\') { // `~\n + t = token;\n + }\n + l = t.line || 0;\n + ch = t.from || 0;\n + w = {\n + id: \'(error)\',\n + raw: m,\n + evidence: lines[l - 1] || \'\',\n + line: l,\n + character: ch,\n + a: a,\n + b: b,\n + c: c,\n + d: d\n + };\n + w.reason = m.supplant(w);\n + JSHINT.errors.push(w);\n + if (option.passfail) {\n + quit(\'Stopping. \', l, ch);\n + }\n + warnings += 1;\n + if (warnings >= option.maxerr) {\n + quit("Too many errors.", l, ch);\n + }\n + return w;\n + }\n +\n + function warningAt(m, l, ch, a, b, c, d) {\n + return warning(m, {\n + line: l,\n + from: ch\n + }, a, b, c, d);\n + }\n +\n + function error(m, t, a, b, c, d) {\n + var w = warning(m, t, a, b, c, d);\n + }\n +\n + function errorAt(m, l, ch, a, b, c, d) {\n + return error(m, {\n + line: l,\n + from: ch\n + }, a, b, c, d);\n + }\n +\n +\n +\n +// lexical analysis and token construction\n +\n + var lex = (function lex() {\n + var character, from, line, s;\n +\n +// Private lex methods\n +\n + function nextLine() {\n + var at,\n + tw; // trailing whitespace check\n +\n + if (line >= lines.length)\n + return false;\n +\n + character = 1;\n + s = lines[line];\n + line += 1;\n +\n + // If smarttabs option is used check for spaces followed by tabs only.\n + // Otherwise check for any occurence of mixed tabs and spaces.\n + if (option.smarttabs)\n + at = s.search(/ \\t/);\n + else\n + at = s.search(/ \\t|\\t /);\n +\n + if (at >= 0)\n + warningAt("Mixed spaces and tabs.", line, at + 1);\n +\n + s = s.replace(/\\t/g, tab);\n + at = s.search(cx);\n +\n + if (at >= 0)\n + warningAt("Unsafe character.", line, at);\n +\n + if (option.maxlen && option.maxlen < s.length)\n + warningAt("Line too long.", line, s.length);\n +\n + // Check for trailing whitespaces\n + tw = option.trailing && s.match(/^(.*?)\\s+$/);\n + if (tw && !/^\\s+$/.test(s)) {\n + warningAt("Trailing whitespace.", line, tw[1].length + 1);\n + }\n + return true;\n + }\n +\n +// Produce a token object. The token inherits from a syntax symbol.\n +\n + function it(type, value) {\n + var i, t;\n + if (type === \'(color)\' || type === \'(range)\') {\n + t = {type: type};\n + } else if (type === \'(punctuator)\' ||\n + (type === \'(identifier)\' && is_own(syntax, value))) {\n + t = syntax[value] || syntax[\'(error)\'];\n + } else {\n + t = syntax[type];\n + }\n + t = Object.create(t);\n + if (type === \'(string)\' || type === \'(range)\') {\n + if (!option.scripturl && jx.test(value)) {\n + warningAt("Script URL.", line, from);\n + }\n + }\n + if (type === \'(identifier)\') {\n + t.identifier = true;\n + if (value === \'__proto__\' && !option.proto) {\n + warningAt("The \'{a}\' property is deprecated.",\n + line, from, value);\n + } else if (value === \'__iterator__\' && !option.iterator) {\n + warningAt("\'{a}\' is only available in JavaScript 1.7.",\n + line, from, value);\n + } else if (option.nomen && (value.charAt(0) === \'_\' ||\n + value.charAt(value.length - 1) === \'_\')) {\n + if (!option.node || token.id === \'.\' ||\n + (value !== \'__dirname\' && value !== \'__filename\')) {\n + warningAt("Unexpected {a} in \'{b}\'.", line, from, "dangling \'_\'", value);\n + }\n + }\n + }\n + t.value = value;\n + t.line = line;\n + t.character = character;\n + t.from = from;\n + i = t.id;\n + if (i !== \'(endline)\') {\n + prereg = i &&\n + ((\'(,=:[!&|?{};\'.indexOf(i.charAt(i.length - 1)) >= 0) ||\n + i === \'return\' ||\n + i === \'case\');\n + }\n + return t;\n + }\n +\n + // Public lex methods\n + return {\n + init: function (source) {\n + if (typeof source === \'string\') {\n + lines = source\n + .replace(/\\r\\n/g, \'\\n\')\n + .replace(/\\r/g, \'\\n\')\n + .split(\'\\n\');\n + } else {\n + lines = source;\n + }\n +\n + // If the first line is a shebang (#!), make it a blank and move on.\n + // Shebangs are used by Node scripts.\n + if (lines[0] && lines[0].substr(0, 2) === \'#!\')\n + lines[0] = \'\';\n +\n + line = 0;\n + nextLine();\n + from = 1;\n + },\n +\n + range: function (begin, end) {\n + var c, value = \'\';\n + from = character;\n + if (s.charAt(0) !== begin) {\n + errorAt("Expected \'{a}\' and instead saw \'{b}\'.",\n + line, character, begin, s.charAt(0));\n + }\n + for (;;) {\n + s = s.slice(1);\n + character += 1;\n + c = s.charAt(0);\n + switch (c) {\n + case \'\':\n + errorAt("Missing \'{a}\'.", line, character, c);\n + break;\n + case end:\n + s = s.slice(1);\n + character += 1;\n + return it(\'(range)\', value);\n + case \'\\\\\':\n + warningAt("Unexpected \'{a}\'.", line, character, c);\n + }\n + value += c;\n + }\n +\n + },\n +\n +\n + // token -- this is called by advance to get the next token\n + token: function () {\n + var b, c, captures, d, depth, high, i, l, low, q, t, isLiteral, isInRange, n;\n +\n + function match(x) {\n + var r = x.exec(s), r1;\n + if (r) {\n + l = r[0].length;\n + r1 = r[1];\n + c = r1.charAt(0);\n + s = s.substr(l);\n + from = character + l - r1.length;\n + character += l;\n + return r1;\n + }\n + }\n +\n + function string(x) {\n + var c, j, r = \'\', allowNewLine = false;\n +\n + if (jsonmode && x !== \'"\') {\n + warningAt("Strings must use doublequote.",\n + line, character);\n + }\n +\n + function esc(n) {\n + var i = parseInt(s.substr(j + 1, n), 16);\n + j += n;\n + if (i >= 32 && i <= 126 &&\n + i !== 34 && i !== 92 && i !== 39) {\n + warningAt("Unnecessary escapement.", line, character);\n + }\n + character += n;\n + c = String.fromCharCode(i);\n + }\n + j = 0;\n +unclosedString: for (;;) {\n + while (j >= s.length) {\n + j = 0;\n +\n + var cl = line, cf = from;\n + if (!nextLine()) {\n + errorAt("Unclosed string.", cl, cf);\n + break unclosedString;\n + }\n +\n + if (allowNewLine) {\n + allowNewLine = false;\n + } else {\n + warningAt("Unclosed string.", cl, cf);\n + }\n + }\n + c = s.charAt(j);\n + if (c === x) {\n + character += 1;\n + s = s.substr(j + 1);\n + return it(\'(string)\', r, x);\n + }\n + if (c < \' \') {\n + if (c === \'\\n\' || c === \'\\r\') {\n + break;\n + }\n + warningAt("Control character in string: {a}.",\n + line, character + j, s.slice(0, j));\n + } else if (c === \'\\\\\') {\n + j += 1;\n + character += 1;\n + c = s.charAt(j);\n + n = s.charAt(j + 1);\n + switch (c) {\n + case \'\\\\\':\n + case \'"\':\n + case \'/\':\n + break;\n + case \'\\\'\':\n + if (jsonmode) {\n + warningAt("Avoid \\\\\'.", line, character);\n + }\n + break;\n + case \'b\':\n + c = \'\\b\';\n + break;\n + case \'f\':\n + c = \'\\f\';\n + break;\n + case \'n\':\n + c = \'\\n\';\n + break;\n + case \'r\':\n + c = \'\\r\';\n + break;\n + case \'t\':\n + c = \'\\t\';\n + break;\n + case \'0\':\n + c = \'\\0\';\n + // Octal literals fail in strict mode\n + // check if the number is between 00 and 07\n + // where \'n\' is the token next to \'c\'\n + if (n >= 0 && n <= 7 && directive["use strict"]) {\n + warningAt(\n + "Octal literals are not allowed in strict mode.",\n + line, character);\n + }\n + break;\n + case \'u\':\n + esc(4);\n + break;\n + case \'v\':\n + if (jsonmode) {\n + warningAt("Avoid \\\\v.", line, character);\n + }\n + c = \'\\v\';\n + break;\n + case \'x\':\n + if (jsonmode) {\n + warningAt("Avoid \\\\x-.", line, character);\n + }\n + esc(2);\n + break;\n + case \'\':\n + // last character is escape character\n + // always allow new line if escaped, but show\n + // warning if option is not set\n + allowNewLine = true;\n + if (option.multistr) {\n + if (jsonmode) {\n + warningAt("Avoid EOL escapement.", line, character);\n + }\n + c = \'\';\n + character -= 1;\n + break;\n + }\n + warningAt("Bad escapement of EOL. Use option multistr if needed.",\n + line, character);\n + break;\n + default:\n + warningAt("Bad escapement.", line, character);\n + }\n + }\n + r += c;\n + character += 1;\n + j += 1;\n + }\n + }\n +\n + for (;;) {\n + if (!s) {\n + return it(nextLine() ? \'(endline)\' : \'(end)\', \'\');\n + }\n + t = match(tx);\n + if (!t) {\n + t = \'\';\n + c = \'\';\n + while (s && s < \'!\') {\n + s = s.substr(1);\n + }\n + if (s) {\n + errorAt("Unexpected \'{a}\'.", line, character, s.substr(0, 1));\n + s = \'\';\n + }\n + } else {\n +\n + // identifier\n +\n + if (c.isAlpha() || c === \'_\' || c === \'$\') {\n + return it(\'(identifier)\', t);\n + }\n +\n + // number\n +\n + if (c.isDigit()) {\n + if (!isFinite(Number(t))) {\n + warningAt("Bad number \'{a}\'.",\n + line, character, t);\n + }\n + if (s.substr(0, 1).isAlpha()) {\n + warningAt("Missing space after \'{a}\'.",\n + line, character, t);\n + }\n + if (c === \'0\') {\n + d = t.substr(1, 1);\n + if (d.isDigit()) {\n + if (token.id !== \'.\') {\n + warningAt("Don\'t use extra leading zeros \'{a}\'.",\n + line, character, t);\n + }\n + } else if (jsonmode && (d === \'x\' || d === \'X\')) {\n + warningAt("Avoid 0x-. \'{a}\'.",\n + line, character, t);\n + }\n + }\n + if (t.substr(t.length - 1) === \'.\') {\n + warningAt(\n +"A trailing decimal point can be confused with a dot \'{a}\'.", line, character, t);\n + }\n + return it(\'(number)\', t);\n + }\n + switch (t) {\n +\n + // string\n +\n + case \'"\':\n + case "\'":\n + return string(t);\n +\n + // // comment\n +\n + case \'//\':\n + s = \'\';\n + token.comment = true;\n + break;\n +\n + // /* comment\n +\n + case \'/*\':\n + for (;;) {\n + i = s.search(lx);\n + if (i >= 0) {\n + break;\n + }\n + if (!nextLine()) {\n + errorAt("Unclosed comment.", line, character);\n + }\n + }\n + character += i + 2;\n + if (s.substr(i, 1) === \'/\') {\n + errorAt("Nested comment.", line, character);\n + }\n + s = s.substr(i + 2);\n + token.comment = true;\n + break;\n +\n + // /*members /*jshint /*global\n +\n + case \'/*members\':\n + case \'/*member\':\n + case \'/*jshint\':\n + case \'/*jslint\':\n + case \'/*global\':\n + case \'*/\':\n + return {\n + value: t,\n + type: \'special\',\n + line: line,\n + character: character,\n + from: from\n + };\n +\n + case \'\':\n + break;\n + // /\n + case \'/\':\n + if (token.id === \'/=\') {\n + errorAt("A regular expression literal can be confused with \'/=\'.",\n + line, from);\n + }\n + if (prereg) {\n + depth = 0;\n + captures = 0;\n + l = 0;\n + for (;;) {\n + b = true;\n + c = s.charAt(l);\n + l += 1;\n + switch (c) {\n + case \'\':\n + errorAt("Unclosed regular expression.", line, from);\n + return quit(\'Stopping.\', line, from);\n + case \'/\':\n + if (depth > 0) {\n + warningAt("{a} unterminated regular expression " +\n + "group(s).", line, from + l, depth);\n + }\n + c = s.substr(0, l - 1);\n + q = {\n + g: true,\n + i: true,\n + m: true\n + };\n + while (q[s.charAt(l)] === true) {\n + q[s.charAt(l)] = false;\n + l += 1;\n + }\n + character += l;\n + s = s.substr(l);\n + q = s.charAt(0);\n + if (q === \'/\' || q === \'*\') {\n + errorAt("Confusing regular expression.",\n + line, from);\n + }\n + return it(\'(regexp)\', c);\n + case \'\\\\\':\n + c = s.charAt(l);\n + if (c < \' \') {\n + warningAt(\n +"Unexpected control character in regular expression.", line, from + l);\n + } else if (c === \'<\') {\n + warningAt(\n +"Unexpected escaped character \'{a}\' in regular expression.", line, from + l, c);\n + }\n + l += 1;\n + break;\n + case \'(\':\n + depth += 1;\n + b = false;\n + if (s.charAt(l) === \'?\') {\n + l += 1;\n + switch (s.charAt(l)) {\n + case \':\':\n + case \'=\':\n + case \'!\':\n + l += 1;\n + break;\n + default:\n + warningAt(\n +"Expected \'{a}\' and instead saw \'{b}\'.", line, from + l, \':\', s.charAt(l));\n + }\n + } else {\n + captures += 1;\n + }\n + break;\n + case \'|\':\n + b = false;\n + break;\n + case \')\':\n + if (depth === 0) {\n + warningAt("Unescaped \'{a}\'.",\n + line, from + l, \')\');\n + } else {\n + depth -= 1;\n + }\n + break;\n + case \' \':\n + q = 1;\n + while (s.charAt(l) === \' \') {\n + l += 1;\n + q += 1;\n + }\n + if (q > 1) {\n + warningAt(\n +"Spaces are hard to count. Use {{a}}.", line, from + l, q);\n + }\n + break;\n + case \'[\':\n + c = s.charAt(l);\n + if (c === \'^\') {\n + l += 1;\n + if (option.regexp) {\n + warningAt("Insecure \'{a}\'.",\n + line, from + l, c);\n + } else if (s.charAt(l) === \']\') {\n + errorAt("Unescaped \'{a}\'.",\n + line, from + l, \'^\');\n + }\n + }\n + if (c === \']\') {\n + warningAt("Empty class.", line,\n + from + l - 1);\n + }\n + isLiteral = false;\n + isInRange = false;\n +klass: do {\n + c = s.charAt(l);\n + l += 1;\n + switch (c) {\n + case \'[\':\n + case \'^\':\n + warningAt("Unescaped \'{a}\'.",\n + line, from + l, c);\n + if (isInRange) {\n + isInRange = false;\n + } else {\n + isLiteral = true;\n + }\n + break;\n + case \'-\':\n + if (isLiteral && !isInRange) {\n + isLiteral = false;\n + isInRange = true;\n + } else if (isInRange) {\n + isInRange = false;\n + } else if (s.charAt(l) === \']\') {\n + isInRange = true;\n + } else {\n + if (option.regexdash !== (l === 2 || (l === 3 &&\n + s.charAt(1) === \'^\'))) {\n + warningAt("Unescaped \'{a}\'.",\n + line, from + l - 1, \'-\');\n + }\n + isLiteral = true;\n + }\n + break;\n + case \']\':\n + if (isInRange && !option.regexdash) {\n + warningAt("Unescaped \'{a}\'.",\n + line, from + l - 1, \'-\');\n + }\n + break klass;\n + case \'\\\\\':\n + c = s.charAt(l);\n + if (c < \' \') {\n + warningAt(\n +"Unexpected control character in regular expression.", line, from + l);\n + } else if (c === \'<\') {\n + warningAt(\n +"Unexpected escaped character \'{a}\' in regular expression.", line, from + l, c);\n + }\n + l += 1;\n +\n + // \\w, \\s and \\d are never part of a character range\n + if (/[wsd]/i.test(c)) {\n + if (isInRange) {\n + warningAt("Unescaped \'{a}\'.",\n + line, from + l, \'-\');\n + isInRange = false;\n + }\n + isLiteral = false;\n + } else if (isInRange) {\n + isInRange = false;\n + } else {\n + isLiteral = true;\n + }\n + break;\n + case \'/\':\n + warningAt("Unescaped \'{a}\'.",\n + line, from + l - 1, \'/\');\n +\n + if (isInRange) {\n + isInRange = false;\n + } else {\n + isLiteral = true;\n + }\n + break;\n + case \'<\':\n + if (isInRange) {\n + isInRange = false;\n + } else {\n + isLiteral = true;\n + }\n + break;\n + default:\n + if (isInRange) {\n + isInRange = false;\n + } else {\n + isLiteral = true;\n + }\n + }\n + } while (c);\n + break;\n + case \'.\':\n + if (option.regexp) {\n + warningAt("Insecure \'{a}\'.", line,\n + from + l, c);\n + }\n + break;\n + case \']\':\n + case \'?\':\n + case \'{\':\n + case \'}\':\n + case \'+\':\n + case \'*\':\n + warningAt("Unescaped \'{a}\'.", line,\n + from + l, c);\n + }\n + if (b) {\n + switch (s.charAt(l)) {\n + case \'?\':\n + case \'+\':\n + case \'*\':\n + l += 1;\n + if (s.charAt(l) === \'?\') {\n + l += 1;\n + }\n + break;\n + case \'{\':\n + l += 1;\n + c = s.charAt(l);\n + if (c < \'0\' || c > \'9\') {\n + warningAt(\n +"Expected a number and instead saw \'{a}\'.", line, from + l, c);\n + }\n + l += 1;\n + low = +c;\n + for (;;) {\n + c = s.charAt(l);\n + if (c < \'0\' || c > \'9\') {\n + break;\n + }\n + l += 1;\n + low = +c + (low * 10);\n + }\n + high = low;\n + if (c === \',\') {\n + l += 1;\n + high = Infinity;\n + c = s.charAt(l);\n + if (c >= \'0\' && c <= \'9\') {\n + l += 1;\n + high = +c;\n + for (;;) {\n + c = s.charAt(l);\n + if (c < \'0\' || c > \'9\') {\n + break;\n + }\n + l += 1;\n + high = +c + (high * 10);\n + }\n + }\n + }\n + if (s.charAt(l) !== \'}\') {\n + warningAt(\n +"Expected \'{a}\' and instead saw \'{b}\'.", line, from + l, \'}\', c);\n + } else {\n + l += 1;\n + }\n + if (s.charAt(l) === \'?\') {\n + l += 1;\n + }\n + if (low > high) {\n + warningAt(\n +"\'{a}\' should not be greater than \'{b}\'.", line, from + l, low, high);\n + }\n + }\n + }\n + }\n + c = s.substr(0, l - 1);\n + character += l;\n + s = s.substr(l);\n + return it(\'(regexp)\', c);\n + }\n + return it(\'(punctuator)\', t);\n +\n + // punctuator\n +\n + case \'#\':\n + return it(\'(punctuator)\', t);\n + default:\n + return it(\'(punctuator)\', t);\n + }\n + }\n + }\n + }\n + };\n + }());\n +\n +\n + function addlabel(t, type) {\n +\n + if (t === \'hasOwnProperty\') {\n + warning("\'hasOwnProperty\' is a really bad name.");\n + }\n +\n +// Define t in the current function in the current scope.\n + if (is_own(funct, t) && !funct[\'(global)\']) {\n + if (funct[t] === true) {\n + if (option.latedef)\n + warning("\'{a}\' was used before it was defined.", nexttoken, t);\n + } else {\n + if (!option.shadow && type !== "exception")\n + warning("\'{a}\' is already defined.", nexttoken, t);\n + }\n + }\n +\n + funct[t] = type;\n + if (funct[\'(global)\']) {\n + global[t] = funct;\n + if (is_own(implied, t)) {\n + if (option.latedef)\n + warning("\'{a}\' was used before it was defined.", nexttoken, t);\n + delete implied[t];\n + }\n + } else {\n + scope[t] = funct;\n + }\n + }\n +\n +\n + function doOption() {\n + var b, obj, filter, o = nexttoken.value, t, tn, v;\n +\n + switch (o) {\n + case \'*/\':\n + error("Unbegun comment.");\n + break;\n + case \'/*members\':\n + case \'/*member\':\n + o = \'/*members\';\n + if (!membersOnly) {\n + membersOnly = {};\n + }\n + obj = membersOnly;\n + break;\n + case \'/*jshint\':\n + case \'/*jslint\':\n + obj = option;\n + filter = boolOptions;\n + break;\n + case \'/*global\':\n + obj = predefined;\n + break;\n + default:\n + error("What?");\n + }\n +\n + t = lex.token();\n +loop: for (;;) {\n + for (;;) {\n + if (t.type === \'special\' && t.value === \'*/\') {\n + break loop;\n + }\n + if (t.id !== \'(endline)\' && t.id !== \',\') {\n + break;\n + }\n + t = lex.token();\n + }\n + if (t.type !== \'(string)\' && t.type !== \'(identifier)\' &&\n + o !== \'/*members\') {\n + error("Bad option.", t);\n + }\n +\n + v = lex.token();\n + if (v.id === \':\') {\n + v = lex.token();\n +\n + if (obj === membersOnly) {\n + error("Expected \'{a}\' and instead saw \'{b}\'.",\n + t, \'*/\', \':\');\n + }\n +\n + if (o === \'/*jshint\') {\n + checkOption(t.value, t);\n + }\n +\n + if (t.value === \'indent\' && (o === \'/*jshint\' || o === \'/*jslint\')) {\n + b = +v.value;\n + if (typeof b !== \'number\' || !isFinite(b) || b <= 0 ||\n + Math.floor(b) !== b) {\n + error("Expected a small integer and instead saw \'{a}\'.",\n + v, v.value);\n + }\n + obj.white = true;\n + obj.indent = b;\n + } else if (t.value === \'maxerr\' && (o === \'/*jshint\' || o === \'/*jslint\')) {\n + b = +v.value;\n + if (typeof b !== \'number\' || !isFinite(b) || b <= 0 ||\n + Math.floor(b) !== b) {\n + error("Expected a small integer and instead saw \'{a}\'.",\n + v, v.value);\n + }\n + obj.maxerr = b;\n + } else if (t.value === \'maxlen\' && (o === \'/*jshint\' || o === \'/*jslint\')) {\n + b = +v.value;\n + if (typeof b !== \'number\' || !isFinite(b) || b <= 0 ||\n + Math.floor(b) !== b) {\n + error("Expected a small integer and instead saw \'{a}\'.",\n + v, v.value);\n + }\n + obj.maxlen = b;\n + } else if (t.value === \'validthis\') {\n + if (funct[\'(global)\']) {\n + error("Option \'validthis\' can\'t be used in a global scope.");\n + } else {\n + if (v.value === \'true\' || v.value === \'false\')\n + obj[t.value] = v.value === \'true\';\n + else\n + error("Bad option value.", v);\n + }\n + } else if (v.value === \'true\' || v.value === \'false\') {\n + if (o === \'/*jslint\') {\n + tn = renamedOptions[t.value] || t.value;\n + obj[tn] = v.value === \'true\';\n + if (invertedOptions[tn] !== undefined) {\n + obj[tn] = !obj[tn];\n + }\n + } else {\n + obj[t.value] = v.value === \'true\';\n + }\n + } else {\n + error("Bad option value.", v);\n + }\n + t = lex.token();\n + } else {\n + if (o === \'/*jshint\' || o === \'/*jslint\') {\n + error("Missing option value.", t);\n + }\n + obj[t.value] = false;\n + t = v;\n + }\n + }\n + if (filter) {\n + assume();\n + }\n + }\n +\n +\n +// We need a peek function. If it has an argument, it peeks that much farther\n +// ahead. It is used to distinguish\n +// for ( var i in ...\n +// from\n +// for ( var i = ...\n +\n + function peek(p) {\n + var i = p || 0, j = 0, t;\n +\n + while (j <= i) {\n + t = lookahead[j];\n + if (!t) {\n + t = lookahead[j] = lex.token();\n + }\n + j += 1;\n + }\n + return t;\n + }\n +\n +\n +\n +// Produce the next token. It looks for programming errors.\n +\n + function advance(id, t) {\n + switch (token.id) {\n + case \'(number)\':\n + if (nexttoken.id === \'.\') {\n + warning("A dot following a number can be confused with a decimal point.", token);\n + }\n + break;\n + case \'-\':\n + if (nexttoken.id === \'-\' || nexttoken.id === \'--\') {\n + warning("Confusing minusses.");\n + }\n + break;\n + case \'+\':\n + if (nexttoken.id === \'+\' || nexttoken.id === \'++\') {\n + warning("Confusing plusses.");\n + }\n + break;\n + }\n +\n + if (token.type === \'(string)\' || token.identifier) {\n + anonname = token.value;\n + }\n +\n + if (id && nexttoken.id !== id) {\n + if (t) {\n + if (nexttoken.id === \'(end)\') {\n + warning("Unmatched \'{a}\'.", t, t.id);\n + } else {\n + warning("Expected \'{a}\' to match \'{b}\' from line {c} and instead saw \'{d}\'.",\n + nexttoken, id, t.id, t.line, nexttoken.value);\n + }\n + } else if (nexttoken.type !== \'(identifier)\' ||\n + nexttoken.value !== id) {\n + warning("Expected \'{a}\' and instead saw \'{b}\'.",\n + nexttoken, id, nexttoken.value);\n + }\n + }\n +\n + prevtoken = token;\n + token = nexttoken;\n + for (;;) {\n + nexttoken = lookahead.shift() || lex.token();\n + if (nexttoken.id === \'(end)\' || nexttoken.id === \'(error)\') {\n + return;\n + }\n + if (nexttoken.type === \'special\') {\n + doOption();\n + } else {\n + if (nexttoken.id !== \'(endline)\') {\n + break;\n + }\n + }\n + }\n + }\n +\n +\n +// This is the heart of JSHINT, the Pratt parser. In addition to parsing, it\n +// is looking for ad hoc lint patterns. We add .fud to Pratt\'s model, which is\n +// like .nud except that it is only used on the first token of a statement.\n +// Having .fud makes it much easier to define statement-oriented languages like\n +// JavaScript. I retained Pratt\'s nomenclature.\n +\n +// .nud Null denotation\n +// .fud First null denotation\n +// .led Left denotation\n +// lbp Left binding power\n +// rbp Right binding power\n +\n +// They are elements of the parsing method called Top Down Operator Precedence.\n +\n + function expression(rbp, initial) {\n + var left, isArray = false, isObject = false;\n +\n + if (nexttoken.id === \'(end)\')\n + error("Unexpected early end of program.", token);\n +\n + advance();\n + if (initial) {\n + anonname = \'anonymous\';\n + funct[\'(verb)\'] = token.value;\n + }\n + if (initial === true && token.fud) {\n + left = token.fud();\n + } else {\n + if (token.nud) {\n + left = token.nud();\n + } else {\n + if (nexttoken.type === \'(number)\' && token.id === \'.\') {\n + warning("A leading decimal point can be confused with a dot: \'.{a}\'.",\n + token, nexttoken.value);\n + advance();\n + return token;\n + } else {\n + error("Expected an identifier and instead saw \'{a}\'.",\n + token, token.id);\n + }\n + }\n + while (rbp < nexttoken.lbp) {\n + isArray = token.value === \'Array\';\n + isObject = token.value === \'Object\';\n +\n + // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object()\n + // Line breaks in IfStatement heads exist to satisfy the checkJSHint\n + // "Line too long." error.\n + if (left && (left.value || (left.first && left.first.value))) {\n + // If the left.value is not "new", or the left.first.value is a "."\n + // then safely assume that this is not "new Array()" and possibly\n + // not "new Object()"...\n + if (left.value !== \'new\' ||\n + (left.first && left.first.value && left.first.value === \'.\')) {\n + isArray = false;\n + // ...In the case of Object, if the left.value and token.value\n + // are not equal, then safely assume that this not "new Object()"\n + if (left.value !== token.value) {\n + isObject = false;\n + }\n + }\n + }\n +\n + advance();\n + if (isArray && token.id === \'(\' && nexttoken.id === \')\')\n + warning("Use the array literal notation [].", token);\n + if (isObject && token.id === \'(\' && nexttoken.id === \')\')\n + warning("Use the object literal notation {}.", token);\n + if (token.led) {\n + left = token.led(left);\n + } else {\n + error("Expected an operator and instead saw \'{a}\'.",\n + token, token.id);\n + }\n + }\n + }\n + return left;\n + }\n +\n +\n +// Functions for conformance of style.\n +\n + function adjacent(left, right) {\n + left = left || token;\n + right = right || nexttoken;\n + if (option.white) {\n + if (left.character !== right.from && left.line === right.line) {\n + left.from += (left.character - left.from);\n + warning("Unexpected space after \'{a}\'.", left, left.value);\n + }\n + }\n + }\n +\n + function nobreak(left, right) {\n + left = left || token;\n + right = right || nexttoken;\n + if (option.white && (left.character !== right.from || left.line !== right.line)) {\n + warning("Unexpected space before \'{a}\'.", right, right.value);\n + }\n + }\n +\n + function nospace(left, right) {\n + left = left || token;\n + right = right || nexttoken;\n + if (option.white && !left.comment) {\n + if (left.line === right.line) {\n + adjacent(left, right);\n + }\n + }\n + }\n +\n + function nonadjacent(left, right) {\n + if (option.white) {\n + left = left || token;\n + right = right || nexttoken;\n + if (left.line === right.line && left.character === right.from) {\n + left.from += (left.character - left.from);\n + warning("Missing space after \'{a}\'.",\n + left, left.value);\n + }\n + }\n + }\n +\n + function nobreaknonadjacent(left, right) {\n + left = left || token;\n + right = right || nexttoken;\n + if (!option.laxbreak && left.line !== right.line) {\n + warning("Bad line breaking before \'{a}\'.", right, right.id);\n + } else if (option.white) {\n + left = left || token;\n + right = right || nexttoken;\n + if (left.character === right.from) {\n + left.from += (left.character - left.from);\n + warning("Missing space after \'{a}\'.",\n + left, left.value);\n + }\n + }\n + }\n +\n + function indentation(bias) {\n + var i;\n + if (option.white && nexttoken.id !== \'(end)\') {\n + i = indent + (bias || 0);\n + if (nexttoken.from !== i) {\n + warning(\n +"Expected \'{a}\' to have an indentation at {b} instead at {c}.",\n + nexttoken, nexttoken.value, i, nexttoken.from);\n + }\n + }\n + }\n +\n + function nolinebreak(t) {\n + t = t || token;\n + if (t.line !== nexttoken.line) {\n + warning("Line breaking error \'{a}\'.", t, t.value);\n + }\n + }\n +\n +\n + function comma() {\n + if (token.line !== nexttoken.line) {\n + if (!option.laxcomma) {\n + if (comma.first) {\n + warning("Comma warnings can be turned off with \'laxcomma\'");\n + comma.first = false;\n + }\n + warning("Bad line breaking before \'{a}\'.", token, nexttoken.id);\n + }\n + } else if (!token.comment && token.character !== nexttoken.from && option.white) {\n + token.from += (token.character - token.from);\n + warning("Unexpected space after \'{a}\'.", token, token.value);\n + }\n + advance(\',\');\n + nonadjacent(token, nexttoken);\n + }\n +\n +\n +// Functional constructors for making the symbols that will be inherited by\n +// tokens.\n +\n + function symbol(s, p) {\n + var x = syntax[s];\n + if (!x || typeof x !== \'object\') {\n + syntax[s] = x = {\n + id: s,\n + lbp: p,\n + value: s\n + };\n + }\n + return x;\n + }\n +\n +\n + function delim(s) {\n + return symbol(s, 0);\n + }\n +\n +\n + function stmt(s, f) {\n + var x = delim(s);\n + x.identifier = x.reserved = true;\n + x.fud = f;\n + return x;\n + }\n +\n +\n + function blockstmt(s, f) {\n + var x = stmt(s, f);\n + x.block = true;\n + return x;\n + }\n +\n +\n + function reserveName(x) {\n + var c = x.id.charAt(0);\n + if ((c >= \'a\' && c <= \'z\') || (c >= \'A\' && c <= \'Z\')) {\n + x.identifier = x.reserved = true;\n + }\n + return x;\n + }\n +\n +\n + function prefix(s, f) {\n + var x = symbol(s, 150);\n + reserveName(x);\n + x.nud = (typeof f === \'function\') ? f : function () {\n + this.right = expression(150);\n + this.arity = \'unary\';\n + if (this.id === \'++\' || this.id === \'--\') {\n + if (option.plusplus) {\n + warning("Unexpected use of \'{a}\'.", this, this.id);\n + } else if ((!this.right.identifier || this.right.reserved) &&\n + this.right.id !== \'.\' && this.right.id !== \'[\') {\n + warning("Bad operand.", this);\n + }\n + }\n + return this;\n + };\n + return x;\n + }\n +\n +\n + function type(s, f) {\n + var x = delim(s);\n + x.type = s;\n + x.nud = f;\n + return x;\n + }\n +\n +\n + function reserve(s, f) {\n + var x = type(s, f);\n + x.identifier = x.reserved = true;\n + return x;\n + }\n +\n +\n + function reservevar(s, v) {\n + return reserve(s, function () {\n + if (typeof v === \'function\') {\n + v(this);\n + }\n + return this;\n + });\n + }\n +\n +\n + function infix(s, f, p, w) {\n + var x = symbol(s, p);\n + reserveName(x);\n + x.led = function (left) {\n + if (!w) {\n + nobreaknonadjacent(prevtoken, token);\n + nonadjacent(token, nexttoken);\n + }\n + if (s === "in" && left.id === "!") {\n + warning("Confusing use of \'{a}\'.", left, \'!\');\n + }\n + if (typeof f === \'function\') {\n + return f(left, this);\n + } else {\n + this.left = left;\n + this.right = expression(p);\n + return this;\n + }\n + };\n + return x;\n + }\n +\n +\n + function relation(s, f) {\n + var x = symbol(s, 100);\n + x.led = function (left) {\n + nobreaknonadjacent(prevtoken, token);\n + nonadjacent(token, nexttoken);\n + var right = expression(100);\n + if ((left && left.id === \'NaN\') || (right && right.id === \'NaN\')) {\n + warning("Use the isNaN function to compare with NaN.", this);\n + } else if (f) {\n + f.apply(this, [left, right]);\n + }\n + if (left.id === \'!\') {\n + warning("Confusing use of \'{a}\'.", left, \'!\');\n + }\n + if (right.id === \'!\') {\n + warning("Confusing use of \'{a}\'.", right, \'!\');\n + }\n + this.left = left;\n + this.right = right;\n + return this;\n + };\n + return x;\n + }\n +\n +\n + function isPoorRelation(node) {\n + return node &&\n + ((node.type === \'(number)\' && +node.value === 0) ||\n + (node.type === \'(string)\' && node.value === \'\') ||\n + (node.type === \'null\' && !option.eqnull) ||\n + node.type === \'true\' ||\n + node.type === \'false\' ||\n + node.type === \'undefined\');\n + }\n +\n +\n + function assignop(s, f) {\n + symbol(s, 20).exps = true;\n + return infix(s, function (left, that) {\n + var l;\n + that.left = left;\n + if (predefined[left.value] === false &&\n + scope[left.value][\'(global)\'] === true) {\n + warning("Read only.", left);\n + } else if (left[\'function\']) {\n + warning("\'{a}\' is a function.", left, left.value);\n + }\n + if (left) {\n + if (option.esnext && funct[left.value] === \'const\') {\n + warning("Attempting to override \'{a}\' which is a constant", left, left.value);\n + }\n + if (left.id === \'.\' || left.id === \'[\') {\n + if (!left.left || left.left.value === \'arguments\') {\n + warning(\'Bad assignment.\', that);\n + }\n + that.right = expression(19);\n + return that;\n + } else if (left.identifier && !left.reserved) {\n + if (funct[left.value] === \'exception\') {\n + warning("Do not assign to the exception parameter.", left);\n + }\n + that.right = expression(19);\n + return that;\n + }\n + if (left === syntax[\'function\']) {\n + warning(\n +"Expected an identifier in an assignment and instead saw a function invocation.",\n + token);\n + }\n + }\n + error("Bad assignment.", that);\n + }, 20);\n + }\n +\n +\n + function bitwise(s, f, p) {\n + var x = symbol(s, p);\n + reserveName(x);\n + x.led = (typeof f === \'function\') ? f : function (left) {\n + if (option.bitwise) {\n + warning("Unexpected use of \'{a}\'.", this, this.id);\n + }\n + this.left = left;\n + this.right = expression(p);\n + return this;\n + };\n + return x;\n + }\n +\n +\n + function bitwiseassignop(s) {\n + symbol(s, 20).exps = true;\n + return infix(s, function (left, that) {\n + if (option.bitwise) {\n + warning("Unexpected use of \'{a}\'.", that, that.id);\n + }\n + nonadjacent(prevtoken, token);\n + nonadjacent(token, nexttoken);\n + if (left) {\n + if (left.id === \'.\' || left.id === \'[\' ||\n + (left.identifier && !left.reserved)) {\n + expression(19);\n + return that;\n + }\n + if (left === syntax[\'function\']) {\n + warning(\n +"Expected an identifier in an assignment, and instead saw a function invocation.",\n + token);\n + }\n + return that;\n + }\n + error("Bad assignment.", that);\n + }, 20);\n + }\n +\n +\n + function suffix(s, f) {\n + var x = symbol(s, 150);\n + x.led = function (left) {\n + if (option.plusplus) {\n + warning("Unexpected use of \'{a}\'.", this, this.id);\n + } else if ((!left.identifier || left.reserved) &&\n + left.id !== \'.\' && left.id !== \'[\') {\n + warning("Bad operand.", this);\n + }\n + this.left = left;\n + return this;\n + };\n + return x;\n + }\n +\n +\n + // fnparam means that this identifier is being defined as a function\n + // argument (see identifier())\n + function optionalidentifier(fnparam) {\n + if (nexttoken.identifier) {\n + advance();\n + if (token.reserved && !option.es5) {\n + // `undefined` as a function param is a common pattern to protect\n + // against the case when somebody does `undefined = true` and\n + // help with minification. More info: https://gist.github.com/315916\n + if (!fnparam || token.value !== \'undefined\') {\n + warning("Expected an identifier and instead saw \'{a}\' (a reserved word).",\n + token, token.id);\n + }\n + }\n + return token.value;\n + }\n + }\n +\n + // fnparam means that this identifier is being defined as a function\n + // argument\n + function identifier(fnparam) {\n + var i = optionalidentifier(fnparam);\n + if (i) {\n + return i;\n + }\n + if (token.id === \'function\' && nexttoken.id === \'(\') {\n + warning("Missing name in function declaration.");\n + } else {\n + error("Expected an identifier and instead saw \'{a}\'.",\n + nexttoken, nexttoken.value);\n + }\n + }\n +\n +\n + function reachable(s) {\n + var i = 0, t;\n + if (nexttoken.id !== \';\' || noreach) {\n + return;\n + }\n + for (;;) {\n + t = peek(i);\n + if (t.reach) {\n + return;\n + }\n + if (t.id !== \'(endline)\') {\n + if (t.id === \'function\') {\n + if (!option.latedef) {\n + break;\n + }\n + warning(\n +"Inner functions should be listed at the top of the outer function.", t);\n + break;\n + }\n + warning("Unreachable \'{a}\' after \'{b}\'.", t, t.value, s);\n + break;\n + }\n + i += 1;\n + }\n + }\n +\n +\n + function statement(noindent) {\n + var i = indent, r, s = scope, t = nexttoken;\n +\n + if (t.id === ";") {\n + advance(";");\n + return;\n + }\n +\n +// Is this a labelled statement?\n +\n + if (t.identifier && !t.reserved && peek().id === \':\') {\n + advance();\n + advance(\':\');\n + scope = Object.create(s);\n + addlabel(t.value, \'label\');\n + if (!nexttoken.labelled) {\n + warning("Label \'{a}\' on {b} statement.",\n + nexttoken, t.value, nexttoken.value);\n + }\n + if (jx.test(t.value + \':\')) {\n + warning("Label \'{a}\' looks like a javascript url.",\n + t, t.value);\n + }\n + nexttoken.label = t.value;\n + t = nexttoken;\n + }\n +\n +// Parse the statement.\n +\n + if (!noindent) {\n + indentation();\n + }\n + r = expression(0, true);\n +\n + // Look for the final semicolon.\n + if (!t.block) {\n + if (!option.expr && (!r || !r.exps)) {\n + warning("Expected an assignment or function call and instead saw an expression.",\n + token);\n + } else if (option.nonew && r.id === \'(\' && r.left.id === \'new\') {\n + warning("Do not use \'new\' for side effects.");\n + }\n +\n + if (nexttoken.id === \',\') {\n + return comma();\n + }\n +\n + if (nexttoken.id !== \';\') {\n + if (!option.asi) {\n + // If this is the last statement in a block that ends on\n + // the same line *and* option lastsemic is on, ignore the warning.\n + // Otherwise, complain about missing semicolon.\n + if (!option.lastsemic || nexttoken.id !== \'}\' ||\n + nexttoken.line !== token.line) {\n + warningAt("Missing semicolon.", token.line, token.character);\n + }\n + }\n + } else {\n + adjacent(token, nexttoken);\n + advance(\';\');\n + nonadjacent(token, nexttoken);\n + }\n + }\n +\n +// Restore the indentation.\n +\n + indent = i;\n + scope = s;\n + return r;\n + }\n +\n +\n + function statements(startLine) {\n + var a = [], f, p;\n +\n + while (!nexttoken.reach && nexttoken.id !== \'(end)\') {\n + if (nexttoken.id === \';\') {\n + p = peek();\n + if (!p || p.id !== "(") {\n + warning("Unnecessary semicolon.");\n + }\n + advance(\';\');\n + } el + +]]></string> </value> + </item> + <item> + <key> <string>next</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> + </value> + </item> + </dictionary> + </pickle> + </record> + <record id="3" aka="AAAAAAAAAAM="> + <pickle> + <global name="Pdata" module="OFS.Image"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>data</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +se {\n + a.push(statement(startLine === nexttoken.line));\n + }\n + }\n + return a;\n + }\n +\n +\n + /*\n + * read all directives\n + * recognizes a simple form of asi, but always\n + * warns, if it is used\n + */\n + function directives() {\n + var i, p, pn;\n +\n + for (;;) {\n + if (nexttoken.id === "(string)") {\n + p = peek(0);\n + if (p.id === "(endline)") {\n + i = 1;\n + do {\n + pn = peek(i);\n + i = i + 1;\n + } while (pn.id === "(endline)");\n +\n + if (pn.id !== ";") {\n + if (pn.id !== "(string)" && pn.id !== "(number)" &&\n + pn.id !== "(regexp)" && pn.identifier !== true &&\n + pn.id !== "}") {\n + break;\n + }\n + warning("Missing semicolon.", nexttoken);\n + } else {\n + p = pn;\n + }\n + } else if (p.id === "}") {\n + // directive with no other statements, warn about missing semicolon\n + warning("Missing semicolon.", p);\n + } else if (p.id !== ";") {\n + break;\n + }\n +\n + indentation();\n + advance();\n + if (directive[token.value]) {\n + warning("Unnecessary directive \\"{a}\\".", token, token.value);\n + }\n +\n + if (token.value === "use strict") {\n + option.newcap = true;\n + option.undef = true;\n + }\n +\n + // there\'s no directive negation, so always set to true\n + directive[token.value] = true;\n +\n + if (p.id === ";") {\n + advance(";");\n + }\n + continue;\n + }\n + break;\n + }\n + }\n +\n +\n + /*\n + * Parses a single block. A block is a sequence of statements wrapped in\n + * braces.\n + *\n + * ordinary - true for everything but function bodies and try blocks.\n + * stmt - true if block can be a single statement (e.g. in if/for/while).\n + * isfunc - true if block is a function body\n + */\n + function block(ordinary, stmt, isfunc) {\n + var a,\n + b = inblock,\n + old_indent = indent,\n + m,\n + s = scope,\n + t,\n + line,\n + d;\n +\n + inblock = ordinary;\n + if (!ordinary || !option.funcscope) scope = Object.create(scope);\n + nonadjacent(token, nexttoken);\n + t = nexttoken;\n +\n + if (nexttoken.id === \'{\') {\n + advance(\'{\');\n + line = token.line;\n + if (nexttoken.id !== \'}\') {\n + indent += option.indent;\n + while (!ordinary && nexttoken.from > indent) {\n + indent += option.indent;\n + }\n +\n + if (isfunc) {\n + m = {};\n + for (d in directive) {\n + if (is_own(directive, d)) {\n + m[d] = directive[d];\n + }\n + }\n + directives();\n +\n + if (option.strict && funct[\'(context)\'][\'(global)\']) {\n + if (!m["use strict"] && !directive["use strict"]) {\n + warning("Missing \\"use strict\\" statement.");\n + }\n + }\n + }\n +\n + a = statements(line);\n +\n + if (isfunc) {\n + directive = m;\n + }\n +\n + indent -= option.indent;\n + if (line !== nexttoken.line) {\n + indentation();\n + }\n + } else if (line !== nexttoken.line) {\n + indentation();\n + }\n + advance(\'}\', t);\n + indent = old_indent;\n + } else if (!ordinary) {\n + error("Expected \'{a}\' and instead saw \'{b}\'.",\n + nexttoken, \'{\', nexttoken.value);\n + } else {\n + if (!stmt || option.curly)\n + warning("Expected \'{a}\' and instead saw \'{b}\'.",\n + nexttoken, \'{\', nexttoken.value);\n +\n + noreach = true;\n + indent += option.indent;\n + // test indentation only if statement is in new line\n + a = [statement(nexttoken.line === token.line)];\n + indent -= option.indent;\n + noreach = false;\n + }\n + funct[\'(verb)\'] = null;\n + if (!ordinary || !option.funcscope) scope = s;\n + inblock = b;\n + if (ordinary && option.noempty && (!a || a.length === 0)) {\n + warning("Empty block.");\n + }\n + return a;\n + }\n +\n +\n + function countMember(m) {\n + if (membersOnly && typeof membersOnly[m] !== \'boolean\') {\n + warning("Unexpected /*member \'{a}\'.", token, m);\n + }\n + if (typeof member[m] === \'number\') {\n + member[m] += 1;\n + } else {\n + member[m] = 1;\n + }\n + }\n +\n +\n + function note_implied(token) {\n + var name = token.value, line = token.line, a = implied[name];\n + if (typeof a === \'function\') {\n + a = false;\n + }\n +\n + if (!a) {\n + a = [line];\n + implied[name] = a;\n + } else if (a[a.length - 1] !== line) {\n + a.push(line);\n + }\n + }\n +\n +\n + // Build the syntax table by declaring the syntactic elements of the language.\n +\n + type(\'(number)\', function () {\n + return this;\n + });\n +\n + type(\'(string)\', function () {\n + return this;\n + });\n +\n + syntax[\'(identifier)\'] = {\n + type: \'(identifier)\',\n + lbp: 0,\n + identifier: true,\n + nud: function () {\n + var v = this.value,\n + s = scope[v],\n + f;\n +\n + if (typeof s === \'function\') {\n + // Protection against accidental inheritance.\n + s = undefined;\n + } else if (typeof s === \'boolean\') {\n + f = funct;\n + funct = functions[0];\n + addlabel(v, \'var\');\n + s = funct;\n + funct = f;\n + }\n +\n + // The name is in scope and defined in the current function.\n + if (funct === s) {\n + // Change \'unused\' to \'var\', and reject labels.\n + switch (funct[v]) {\n + case \'unused\':\n + funct[v] = \'var\';\n + break;\n + case \'unction\':\n + funct[v] = \'function\';\n + this[\'function\'] = true;\n + break;\n + case \'function\':\n + this[\'function\'] = true;\n + break;\n + case \'label\':\n + warning("\'{a}\' is a statement label.", token, v);\n + break;\n + }\n + } else if (funct[\'(global)\']) {\n + // The name is not defined in the function. If we are in the global\n + // scope, then we have an undefined variable.\n + //\n + // Operators typeof and delete do not raise runtime errors even if\n + // the base object of a reference is null so no need to display warning\n + // if we\'re inside of typeof or delete.\n +\n + if (option.undef && typeof predefined[v] !== \'boolean\') {\n + // Attempting to subscript a null reference will throw an\n + // error, even within the typeof and delete operators\n + if (!(anonname === \'typeof\' || anonname === \'delete\') ||\n + (nexttoken && (nexttoken.value === \'.\' || nexttoken.value === \'[\'))) {\n +\n + isundef(funct, "\'{a}\' is not defined.", token, v);\n + }\n + }\n + note_implied(token);\n + } else {\n + // If the name is already defined in the current\n + // function, but not as outer, then there is a scope error.\n +\n + switch (funct[v]) {\n + case \'closure\':\n + case \'function\':\n + case \'var\':\n + case \'unused\':\n + warning("\'{a}\' used out of scope.", token, v);\n + break;\n + case \'label\':\n + warning("\'{a}\' is a statement label.", token, v);\n + break;\n + case \'outer\':\n + case \'global\':\n + break;\n + default:\n + // If the name is defined in an outer function, make an outer entry,\n + // and if it was unused, make it var.\n + if (s === true) {\n + funct[v] = true;\n + } else if (s === null) {\n + warning("\'{a}\' is not allowed.", token, v);\n + note_implied(token);\n + } else if (typeof s !== \'object\') {\n + // Operators typeof and delete do not raise runtime errors even\n + // if the base object of a reference is null so no need to\n + // display warning if we\'re inside of typeof or delete.\n + if (option.undef) {\n + // Attempting to subscript a null reference will throw an\n + // error, even within the typeof and delete operators\n + if (!(anonname === \'typeof\' || anonname === \'delete\') ||\n + (nexttoken &&\n + (nexttoken.value === \'.\' || nexttoken.value === \'[\'))) {\n +\n + isundef(funct, "\'{a}\' is not defined.", token, v);\n + }\n + }\n + funct[v] = true;\n + note_implied(token);\n + } else {\n + switch (s[v]) {\n + case \'function\':\n + case \'unction\':\n + this[\'function\'] = true;\n + s[v] = \'closure\';\n + funct[v] = s[\'(global)\'] ? \'global\' : \'outer\';\n + break;\n + case \'var\':\n + case \'unused\':\n + s[v] = \'closure\';\n + funct[v] = s[\'(global)\'] ? \'global\' : \'outer\';\n + break;\n + case \'closure\':\n + case \'parameter\':\n + funct[v] = s[\'(global)\'] ? \'global\' : \'outer\';\n + break;\n + case \'label\':\n + warning("\'{a}\' is a statement label.", token, v);\n + }\n + }\n + }\n + }\n + return this;\n + },\n + led: function () {\n + error("Expected an operator and instead saw \'{a}\'.",\n + nexttoken, nexttoken.value);\n + }\n + };\n +\n + type(\'(regexp)\', function () {\n + return this;\n + });\n +\n +\n +// ECMAScript parser\n +\n + delim(\'(endline)\');\n + delim(\'(begin)\');\n + delim(\'(end)\').reach = true;\n + delim(\'</\').reach = true;\n + delim(\'<!\');\n + delim(\'<!--\');\n + delim(\'-->\');\n + delim(\'(error)\').reach = true;\n + delim(\'}\').reach = true;\n + delim(\')\');\n + delim(\']\');\n + delim(\'"\').reach = true;\n + delim("\'").reach = true;\n + delim(\';\');\n + delim(\':\').reach = true;\n + delim(\',\');\n + delim(\'#\');\n + delim(\'@\');\n + reserve(\'else\');\n + reserve(\'case\').reach = true;\n + reserve(\'catch\');\n + reserve(\'default\').reach = true;\n + reserve(\'finally\');\n + reservevar(\'arguments\', function (x) {\n + if (directive[\'use strict\'] && funct[\'(global)\']) {\n + warning("Strict violation.", x);\n + }\n + });\n + reservevar(\'eval\');\n + reservevar(\'false\');\n + reservevar(\'Infinity\');\n + reservevar(\'NaN\');\n + reservevar(\'null\');\n + reservevar(\'this\', function (x) {\n + if (directive[\'use strict\'] && !option.validthis && ((funct[\'(statement)\'] &&\n + funct[\'(name)\'].charAt(0) > \'Z\') || funct[\'(global)\'])) {\n + warning("Possible strict violation.", x);\n + }\n + });\n + reservevar(\'true\');\n + reservevar(\'undefined\');\n + assignop(\'=\', \'assign\', 20);\n + assignop(\'+=\', \'assignadd\', 20);\n + assignop(\'-=\', \'assignsub\', 20);\n + assignop(\'*=\', \'assignmult\', 20);\n + assignop(\'/=\', \'assigndiv\', 20).nud = function () {\n + error("A regular expression literal can be confused with \'/=\'.");\n + };\n + assignop(\'%=\', \'assignmod\', 20);\n + bitwiseassignop(\'&=\', \'assignbitand\', 20);\n + bitwiseassignop(\'|=\', \'assignbitor\', 20);\n + bitwiseassignop(\'^=\', \'assignbitxor\', 20);\n + bitwiseassignop(\'<<=\', \'assignshiftleft\', 20);\n + bitwiseassignop(\'>>=\', \'assignshiftright\', 20);\n + bitwiseassignop(\'>>>=\', \'assignshiftrightunsigned\', 20);\n + infix(\'?\', function (left, that) {\n + that.left = left;\n + that.right = expression(10);\n + advance(\':\');\n + that[\'else\'] = expression(10);\n + return that;\n + }, 30);\n +\n + infix(\'||\', \'or\', 40);\n + infix(\'&&\', \'and\', 50);\n + bitwise(\'|\', \'bitor\', 70);\n + bitwise(\'^\', \'bitxor\', 80);\n + bitwise(\'&\', \'bitand\', 90);\n + relation(\'==\', function (left, right) {\n + var eqnull = option.eqnull && (left.value === \'null\' || right.value === \'null\');\n +\n + if (!eqnull && option.eqeqeq)\n + warning("Expected \'{a}\' and instead saw \'{b}\'.", this, \'===\', \'==\');\n + else if (isPoorRelation(left))\n + warning("Use \'{a}\' to compare with \'{b}\'.", this, \'===\', left.value);\n + else if (isPoorRelation(right))\n + warning("Use \'{a}\' to compare with \'{b}\'.", this, \'===\', right.value);\n +\n + return this;\n + });\n + relation(\'===\');\n + relation(\'!=\', function (left, right) {\n + var eqnull = option.eqnull &&\n + (left.value === \'null\' || right.value === \'null\');\n +\n + if (!eqnull && option.eqeqeq) {\n + warning("Expected \'{a}\' and instead saw \'{b}\'.",\n + this, \'!==\', \'!=\');\n + } else if (isPoorRelation(left)) {\n + warning("Use \'{a}\' to compare with \'{b}\'.",\n + this, \'!==\', left.value);\n + } else if (isPoorRelation(right)) {\n + warning("Use \'{a}\' to compare with \'{b}\'.",\n + this, \'!==\', right.value);\n + }\n + return this;\n + });\n + relation(\'!==\');\n + relation(\'<\');\n + relation(\'>\');\n + relation(\'<=\');\n + relation(\'>=\');\n + bitwise(\'<<\', \'shiftleft\', 120);\n + bitwise(\'>>\', \'shiftright\', 120);\n + bitwise(\'>>>\', \'shiftrightunsigned\', 120);\n + infix(\'in\', \'in\', 120);\n + infix(\'instanceof\', \'instanceof\', 120);\n + infix(\'+\', function (left, that) {\n + var right = expression(130);\n + if (left && right && left.id === \'(string)\' && right.id === \'(string)\') {\n + left.value += right.value;\n + left.character = right.character;\n + if (!option.scripturl && jx.test(left.value)) {\n + warning("JavaScript URL.", left);\n + }\n + return left;\n + }\n + that.left = left;\n + that.right = right;\n + return that;\n + }, 130);\n + prefix(\'+\', \'num\');\n + prefix(\'+++\', function () {\n + warning("Confusing pluses.");\n + this.right = expression(150);\n + this.arity = \'unary\';\n + return this;\n + });\n + infix(\'+++\', function (left) {\n + warning("Confusing pluses.");\n + this.left = left;\n + this.right = expression(130);\n + return this;\n + }, 130);\n + infix(\'-\', \'sub\', 130);\n + prefix(\'-\', \'neg\');\n + prefix(\'---\', function () {\n + warning("Confusing minuses.");\n + this.right = expression(150);\n + this.arity = \'unary\';\n + return this;\n + });\n + infix(\'---\', function (left) {\n + warning("Confusing minuses.");\n + this.left = left;\n + this.right = expression(130);\n + return this;\n + }, 130);\n + infix(\'*\', \'mult\', 140);\n + infix(\'/\', \'div\', 140);\n + infix(\'%\', \'mod\', 140);\n +\n + suffix(\'++\', \'postinc\');\n + prefix(\'++\', \'preinc\');\n + syntax[\'++\'].exps = true;\n +\n + suffix(\'--\', \'postdec\');\n + prefix(\'--\', \'predec\');\n + syntax[\'--\'].exps = true;\n + prefix(\'delete\', function () {\n + var p = expression(0);\n + if (!p || (p.id !== \'.\' && p.id !== \'[\')) {\n + warning("Variables should not be deleted.");\n + }\n + this.first = p;\n + return this;\n + }).exps = true;\n +\n + prefix(\'~\', function () {\n + if (option.bitwise) {\n + warning("Unexpected \'{a}\'.", this, \'~\');\n + }\n + expression(150);\n + return this;\n + });\n +\n + prefix(\'!\', function () {\n + this.right = expression(150);\n + this.arity = \'unary\';\n + if (bang[this.right.id] === true) {\n + warning("Confusing use of \'{a}\'.", this, \'!\');\n + }\n + return this;\n + });\n + prefix(\'typeof\', \'typeof\');\n + prefix(\'new\', function () {\n + var c = expression(155), i;\n + if (c && c.id !== \'function\') {\n + if (c.identifier) {\n + c[\'new\'] = true;\n + switch (c.value) {\n + case \'Number\':\n + case \'String\':\n + case \'Boolean\':\n + case \'Math\':\n + case \'JSON\':\n + warning("Do not use {a} as a constructor.", token, c.value);\n + break;\n + case \'Function\':\n + if (!option.evil) {\n + warning("The Function constructor is eval.");\n + }\n + break;\n + case \'Date\':\n + case \'RegExp\':\n + break;\n + default:\n + if (c.id !== \'function\') {\n + i = c.value.substr(0, 1);\n + if (option.newcap && (i < \'A\' || i > \'Z\')) {\n + warning("A constructor name should start with an uppercase letter.",\n + token);\n + }\n + }\n + }\n + } else {\n + if (c.id !== \'.\' && c.id !== \'[\' && c.id !== \'(\') {\n + warning("Bad constructor.", token);\n + }\n + }\n + } else {\n + if (!option.supernew)\n + warning("Weird construction. Delete \'new\'.", this);\n + }\n + adjacent(token, nexttoken);\n + if (nexttoken.id !== \'(\' && !option.supernew) {\n + warning("Missing \'()\' invoking a constructor.");\n + }\n + this.first = c;\n + return this;\n + });\n + syntax[\'new\'].exps = true;\n +\n + prefix(\'void\').exps = true;\n +\n + infix(\'.\', function (left, that) {\n + adjacent(prevtoken, token);\n + nobreak();\n + var m = identifier();\n + if (typeof m === \'string\') {\n + countMember(m);\n + }\n + that.left = left;\n + that.right = m;\n + if (left && left.value === \'arguments\' && (m === \'callee\' || m === \'caller\')) {\n + if (option.noarg)\n + warning("Avoid arguments.{a}.", left, m);\n + else if (directive[\'use strict\'])\n + error(\'Strict violation.\');\n + } else if (!option.evil && left && left.value === \'document\' &&\n + (m === \'write\' || m === \'writeln\')) {\n + warning("document.write can be a form of eval.", left);\n + }\n + if (!option.evil && (m === \'eval\' || m === \'execScript\')) {\n + warning(\'eval is evil.\');\n + }\n + return that;\n + }, 160, true);\n +\n + infix(\'(\', function (left, that) {\n + if (prevtoken.id !== \'}\' && prevtoken.id !== \')\') {\n + nobreak(prevtoken, token);\n + }\n + nospace();\n + if (option.immed && !left.immed && left.id === \'function\') {\n + warning("Wrap an immediate function invocation in parentheses " +\n + "to assist the reader in understanding that the expression " +\n + "is the result of a function, and not the function itself.");\n + }\n + var n = 0,\n + p = [];\n + if (left) {\n + if (left.type === \'(identifier)\') {\n + if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {\n + if (left.value !== \'Number\' && left.value !== \'String\' &&\n + left.value !== \'Boolean\' &&\n + left.value !== \'Date\') {\n + if (left.value === \'Math\') {\n + warning("Math is not a function.", left);\n + } else if (option.newcap) {\n + warning(\n +"Missing \'new\' prefix when invoking a constructor.", left);\n + }\n + }\n + }\n + }\n + }\n + if (nexttoken.id !== \')\') {\n + for (;;) {\n + p[p.length] = expression(10);\n + n += 1;\n + if (nexttoken.id !== \',\') {\n + break;\n + }\n + comma();\n + }\n + }\n + advance(\')\');\n + nospace(prevtoken, token);\n + if (typeof left === \'object\') {\n + if (left.value === \'parseInt\' && n === 1) {\n + warning("Missing radix parameter.", left);\n + }\n + if (!option.evil) {\n + if (left.value === \'eval\' || left.value === \'Function\' ||\n + left.value === \'execScript\') {\n + warning("eval is evil.", left);\n + } else if (p[0] && p[0].id === \'(string)\' &&\n + (left.value === \'setTimeout\' ||\n + left.value === \'setInterval\')) {\n + warning(\n + "Implied eval is evil. Pass a function instead of a string.", left);\n + }\n + }\n + if (!left.identifier && left.id !== \'.\' && left.id !== \'[\' &&\n + left.id !== \'(\' && left.id !== \'&&\' && left.id !== \'||\' &&\n + left.id !== \'?\') {\n + warning("Bad invocation.", left);\n + }\n + }\n + that.left = left;\n + return that;\n + }, 155, true).exps = true;\n +\n + prefix(\'(\', function () {\n + nospace();\n + if (nexttoken.id === \'function\') {\n + nexttoken.immed = true;\n + }\n + var v = expression(0);\n + advance(\')\', this);\n + nospace(prevtoken, token);\n + if (option.immed && v.id === \'function\') {\n + if (nexttoken.id === \'(\' ||\n + (nexttoken.id === \'.\' && (peek().value === \'call\' || peek().value === \'apply\'))) {\n + warning(\n +"Move the invocation into the parens that contain the function.", nexttoken);\n + } else {\n + warning(\n +"Do not wrap function literals in parens unless they are to be immediately invoked.",\n + this);\n + }\n + }\n + return v;\n + });\n +\n + infix(\'[\', function (left, that) {\n + nobreak(prevtoken, token);\n + nospace();\n + var e = expression(0), s;\n + if (e && e.type === \'(string)\') {\n + if (!option.evil && (e.value === \'eval\' || e.value === \'execScript\')) {\n + warning("eval is evil.", that);\n + }\n + countMember(e.value);\n + if (!option.sub && ix.test(e.value)) {\n + s = syntax[e.value];\n + if (!s || !s.reserved) {\n + warning("[\'{a}\'] is better written in dot notation.",\n + e, e.value);\n + }\n + }\n + }\n + advance(\']\', that);\n + nospace(prevtoken, token);\n + that.left = left;\n + that.right = e;\n + return that;\n + }, 160, true);\n +\n + prefix(\'[\', function () {\n + var b = token.line !== nexttoken.line;\n + this.first = [];\n + if (b) {\n + indent += option.indent;\n + if (nexttoken.from === indent + option.indent) {\n + indent += option.indent;\n + }\n + }\n + while (nexttoken.id !== \'(end)\') {\n + while (nexttoken.id === \',\') {\n + warning("Extra comma.");\n + advance(\',\');\n + }\n + if (nexttoken.id === \']\') {\n + break;\n + }\n + if (b && token.line !== nexttoken.line) {\n + indentation();\n + }\n + this.first.push(expression(10));\n + if (nexttoken.id === \',\') {\n + comma();\n + if (nexttoken.id === \']\' && !option.es5) {\n + warning("Extra comma.", token);\n + break;\n + }\n + } else {\n + break;\n + }\n + }\n + if (b) {\n + indent -= option.indent;\n + indentation();\n + }\n + advance(\']\', this);\n + return this;\n + }, 160);\n +\n +\n + function property_name() {\n + var id = optionalidentifier(true);\n + if (!id) {\n + if (nexttoken.id === \'(string)\') {\n + id = nexttoken.value;\n + advance();\n + } else if (nexttoken.id === \'(number)\') {\n + id = nexttoken.value.toString();\n + advance();\n + }\n + }\n + return id;\n + }\n +\n +\n + function functionparams() {\n + var i, t = nexttoken, p = [];\n + advance(\'(\');\n + nospace();\n + if (nexttoken.id === \')\') {\n + advance(\')\');\n + return;\n + }\n + for (;;) {\n + i = identifier(true);\n + p.push(i);\n + addlabel(i, \'parameter\');\n + if (nexttoken.id === \',\') {\n + comma();\n + } else {\n + advance(\')\', t);\n + nospace(prevtoken, token);\n + return p;\n + }\n + }\n + }\n +\n +\n + function doFunction(i, statement) {\n + var f,\n + oldOption = option,\n + oldScope = scope;\n +\n + option = Object.create(option);\n + scope = Object.create(scope);\n +\n + funct = {\n + \'(name)\' : i || \'"\' + anonname + \'"\',\n + \'(line)\' : nexttoken.line,\n + \'(context)\' : funct,\n + \'(breakage)\' : 0,\n + \'(loopage)\' : 0,\n + \'(scope)\' : scope,\n + \'(statement)\': statement\n + };\n + f = funct;\n + token.funct = funct;\n + functions.push(funct);\n + if (i) {\n + addlabel(i, \'function\');\n + }\n + funct[\'(params)\'] = functionparams();\n +\n + block(false, false, true);\n + scope = oldScope;\n + option = oldOption;\n + funct[\'(last)\'] = token.line;\n + funct = funct[\'(context)\'];\n + return f;\n + }\n +\n +\n + (function (x) {\n + x.nud = function () {\n + var b, f, i, j, p, t;\n + var props = {}; // All properties, including accessors\n +\n + function saveProperty(name, token) {\n + if (props[name] && is_own(props, name))\n + warning("Duplicate member \'{a}\'.", nexttoken, i);\n + else\n + props[name] = {};\n +\n + props[name].basic = true;\n + props[name].basicToken = token;\n + }\n +\n + function saveSetter(name, token) {\n + if (props[name] && is_own(props, name)) {\n + if (props[name].basic || props[name].setter)\n + warning("Duplicate member \'{a}\'.", nexttoken, i);\n + } else {\n + props[name] = {};\n + }\n +\n + props[name].setter = true;\n + props[name].setterToken = token;\n + }\n +\n + function saveGetter(name) {\n + if (props[name] && is_own(props, name)) {\n + if (props[name].basic || props[name].getter)\n + warning("Duplicate member \'{a}\'.", nexttoken, i);\n + } else {\n + props[name] = {};\n + }\n +\n + props[name].getter = true;\n + props[name].getterToken = token;\n + }\n +\n + b = token.line !== nexttoken.line;\n + if (b) {\n + indent += option.indent;\n + if (nexttoken.from === indent + option.indent) {\n + indent += option.indent;\n + }\n + }\n + for (;;) {\n + if (nexttoken.id === \'}\') {\n + break;\n + }\n + if (b) {\n + indentation();\n + }\n + if (nexttoken.value === \'get\' && peek().id !== \':\') {\n + advance(\'get\');\n + if (!option.es5) {\n + error("get/set are ES5 features.");\n + }\n + i = property_name();\n + if (!i) {\n + error("Missing property name.");\n + }\n + saveGetter(i);\n + t = nexttoken;\n + adjacent(token, nexttoken);\n + f = doFunction();\n + p = f[\'(params)\'];\n + if (p) {\n + warning("Unexpected parameter \'{a}\' in get {b} function.", t, p[0], i);\n + }\n + adjacent(token, nexttoken);\n + } else if (nexttoken.value === \'set\' && peek().id !== \':\') {\n + advance(\'set\');\n + if (!option.es5) {\n + error("get/set are ES5 features.");\n + }\n + i = property_name();\n + if (!i) {\n + error("Missing property name.");\n + }\n + saveSetter(i, nexttoken);\n + t = nexttoken;\n + adjacent(token, nexttoken);\n + f = doFunction();\n + p = f[\'(params)\'];\n + if (!p || p.length !== 1) {\n + warning("Expected a single parameter in set {a} function.", t, i);\n + }\n + } else {\n + i = property_name();\n + saveProperty(i, nexttoken);\n + if (typeof i !== \'string\') {\n + break;\n + }\n + advance(\':\');\n + nonadjacent(token, nexttoken);\n + expression(10);\n + }\n +\n + countMember(i);\n + if (nexttoken.id === \',\') {\n + comma();\n + if (nexttoken.id === \',\') {\n + warning("Extra comma.", token);\n + } else if (nexttoken.id === \'}\' && !option.es5) {\n + warning("Extra comma.", token);\n + }\n + } else {\n + break;\n + }\n + }\n + if (b) {\n + indent -= option.indent;\n + indentation();\n + }\n + advance(\'}\', this);\n +\n + // Check for lonely setters if in the ES5 mode.\n + if (option.es5) {\n + for (var name in props) {\n + if (is_own(props, name) && props[name].setter && !props[name].getter) {\n + warning("Setter is defined without getter.", props[name].setterToken);\n + }\n + }\n + }\n + return this;\n + };\n + x.fud = function () {\n + error("Expected to see a statement and instead saw a block.", token);\n + };\n + }(delim(\'{\')));\n +\n +// This Function is called when esnext option is set to true\n +// it adds the `const` statement to JSHINT\n +\n + useESNextSyntax = function () {\n + var conststatement = stmt(\'const\', function (prefix) {\n + var id, name, value;\n +\n + this.first = [];\n + for (;;) {\n + nonadjacent(token, nexttoken);\n + id = identifier();\n + if (funct[id] === "const") {\n + warning("const \'" + id + "\' has already been declared");\n + }\n + if (funct[\'(global)\'] && predefined[id] === false) {\n + warning("Redefinition of \'{a}\'.", token, id);\n + }\n + addlabel(id, \'const\');\n + if (prefix) {\n + break;\n + }\n + name = token;\n + this.first.push(token);\n +\n + if (nexttoken.id !== "=") {\n + warning("const " +\n + "\'{a}\' is initialized to \'undefined\'.", token, id);\n + }\n +\n + if (nexttoken.id === \'=\') {\n + nonadjacent(token, nexttoken);\n + advance(\'=\');\n + nonadjacent(token, nexttoken);\n + if (nexttoken.id === \'undefined\') {\n + warning("It is not necessary to initialize " +\n + "\'{a}\' to \'undefined\'.", token, id);\n + }\n + if (peek(0).id === \'=\' && nexttoken.identifier) {\n + error("Constant {a} was not declared correctly.",\n + nexttoken, nexttoken.value);\n + }\n + value = expression(0);\n + name.first = value;\n + }\n +\n + if (nexttoken.id !== \',\') {\n + break;\n + }\n + comma();\n + }\n + return this;\n + });\n + conststatement.exps = true;\n + };\n +\n + var varstatement = stmt(\'var\', function (prefix) {\n + // JavaScript does not have block scope. It only has function scope. So,\n + // declaring a variable in a block can have unexpected consequences.\n + var id, name, value;\n +\n + if (funct[\'(onevar)\'] && option.onevar) {\n + warning("Too many var statements.");\n + } else if (!funct[\'(global)\']) {\n + funct[\'(onevar)\'] = true;\n + }\n + this.first = [];\n + for (;;) {\n + nonadjacent(token, nexttoken);\n + id = identifier();\n + if (option.esnext && funct[id] === "const") {\n + warning("const \'" + id + "\' has already been declared");\n + }\n + if (funct[\'(global)\'] && predefined[id] === false) {\n + warning("Redefinition of \'{a}\'.", token, id);\n + }\n + addlabel(id, \'unused\');\n + if (prefix) {\n + break;\n + }\n + name = token;\n + this.first.push(token);\n + if (nexttoken.id === \'=\') {\n + nonadjacent(token, nexttoken);\n + advance(\'=\');\n + nonadjacent(token, nexttoken);\n + if (nexttoken.id === \'undefined\') {\n + warning("It is not necessary to initialize \'{a}\' to \'undefined\'.", token, id);\n + }\n + if (peek(0).id === \'=\' && nexttoken.identifier) {\n + error("Variable {a} was not declared correctly.",\n + nexttoken, nexttoken.value);\n + }\n + value = expression(0);\n + name.first = value;\n + }\n + if (nexttoken.id !== \',\') {\n + break;\n + }\n + comma();\n + }\n + return this;\n + });\n + varstatement.exps = true;\n +\n + blockstmt(\'function\', function () {\n + if (inblock) {\n + warning("Function declarations should not be placed in blocks. " +\n + "Use a function expression or move the statement to the top of " +\n + "the outer function.", token);\n +\n + }\n + var i = identifier();\n + if (option.esnext && funct[i] === "const") {\n + warning("const \'" + i + "\' has already been declared");\n + }\n + adjacent(token, nexttoken);\n + addlabel(i, \'unction\');\n + doFunction(i, true);\n + if (nexttoken.id === \'(\' && nexttoken.line === token.line) {\n + error(\n +"Function declarations are not invocable. Wrap the whole function invocation in parens.");\n + }\n + return this;\n + });\n +\n + prefix(\'function\', function () {\n + var i = optionalidentifier();\n + if (i) {\n + adjacent(token, nexttoken);\n + } else {\n + nonadjacent(token, nexttoken);\n + }\n + doFunction(i);\n + if (!option.loopfunc && funct[\'(loopage)\']) {\n + warning("Don\'t make functions within a loop.");\n + }\n + return this;\n + });\n +\n + blockstmt(\'if\', function () {\n + var t = nexttoken;\n + advance(\'(\');\n + nonadjacent(this, t);\n + nospace();\n + expression(20);\n + if (nexttoken.id === \'=\') {\n + if (!option.boss)\n + warning("Expected a conditional expression and instead saw an assignment.");\n + advance(\'=\');\n + expression(20);\n + }\n + advance(\')\', t);\n + nospace(prevtoken, token);\n + block(true, true);\n + if (nexttoken.id === \'else\') {\n + nonadjacent(token, nexttoken);\n + advance(\'else\');\n + if (nexttoken.id === \'if\' || nexttoken.id === \'switch\') {\n + statement(true);\n + } else {\n + block(true, true);\n + }\n + }\n + return this;\n + });\n +\n + blockstmt(\'try\', function () {\n + var b, e, s;\n +\n + block(false);\n + if (nexttoken.id === \'catch\') {\n + advance(\'catch\');\n + nonadjacent(token, nexttoken);\n + advance(\'(\');\n + s = scope;\n + scope = Object.create(s);\n + e = nexttoken.value;\n + if (nexttoken.type !== \'(identifier)\') {\n + warning("Expected an identifier and instead saw \'{a}\'.",\n + nexttoken, e);\n + } else {\n + addlabel(e, \'exception\');\n + }\n + advance();\n + advance(\')\');\n + block(false);\n + b = true;\n + scope = s;\n + }\n + if (nexttoken.id === \'finally\') {\n + advance(\'finally\');\n + block(false);\n + return;\n + } else if (!b) {\n + error("Expected \'{a}\' and instead saw \'{b}\'.",\n + nexttoken, \'catch\', nexttoken.value);\n + }\n + return this;\n + });\n +\n + blockstmt(\'while\', function () {\n + var t = nexttoken;\n + funct[\'(breakage)\'] += 1;\n + funct[\'(loopage)\'] += 1;\n + advance(\'(\');\n + nonadjacent(this, t);\n + nospace();\n + expression(20);\n + if (nexttoken.id === \'=\') {\n + if (!option.boss)\n + warning("Expected a conditional expression and instead saw an assignment.");\n + advance(\'=\');\n + expression(20);\n + }\n + advance(\')\', t);\n + nospace(prevtoken, token);\n + block(true, true);\n + funct[\'(breakage)\'] -= 1;\n + funct[\'(loopage)\'] -= 1;\n + return this;\n + }).labelled = true;\n +\n + blockstmt(\'with\', function () {\n + var t = nexttoken;\n + if (directive[\'use strict\']) {\n + error("\'with\' is not allowed in strict mode.", token);\n + } else if (!option.withstmt) {\n + warning("Don\'t use \'with\'.", token);\n + }\n +\n + advance(\'(\');\n + nonadjacent(this, t);\n + nospace();\n + expression(0);\n + advance(\')\', t);\n + nospace(prevtoken, token);\n + block(true, true);\n +\n + return this;\n + });\n +\n + blockstmt(\'switch\', function () {\n + var t = nexttoken,\n + g = false;\n + funct[\'(breakage)\'] += 1;\n + advance(\'(\');\n + nonadjacent(this, t);\n + nospace();\n + this.condition = expression(20);\n + advance(\')\', t);\n + nospace(prevtoken, token);\n + nonadjacent(token, nexttoken);\n + t = nexttoken;\n + advance(\'{\');\n + nonadjacent(token, nexttoken);\n + indent += option.indent;\n + this.cases = [];\n + for (;;) {\n + switch (nexttoken.id) {\n + case \'case\':\n + switch (funct[\'(verb)\']) {\n + case \'break\':\n + case \'case\':\n + case \'continue\':\n + case \'return\':\n + case \'switch\':\n + case \'throw\':\n + break;\n + default:\n + // You can tell JSHint that you don\'t use break intentionally by\n + // adding a comment /* falls through */ on a line just before\n + // the next `case`.\n + if (!ft.test(lines[nexttoken.line - 2])) {\n + warning(\n + "Expected a \'break\' statement before \'case\'.",\n + token);\n + }\n + }\n + indentation(-option.indent);\n + advance(\'case\');\n + this.cases.push(expression(20));\n + g = true;\n + advance(\':\');\n + funct[\'(verb)\'] = \'case\';\n + break;\n + case \'default\':\n + switch (funct[\'(verb)\']) {\n + case \'break\':\n + case \'continue\':\n + case \'return\':\n + case \'throw\':\n + break;\n + default:\n + if (!ft.test(lines[nexttoken.line - 2])) {\n + warning(\n + "Expected a \'break\' statement before \'default\'.",\n + token);\n + }\n + }\n + indentation(-option.indent);\n + advance(\'default\');\n + g = true;\n + advance(\':\');\n + break;\n + case \'}\':\n + indent -= option.indent;\n + indentation();\n + advance(\'}\', t);\n + if (this.cases.length === 1 || this.condition.id === \'true\' ||\n + this.condition.id === \'false\') {\n + if (!option.onecase)\n + warning("This \'switch\' should be an \'if\'.", this);\n + }\n + funct[\'(breakage)\'] -= 1;\n + funct[\'(verb)\'] = undefined;\n + return;\n + case \'(end)\':\n + error("Missing \'{a}\'.", nexttoken, \'}\');\n + return;\n + default:\n + if (g) {\n + switch (token.id) {\n + case \',\':\n + error("Each value should have its own case label.");\n + return;\n + case \':\':\n + g = false;\n + statements();\n + break;\n + default:\n + error("Missing \':\' on a case clause.", token);\n + return;\n + }\n + } else {\n + if (token.id === \':\') {\n + advance(\':\');\n + error("Unexpected \'{a}\'.", token, \':\');\n + statements();\n + } else {\n + error("Expected \'{a}\' and instead saw \'{b}\'.",\n + nexttoken, \'case\', nexttoken.value);\n + return;\n + }\n + }\n + }\n + }\n + }).labelled = true;\n +\n + stmt(\'debugger\', function () {\n + if (!option.debug) {\n + warning("All \'debugger\' statements should be removed.");\n + }\n + return this;\n + }).exps = true;\n +\n + (function () {\n + var x = stmt(\'do\', function () {\n + funct[\'(breakage)\'] += 1;\n + funct[\'(loopage)\'] += 1;\n + this.first = block(true);\n + advance(\'while\');\n + var t = nexttoken;\n + nonadjacent(token, t);\n + advance(\'(\');\n + nospace();\n + expression(20);\n + if (nexttoken.id === \'=\') {\n + if (!option.boss)\n + warning("Expected a conditional expression and instead saw an assignment.");\n + advance(\'=\');\n + expression(20);\n + }\n + advance(\')\', t);\n + nospace(prevtoken, token);\n + funct[\'(breakage)\'] -= 1;\n + funct[\'(loopage)\'] -= 1;\n + return this;\n + });\n + x.labelled = true;\n + x.exps = true;\n + }());\n +\n + blockstmt(\'for\', function () {\n + var s, t = nexttoken;\n + funct[\'(breakage)\'] += 1;\n + funct[\'(loopage)\'] += 1;\n + advance(\'(\');\n + nonadjacent(this, t);\n + nospace();\n + if (peek(nexttoken.id === \'var\' ? 1 : 0).id === \'in\') {\n + if (nexttoken.id === \'var\') {\n + advance(\'var\');\n + varstatement.fud.call(varstatement, true);\n + } else {\n + switch (funct[nexttoken.value]) {\n + case \'unused\':\n + funct[nexttoken.value] = \'var\';\n + break;\n + case \'var\':\n + break;\n + default:\n + warning("Bad for in variable \'{a}\'.",\n + nexttoken, nexttoken.value);\n + }\n + advance();\n + }\n + advance(\'in\');\n + expression(20);\n + advance(\')\', t);\n + s = block(true, true);\n + if (option.forin && s && (s.length > 1 || typeof s[0] !== \'object\' ||\n + s[0].value !== \'if\')) {\n + warning("The body of a for in should be wrapped in an if statement to filter " +\n + "unwanted properties from the prototype.", this);\n + }\n + funct[\'(breakage)\'] -= 1;\n + funct[\'(loopage)\'] -= 1;\n + return this;\n + } else {\n + if (nexttoken.id !== \';\') {\n + if (nexttoken.id === \'var\') {\n + advance(\'var\');\n + varstatement.fud.call(varstatement);\n + } else {\n + for (;;) {\n + expression(0, \'for\');\n + if (nexttoken.id !== \',\') {\n + break;\n + }\n + comma();\n + }\n + }\n + }\n + nolinebreak(token);\n + advance(\';\');\n + if (nexttoken.id !== \';\') {\n + expression(20);\n + if (nexttoken.id === \'=\') {\n + if (!option.boss)\n + warning("Expected a conditional expression and instead saw an assignment.");\n + advance(\'=\');\n + expression(20);\n + }\n + }\n + nolinebreak(token);\n + advance(\';\');\n + if (nexttoken.id === \';\') {\n + error("Expected \'{a}\' and instead saw \'{b}\'.",\n + nexttoken, \')\', \';\');\n + }\n + if (nexttoken.id !== \')\') {\n + for (;;) {\n + expression(0, \'for\');\n + if (nexttoken.id !== \',\') {\n + break;\n + }\n + comma();\n + }\n + }\n + advance(\')\', t);\n + nospace(prevtoken, token);\n + block(true, true);\n + funct[\'(breakage)\'] -= 1;\n + funct[\'(loopage)\'] -= 1;\n + return this;\n + }\n + }).labelled = true;\n +\n +\n + stmt(\'break\', function () {\n + var v = nexttoken.value;\n +\n + if (funct[\'(breakage)\'] === 0)\n + warning("Unexpected \'{a}\'.", nexttoken, this.value);\n +\n + if (!option.asi)\n + nolinebreak(this);\n +\n + if (nexttoken.id !== \';\') {\n + if (token.line === nexttoken.line) {\n + if (funct[v] !== \'label\') {\n + warning("\'{a}\' is not a statement label.", nexttoken, v);\n + } else if (scope[v] !== funct) {\n + warning("\'{a}\' is out of scope.", nexttoken, v);\n + }\n + this.first = nexttoken;\n + advance();\n + }\n + }\n + reachable(\'break\');\n + return this;\n + }).exps = true;\n +\n +\n + stmt(\'continue\', function () {\n + var v = nexttoken.value;\n +\n + if (funct[\'(breakage)\'] === 0)\n + warning("Unexpected \'{a}\'.", nexttoken, this.value);\n +\n + if (!option.asi)\n + nolinebreak(this);\n +\n + if (nexttoken.id !== \';\') {\n + if (token.line === nexttoken.line) {\n + if (funct[v] !== \'label\') {\n + warning("\'{a}\' is not a statement label.", nexttoken, v);\n + } else if (scope[v] !== funct) {\n + warning("\'{a}\' is out of scope.", nexttoken, v);\n + }\n + this.first = nexttoken;\n + advance();\n + }\n + } else if (!funct[\'(loopage)\']) {\n + warning("Unexpected \'{a}\'.", nexttoken, this.value);\n + }\n + reachable(\'continue\');\n + return this;\n + }).exps = true;\n +\n +\n + stmt(\'return\', function () {\n + if (this.line === nexttoken.line) {\n + if (nexttoken.id === \'(regexp)\')\n + warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");\n +\n + if (nexttoken.id !== \';\' && !nexttoken.reach) {\n + nonadjacent(token, nexttoken);\n + if (peek().value === "=" && !option.boss) {\n + warningAt("Did you mean to return a conditional instead of an assignment?",\n + token.line, token.character + 1);\n + }\n + this.first = expression(0);\n + }\n + } else if (!option.asi) {\n + nolinebreak(this); // always warn (Line breaking error)\n + }\n + reachable(\'return\');\n + return this;\n + }).exps = true;\n +\n +\n + stmt(\'throw\', function () {\n + nolinebreak(this);\n + nonadjacent(token, nexttoken);\n + this.first = expression(20);\n + reachable(\'throw\');\n + return this;\n + }).exps = true;\n +\n +// Superfluous reserved words\n +\n + reserve(\'class\');\n + reserve(\'const\');\n + reserve(\'enum\');\n + reserve(\'export\');\n + reserve(\'extends\');\n + reserve(\'import\');\n + reserve(\'super\');\n +\n + reserve(\'let\');\n + reserve(\'yield\');\n + reserve(\'implements\');\n + reserve(\'interface\');\n + reserve(\'package\');\n + reserve(\'private\');\n + reserve(\'protected\');\n + reserve(\'public\');\n + reserve(\'static\');\n +\n +\n +// Parse JSON\n +\n + function jsonValue() {\n +\n + function jsonObject() {\n + var o = {}, t = nexttoken;\n + advance(\'{\');\n + if (nexttoken.id !== \'}\') {\n + for (;;) {\n + if (nexttoken.id === \'(end)\') {\n + error("Missing \'}\' to match \'{\' from line {a}.",\n + nexttoken, t.line);\n + } else if (nexttoken.id === \'}\') {\n + warning("Unexpected comma.", token);\n + break;\n + } else if (nexttoken.id === \',\') {\n + error("Unexpected comma.", nexttoken);\n + } else if (nexttoken.id !== \'(string)\') {\n + warning("Expected a string and instead saw {a}.",\n + nexttoken, nexttoken.value);\n + }\n + if (o[nexttoken.value] === true) {\n + warning("Duplicate key \'{a}\'.",\n + nexttoken, nexttoken.value);\n + } else if ((nexttoken.value === \'__proto__\' &&\n + !option.proto) || (nexttoken.value === \'__iterator__\' &&\n + !option.iterator)) {\n + warning("The \'{a}\' key may produce unexpected results.",\n + nexttoken, nexttoken.value);\n + } else {\n + o[nexttoken.value] = true;\n + }\n + advance();\n + advance(\':\');\n + jsonValue();\n + if (nexttoken.id !== \',\') {\n + break;\n + }\n + advance(\',\');\n + }\n + }\n + advance(\'}\');\n + }\n +\n + function jsonArray() {\n + var t = nexttoken;\n + advance(\'[\');\n + if (nexttoken.id !== \']\') {\n + for (;;) {\n + if (nexttoken.id === \'(end)\') {\n + error("Missing \']\' to match \'[\' from line {a}.",\n + nexttoken, t.line);\n + } else if (nexttoken.id === \']\') {\n + warning("Unexpected comma.", token);\n + break;\n + } else if (nexttoken.id === \',\') {\n + error("Unexpected comma.", nexttoken);\n + }\n + jsonValue();\n + if (nexttoken.id !== \',\') {\n + break;\n + }\n + advance(\',\');\n + }\n + }\n + advance(\']\');\n + }\n +\n + switch (nexttoken.id) {\n + case \'{\':\n + jsonObject();\n + break;\n + case \'[\':\n + jsonArray();\n + break;\n + case \'true\':\n + case \'false\':\n + case \'null\':\n + case \'(number)\':\n + case \'(string)\':\n + advance();\n + break;\n + case \'-\':\n + advance(\'-\');\n + if (token.character !== nexttoken.from) {\n + warning("Unexpected space after \'-\'.", token);\n + }\n + adjacent(token, nexttoken);\n + advance(\'(number)\');\n + break;\n + default:\n + error("Expected a JSON value.", nexttoken);\n + }\n + }\n +\n +\n +// The actual JSHINT function itself.\n +\n + var itself = function (s, o, g) {\n + var a, i, k, x,\n + optionKeys,\n + newOptionObj = {};\n +\n + JSHINT.errors = [];\n + JSHINT.undefs = [];\n + predefined = Object.create(standard);\n + combine(predefined, g || {});\n + if (o) {\n + a = o.predef;\n + if (a) {\n + if (Array.isArray(a)) {\n + for (i = 0; i < a.length; i += 1) {\n + predefined[a[i]] = true;\n + }\n + } else if (typeof a === \'object\') {\n + k = Object.keys(a);\n + for (i = 0; i < k.length; i += 1) {\n + predefined[k[i]] = !!a[k[i]];\n + }\n + }\n + }\n + optionKeys = Object.keys(o);\n + for (x = 0; x < optionKeys.length; x++) {\n + newOptionObj[optionKeys[x]] = o[optionKeys[x]];\n + }\n + }\n +\n + option = newOptionObj;\n +\n + option.indent = option.indent || 4;\n + option.maxerr = option.maxerr || 50;\n +\n + tab = \'\';\n + for (i = 0; i < option.indent; i += 1) {\n + tab += \' \';\n + }\n + indent = 1;\n + global = Object.create(predefined);\n + scope = global;\n + funct = {\n + \'(global)\': true,\n + \'(name)\': \'(global)\',\n + \'(scope)\': scope,\n + \'(breakage)\': 0,\n + \'(loopage)\': 0\n + };\n + functions = [funct];\n + urls = [];\n + stack = null;\n + member = {};\n + membersOnly = null;\n + implied = {};\n + inblock = false;\n + lookahead = [];\n + jsonmode = false;\n + warnings = 0;\n + lex.init(s);\n + prereg = true;\n + directive = {};\n +\n + prevtoken = token = nexttoken = syntax[\'(begin)\'];\n +\n + // Check options\n + for (var name in o) {\n + if (is_own(o, name)) {\n + checkOption(name, token);\n + }\n + }\n +\n + assume();\n +\n + // combine the passed globals after we\'ve assumed all our options\n + combine(predefined, g || {});\n +\n + //reset values\n + comma.first = true;\n +\n + try {\n + advance();\n + switch (nexttoken.id) {\n + case \'{\':\n + case \'[\':\n + option.laxbreak = true;\n + jsonmode = true;\n + jsonValue();\n + break;\n + default:\n + directives();\n + if (directive["use strict"] && !option.globalstrict) {\n + warning("Use the function form of \\"use strict\\".", prevtoken);\n + }\n +\n + statements();\n + }\n + advance(\'(end)\');\n +\n + var markDefined = function (name, context) {\n + do {\n + if (typeof context[name] === \'string\') {\n + // JSHINT marks unused variables as \'unused\' and\n + // unused function declaration as \'unction\'. This\n + // code changes such instances back \'var\' and\n + // \'closure\' so that the code in JSHINT.data()\n + // doesn\'t think they\'re unused.\n +\n + if (context[name] === \'unused\')\n + context[name] = \'var\';\n + else if (context[name] === \'unction\')\n + context[name] = \'closure\';\n +\n + return true;\n + }\n +\n + context = context[\'(context)\'];\n + } while (context);\n +\n + return false;\n + };\n +\n + var clearImplied = function (name, line) {\n + if (!implied[name])\n + return;\n +\n + var newImplied = [];\n + for (var i = 0; i < implied[name].length; i += 1) {\n + if (implied[name][i] !== line)\n + newImplied.push(implied[name][i]);\n + }\n +\n + if (newImplied.length === 0)\n + delete implied[name];\n + else\n + implied[name] = newImplied;\n + };\n +\n + // Check queued \'x is not defined\' instances to see if they\'re still undefined.\n + for (i = 0; i < JSHINT.undefs.length; i += 1) {\n + k = JSHINT.undefs[i].slice(0);\n +\n + if (markDefined(k[2].value, k[0])) {\n + clearImplied(k[2].value, k[2].line);\n + } else {\n + warning.apply(warning, k.slice(1));\n + }\n + }\n + } catch (e) {\n + if (e) {\n + var nt = nexttoken || {};\n + JSHINT.errors.push({\n + raw : e.raw,\n + reason : e.message,\n + line : e.line || nt.line,\n + character : e.character || nt.from\n + }, null);\n + }\n + }\n +\n + return JSHINT.errors.length === 0;\n + };\n +\n + // Data summary.\n + itself.data = function () {\n +\n + var data = { functions: [], options: option }, fu, globals, implieds = [], f, i, j,\n + members = [], n, unused = [], v;\n + if (itself.errors.length) {\n + data.errors = itself.errors;\n + }\n +\n + if (jsonmode) {\n + data.json = true;\n + }\n +\n + for (n in implied) {\n + if (is_own(implied, n)) {\n + implieds.push({\n + name: n,\n + line: implied[n]\n + });\n + }\n + }\n + if (implieds.length > 0) {\n + data.implieds = implieds;\n + }\n +\n + if (urls.length > 0) {\n + data.urls = urls;\n + }\n +\n + globals = Object.keys(scope);\n + if (globals.length > 0) {\n + data.globals = globals;\n + }\n + for (i = 1; i < functions.length; i += 1) {\n + f = functions[i];\n + fu = {};\n + for (j = 0; j < functionicity.length; j += 1) {\n + fu[functionicity[j]] = [];\n + }\n + for (n in f) {\n + if (is_own(f, n) && n.charAt(0) !== \'(\') {\n + v = f[n];\n + if (v === \'unction\') {\n + v = \'unused\';\n + }\n + if (Array.isArray(fu[v])) {\n + fu[v].push(n);\n + if (v === \'unused\') {\n + unused.push({\n + name: n,\n + line: f[\'(line)\'],\n + \'function\': f[\'(name)\']\n + });\n + }\n + }\n + }\n + }\n + for (j = 0; j < functionicity.length; j += 1) {\n + if (fu[functionicity[j]].length === 0) {\n + delete fu[functionicity[j]];\n + }\n + }\n + fu.name = f[\'(name)\'];\n + fu.param = f[\'(params)\'];\n + fu.line = f[\'(line)\'];\n + fu.last = f[\'(last)\'];\n + data.functions.push(fu);\n + }\n +\n + if (unused.length > 0) {\n + data.unused = unused;\n + }\n +\n + members = [];\n + for (n in member) {\n + if (typeof member[n] === \'number\') {\n + data.member = member;\n + break;\n + }\n + }\n +\n + return data;\n + };\n +\n + itself.report = function (option) {\n + var data = itself.data();\n +\n + var a = [], c, e, err, f, i, k, l, m = \'\', n, o = [], s;\n +\n + function detail(h, array) {\n + var b, i, singularity;\n + if (array) {\n + o.push(\'<div><i>\' + h + \'</i> \');\n + array = array.sort();\n + for (i = 0; i < array.length; i += 1) {\n + if (array[i] !== singularity) {\n + singularity = array[i];\n + o.push((b ? \', \' : \'\') + singularity);\n + b = true;\n + }\n + }\n + o.push(\'</div>\');\n + }\n + }\n +\n +\n + if (data.errors || data.implieds || data.unused) {\n + err = true;\n + o.push(\'<div id=errors><i>Error:</i>\');\n + if (data.errors) {\n + for (i = 0; i < data.errors.length; i += 1) {\n + c = data.errors[i];\n + if (c) {\n + e = c.evidence || \'\';\n + o.push(\'<p>Problem\' + (isFinite(c.line) ? \' at line \' +\n + c.line + \' character \' + c.character : \'\') +\n + \': \' + c.reason.entityify() +\n + \'</p><p class=evidence>\' +\n + (e && (e.length > 80 ? e.slice(0, 77) + \'...\' :\n + e).entityify()) + \'</p>\');\n + }\n + }\n + }\n +\n + if (data.implieds) {\n + s = [];\n + for (i = 0; i < data.implieds.length; i += 1) {\n + s[i] = \'<code>\' + data.implieds[i].name + \'</code> <i>\' +\n + data.implieds[i].line + \'</i>\';\n + }\n + o.push(\'<p><i>Implied global:</i> \' + s.join(\', \') + \'</p>\');\n + }\n +\n + if (data.unused) {\n + s = [];\n + for (i = 0; i < data.unused.length; i += 1) {\n + s[i] = \'<code><u>\' + data.unused[i].name + \'</u></code> <i>\' +\n + data.unused[i].line + \'</i> <code>\' +\n + data.unused[i][\'function\'] + \'</code>\';\n + }\n + o.push(\'<p><i>Unused variable:</i> \' + s.join(\', \') + \'</p>\');\n + }\n + if (data.json) {\n + o.push(\'<p>JSON: bad.</p>\');\n + }\n + o.push(\'</div>\');\n + }\n +\n + if (!option) {\n +\n + o.push(\'<br><div id=functions>\');\n +\n + if (data.urls) {\n + detail("URLs<br>", data.urls, \'<br>\');\n + }\n +\n + if (data.json && !err) {\n + o.push(\'<p>JSON: good.</p>\');\n + } else if (data.globals) {\n + o.push(\'<div><i>Global</i> \' +\n + data.globals.sort().join(\', \') + \'</div>\');\n + } else {\n + o.push(\'<div><i>No new global variables introduced.</i></div>\');\n + }\n +\n + for (i = 0; i < data.functions.length; i += 1) {\n + f = data.functions[i];\n +\n + o.push(\'<br><div class=function><i>\' + f.line + \'-\' +\n + f.last + \'</i> \' + (f.name || \'\') + \'(\' +\n + (f.param ? f.param.join(\', \') : \'\') + \')</div>\');\n + detail(\'<big><b>Unused</b></big>\', f.unused);\n + detail(\'Closure\', f.closure);\n + detail(\'Variable\', f[\'var\']);\n + detail(\'Exception\', f.exception);\n + detail(\'Outer\', f.outer);\n + detail(\'Global\', f.global);\n + detail(\'Label\', f.label);\n + }\n +\n + if (data.member) {\n + a = Object.keys(data.member);\n + if (a.length) {\n + a = a.sort();\n + m = \'<br><pre id=members>/*members \';\n + l = 10;\n + for (i = 0; i < a.length; i += 1) {\n + k = a[i];\n + n = k.name();\n + if (l + n.length > 72) {\n + o.push(m + \'<br>\');\n + m = \' \';\n + l = 1;\n + }\n + l += n.length + 2;\n + if (data.member[k] === 1) {\n + n = \'<i>\' + n + \'</i>\';\n + }\n + if (i < a.length - 1) {\n + n += \', \';\n + }\n + m += n;\n + }\n + o.push(m + \'<br>*/</pre>\');\n + }\n + o.push(\'</div>\');\n + }\n + }\n + return o.join(\'\');\n + };\n +\n + itself.jshint = itself;\n +\n + return itself;\n +}());\n +\n +// Make JSHINT a Node module, if possible.\n +if (typeof exports === \'object\' && exports)\n + exports.JSHINT = JSHINT;\n + + +]]></string> </value> + </item> + <item> + <key> <string>next</string> </key> + <value> + <none/> + </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_code_mirror/bt/change_log b/bt5/erp5_code_mirror/bt/change_log index 85ec308f17d249e31daaa295bb379af2626fd263..b3f395cd74884fc85f16601feeec24daa30cbed7 100644 --- a/bt5/erp5_code_mirror/bt/change_log +++ b/bt5/erp5_code_mirror/bt/change_log @@ -1,3 +1,6 @@ +2015-04-23 arnaud.fontaine +* Add support for the ZMI. + 2015-01-22 arnaud.fontaine * Gutter and source code separator line was not displayed because of erp5.css (df7eb0f). diff --git a/bt5/erp5_code_mirror/bt/comment b/bt5/erp5_code_mirror/bt/comment index 766ff76161cace6e6817450bac45669a33645f39..1209268a3e1e23b9526c493e9dc58d40f6191388 100644 --- a/bt5/erp5_code_mirror/bt/comment +++ b/bt5/erp5_code_mirror/bt/comment @@ -2,4 +2,10 @@ CodeMirror is available at: http://codemirror.net diff_match_patch (used by CodeMirror Merge addon): -https://code.google.com/p/google-diff-match-patch \ No newline at end of file +https://code.google.com/p/google-diff-match-patch + +jshint.js (used by CodeMirror Javascript lint addon): +http://ajax.aspnetcdn.com/ajax/jshint/r07/jshint.js + +csslint.js (used by CodeMirror CSS lint addon): +https://rawgit.com/stubbornella/csslint/master/release/csslint.js diff --git a/bt5/erp5_code_mirror/bt/copyright_list b/bt5/erp5_code_mirror/bt/copyright_list index 51cd3130bd0da6e346997b136ca058396374fa55..5a5c175cc06ca586b7307333012a081f6a2ff0fd 100644 --- a/bt5/erp5_code_mirror/bt/copyright_list +++ b/bt5/erp5_code_mirror/bt/copyright_list @@ -5,4 +5,10 @@ CodeMirror (under MIT license): Copyright (c) 2014 by Marijn Haverbeke <marijnh@gmail.com> and others diff_match_patch (under Apache 2.0 license) -Copyright (c) 2006 Google Inc. \ No newline at end of file +Copyright (c) 2006 Google Inc. + +jshint.js (under modified MIT license): +Copyright (c) 2002 Douglas Crockford (www.JSLint.com) + +csslint.js (under MIT license): +Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. diff --git a/product/ERP5Form/EditorField.py b/product/ERP5Form/EditorField.py index 8a90688b7678f430c2698c3c5b9ac50ddc4e2e76..43781da83a66c26cd33113e7d3e53a5cbaa82b58 100644 --- a/product/ERP5Form/EditorField.py +++ b/product/ERP5Form/EditorField.py @@ -126,7 +126,8 @@ class EditorWidget(Widget.TextAreaWidget): return code_mirror_support(field=field, content=value, field_id=key, - portal_url=site_root.absolute_url()) + portal_url=site_root.absolute_url(), + mode='python') elif text_editor != 'text_area': return here.fckeditor_wysiwyg_support.pt_render( extra_context= { diff --git a/product/ERP5Type/patches/AceEditorZMI.py b/product/ERP5Type/patches/AceEditorZMI.py index 8f7ee09406057732143c88c6ee55ae9b7f021048..ac19619c1c16d719acb92b4fa93b347dc7668326 100644 --- a/product/ERP5Type/patches/AceEditorZMI.py +++ b/product/ERP5Type/patches/AceEditorZMI.py @@ -19,7 +19,7 @@ def manage_page_footer(self): except: editor = None - if editor != 'ace': + if editor not in ('ace', 'codemirror'): return default # REQUEST['PUBLISHED'] can be the form in the acquisition context of the @@ -67,14 +67,28 @@ def manage_page_footer(self): textarea_selector = 'textarea[name="template:text"]' elif document.meta_type in ('Page Template', 'ERP5 OOo Template', ): if 'html' in document.content_type: - mode = 'html' + if editor == 'codemirror': + mode = 'htmlmixed' + else: + mode = 'html' else: mode = 'xml' textarea_selector = 'textarea[name="text:text"]' if not textarea_selector: return default - return ''' + + if editor == 'codemirror' and getattr(portal, 'code_mirror_support', None) is not None: + return '''<script type="text/javascript" src="%s/jquery/core/jquery.min.js"></script> + %s + </body> + </html>''' % (portal_url, + portal.code_mirror_support(textarea_selector=textarea_selector, + portal_url=portal_url, + bound_names=bound_names, + mode=mode)) + else: + return ''' <script type="text/javascript" src="%(portal_url)s/jquery/core/jquery.min.js"></script> <script type="text/javascript" src="%(portal_url)s/ace/ace.js"></script> <script type="text/javascript" src="%(portal_url)s/ace/mode-%(mode)s.js"></script>