Created
August 23, 2013 22:24
-
-
Save lcaballero/6324608 to your computer and use it in GitHub Desktop.
CSS Parser in JavaScript. Fork of cssParser (see the lisence and comments).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ***** BEGIN LICENSE BLOCK ***** | |
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 | |
* | |
* The contents of this file are subject to the Mozilla Public License Version | |
* 1.1 (the "License"); you may not use this file except in compliance with | |
* the License. You may obtain a copy of the License at | |
* http://www.mozilla.org/MPL/ | |
* | |
* Software distributed under the License is distributed on an "AS IS" basis, | |
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
* for the specific language governing rights and limitations under the | |
* License. | |
* | |
* The Original Code is mozilla.org code. | |
* | |
* The Initial Developer of the Original Code is | |
* Netscape Communications Corporation. | |
* Portions created by the Initial Developer are Copyright (C) 1998 | |
* the Initial Developer. All Rights Reserved. | |
* | |
* Contributor(s): | |
* emk <[email protected]> | |
* Daniel Glazman <[email protected]> | |
* L. David Baron <[email protected]> | |
* Boris Zbarsky <[email protected]> | |
* Mats Palmgren <[email protected]> | |
* Christian Biesinger <[email protected]> | |
* Jeff Walden <[email protected]> | |
* Jonathon Jongsma <[email protected]>, Collabora Ltd. | |
* Siraj Razick <[email protected]>, Collabora Ltd. | |
* Daniel Glazman <[email protected]> | |
* | |
* Alternatively, the contents of this file may be used under the terms of | |
* either of the GNU General Public License Version 2 or later (the "GPL"), | |
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), | |
* in which case the provisions of the GPL or the LGPL are applicable instead | |
* of those above. If you wish to allow use of your version of this file only | |
* under the terms of either the GPL or the LGPL, and not to allow others to | |
* use your version of this file under the terms of the MPL, indicate your | |
* decision by deleting the provisions above and replace them with the notice | |
* and other provisions required by the GPL or the LGPL. If you do not delete | |
* the provisions above, a recipient may use your version of this file under | |
* the terms of any one of the MPL, the GPL or the LGPL. | |
* | |
* ***** END LICENSE BLOCK ***** */ | |
var kCHARSET_RULE_MISSING_SEMICOLON = "Missing semicolon at the end of @charset rule"; | |
var kCHARSET_RULE_CHARSET_IS_STRING = "The charset in the @charset rule should be a string"; | |
var kCHARSET_RULE_MISSING_WS = "Missing mandatory whitespace after @charset"; | |
var kIMPORT_RULE_MISSING_URL = "Missing URL in @import rule"; | |
var kURL_EOF = "Unexpected end of stylesheet"; | |
var kURL_WS_INSIDE = "Multiple tokens inside a url() notation"; | |
var kVARIABLES_RULE_POSITION = "@variables rule invalid at this position in the stylesheet"; | |
var kIMPORT_RULE_POSITION = "@import rule invalid at this position in the stylesheet"; | |
var kNAMESPACE_RULE_POSITION = "@namespace rule invalid at this position in the stylesheet"; | |
var kCHARSET_RULE_CHARSET_SOF = "@charset rule invalid at this position in the stylesheet"; | |
var kUNKNOWN_AT_RULE = "Unknow @-rule"; | |
/* FROM http://peter.sh/data/vendor-prefixed-css.php?js=1 */ | |
var kCSS_VENDOR_VALUES = { | |
"-moz-box": {"webkit": "-webkit-box", "presto": "", "trident": "", "generic": "box" }, | |
"-moz-inline-box": {"webkit": "-webkit-inline-box", "presto": "", "trident": "", "generic": "inline-box" }, | |
"-moz-initial": {"webkit": "", "presto": "", "trident": "", "generic": "initial" }, | |
"flex": {"webkit": "-webkit-flex", "presto": "", "trident": "", "generic": "" }, | |
"inline-flex": {"webkit": "-webkit-inline-flex", "presto": "", "trident": "", "generic": "" }, | |
"linear-gradient": {"webkit20110101":FilterLinearGradient, | |
"webkit": FilterLinearGradient, | |
"presto": FilterLinearGradient, | |
"trident": FilterLinearGradient, | |
"gecko1.9.2": FilterLinearGradient }, | |
"repeating-linear-gradient": {"webkit20110101":FilterLinearGradient, | |
"webkit": FilterLinearGradient, | |
"presto": FilterLinearGradient, | |
"trident": FilterLinearGradient, | |
"gecko1.9.2": FilterLinearGradient }, | |
"radial-gradient": {"webkit20110101":FilterRadialGradient, | |
"webkit": FilterRadialGradient, | |
"presto": FilterRadialGradient, | |
"trident": FilterRadialGradient, | |
"gecko1.9.2": FilterRadialGradient }, | |
"repeating-radial-gradient": {"webkit20110101":FilterRadialGradient, | |
"webkit": FilterRadialGradient, | |
"presto": FilterRadialGradient, | |
"trident": FilterRadialGradient, | |
"gecko1.9.2": FilterRadialGradient } | |
}; | |
var kCSS_PREFIXED_VALUE = [ | |
{"gecko": "-moz-box", "webkit": "-moz-box", "presto": "", "trident": "", "generic": "box"} | |
]; | |
var kCSS_VENDOR_PREFIXES = | |
{"lastUpdate":1374677405,"properties":[ | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-accelerator","status":"P"}, | |
{"gecko":"","webkit":"","presto":"-wap-accesskey","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-align-content","presto":"","trident":"","status":""}, | |
{"gecko":"align-items","webkit":"-webkit-align-items","presto":"","trident":"","status":""}, | |
{"gecko":"align-self","webkit":"-webkit-align-self","presto":"","trident":"","status":""}, | |
{"gecko":"animation","webkit":"-webkit-animation","presto":"","trident":"animation","status":"WD"}, | |
{"gecko":"animation-delay","webkit":"-webkit-animation-delay","presto":"","trident":"animation-delay","status":"WD"}, | |
{"gecko":"animation-direction","webkit":"-webkit-animation-direction","presto":"","trident":"animation-direction","status":"WD"}, | |
{"gecko":"animation-duration","webkit":"-webkit-animation-duration","presto":"","trident":"animation-duration","status":"WD"}, | |
{"gecko":"animation-fill-mode","webkit":"-webkit-animation-fill-mode","presto":"","trident":"animation-fill-mode","status":"ED"}, | |
{"gecko":"animation-iteration-count","webkit":"-webkit-animation-iteration-count","presto":"","trident":"animation-iteration-count","status":"WD"}, | |
{"gecko":"animation-name","webkit":"-webkit-animation-name","presto":"","trident":"animation-name","status":"WD"}, | |
{"gecko":"animation-play-state","webkit":"-webkit-animation-play-state","presto":"","trident":"animation-play-state","status":"WD"}, | |
{"gecko":"animation-timing-function","webkit":"-webkit-animation-timing-function","presto":"","trident":"animation-timing-function","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-app-region","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-appearance","webkit":"-webkit-appearance","presto":"","trident":"","status":"CR"}, | |
{"gecko":"","webkit":"-webkit-aspect-ratio","presto":"","trident":"","status":""}, | |
{"gecko":"backface-visibility","webkit":"-webkit-backface-visibility","presto":"","trident":"backface-visibility","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-background-blend-mode","presto":"","trident":"","status":""}, | |
{"gecko":"background-clip","webkit":"-webkit-background-clip","presto":"background-clip","trident":"background-clip","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-background-composite","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-background-inline-policy","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"background-origin","webkit":"-webkit-background-origin","presto":"background-origin","trident":"background-origin","status":"WD"}, | |
{"gecko":"","webkit":"background-position-x","presto":"","trident":"-ms-background-position-x","status":""}, | |
{"gecko":"","webkit":"background-position-y","presto":"","trident":"-ms-background-position-y","status":""}, | |
{"gecko":"background-size","webkit":"-webkit-background-size","presto":"background-size","trident":"background-size","status":"WD"}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-behavior","status":""}, | |
{"gecko":"-moz-binding","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"","webkit":"-webkit-blend-mode","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-block-progression","status":""}, | |
{"gecko":"","webkit":"-webkit-border-after","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-border-after-color","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-border-after-style","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-border-after-width","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-border-before","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-border-before-color","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-border-before-style","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-border-before-width","presto":"","trident":"","status":"ED"}, | |
{"gecko":"-moz-border-bottom-colors","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"border-bottom-left-radius","webkit":"-webkit-border-bottom-left-radius","presto":"border-bottom-left-radius","trident":"border-bottom-left-radius","status":"WD"}, | |
{"gecko":"border-bottom-right-radius","webkit":"-webkit-border-bottom-right-radius","presto":"border-bottom-right-radius","trident":"border-bottom-right-radius","status":"WD"}, | |
{"gecko":"-moz-border-end","webkit":"-webkit-border-end","presto":"","trident":"","status":"ED"}, | |
{"gecko":"-moz-border-end-color","webkit":"-webkit-border-end-color","presto":"","trident":"","status":"ED"}, | |
{"gecko":"-moz-border-end-style","webkit":"-webkit-border-end-style","presto":"","trident":"","status":"ED"}, | |
{"gecko":"-moz-border-end-width","webkit":"-webkit-border-end-width","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-border-fit","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-border-horizontal-spacing","presto":"","trident":"","status":""}, | |
{"gecko":"border-image","webkit":"-webkit-border-image","presto":"-o-border-image","trident":"","status":"WD"}, | |
{"gecko":"-moz-border-left-colors","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"border-radius","webkit":"-webkit-border-radius","presto":"border-radius","trident":"border-radius","status":"WD"}, | |
{"gecko":"-moz-border-right-colors","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-border-start","webkit":"-webkit-border-start","presto":"","trident":"","status":"ED"}, | |
{"gecko":"-moz-border-start-color","webkit":"-webkit-border-start-color","presto":"","trident":"","status":"ED"}, | |
{"gecko":"-moz-border-start-style","webkit":"-webkit-border-start-style","presto":"","trident":"","status":"ED"}, | |
{"gecko":"-moz-border-start-width","webkit":"-webkit-border-start-width","presto":"","trident":"","status":"ED"}, | |
{"gecko":"-moz-border-top-colors","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"border-top-left-radius","webkit":"-webkit-border-top-left-radius","presto":"border-top-left-radius","trident":"border-top-left-radius","status":"WD"}, | |
{"gecko":"border-top-right-radius","webkit":"-webkit-border-top-right-radius","presto":"border-top-right-radius","trident":"border-top-right-radius","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-border-vertical-spacing","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-box-align","webkit":"-webkit-box-align","presto":"","trident":"","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-box-decoration-break","presto":"box-decoration-break","trident":"","status":"WD"}, | |
{"gecko":"-moz-box-direction","webkit":"-webkit-box-direction","presto":"","trident":"","status":"WD"}, | |
{"gecko":"-moz-box-flex","webkit":"-webkit-box-flex","presto":"","trident":"","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-box-flex-group","presto":"","trident":"","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-box-lines","presto":"","trident":"","status":"WD"}, | |
{"gecko":"-moz-box-ordinal-group","webkit":"-webkit-box-ordinal-group","presto":"","trident":"","status":"WD"}, | |
{"gecko":"-moz-box-orient","webkit":"-webkit-box-orient","presto":"","trident":"","status":"WD"}, | |
{"gecko":"-moz-box-pack","webkit":"-webkit-box-pack","presto":"","trident":"","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-box-reflect","presto":"","trident":"","status":""}, | |
{"gecko":"box-shadow","webkit":"-webkit-box-shadow","presto":"box-shadow","trident":"box-shadow","status":"WD"}, | |
{"gecko":"-moz-box-sizing","webkit":"-webkit-box-sizing","presto":"box-sizing","trident":"box-sizing","status":"CR"}, | |
{"gecko":"caption-side","webkit":"-epub-caption-side","presto":"caption-side","trident":"caption-side","status":""}, | |
{"gecko":"clip-path","webkit":"-webkit-clip-path","presto":"clip-path","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-color-correction","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-column-axis","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-column-break-after","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-column-break-before","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-column-break-inside","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-column-count","webkit":"-webkit-column-count","presto":"column-count","trident":"column-count","status":"CR"}, | |
{"gecko":"-moz-column-fill","webkit":"","presto":"column-fill","trident":"column-fill","status":"CR"}, | |
{"gecko":"-moz-column-gap","webkit":"-webkit-column-gap","presto":"column-gap","trident":"column-gap","status":"CR"}, | |
{"gecko":"","webkit":"-webkit-column-progression","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-column-rule","webkit":"-webkit-column-rule","presto":"column-rule","trident":"column-rule","status":"CR"}, | |
{"gecko":"-moz-column-rule-color","webkit":"-webkit-column-rule-color","presto":"column-rule-color","trident":"column-rule-color","status":"CR"}, | |
{"gecko":"-moz-column-rule-style","webkit":"-webkit-column-rule-style","presto":"column-rule-style","trident":"column-rule-style","status":"CR"}, | |
{"gecko":"-moz-column-rule-width","webkit":"-webkit-column-rule-width","presto":"column-rule-width","trident":"column-rule-width","status":"CR"}, | |
{"gecko":"","webkit":"-webkit-column-span","presto":"column-span","trident":"column-span","status":"CR"}, | |
{"gecko":"-moz-column-width","webkit":"-webkit-column-width","presto":"column-width","trident":"column-width","status":"CR"}, | |
{"gecko":"-moz-columns","webkit":"-webkit-columns","presto":"columns","trident":"columns","status":"CR"}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-content-zoom-chaining","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-content-zoom-limit","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-content-zoom-limit-max","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-content-zoom-limit-min","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-content-zoom-snap","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-content-zoom-snap-points","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-content-zoom-snap-type","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-content-zooming","status":""}, | |
{"gecko":"","webkit":"-webkit-cursor-visibility","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-dashboard-region","presto":"-apple-dashboard-region","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-o-device-pixel-ratio","trident":"","status":""}, | |
{"gecko":"filter","webkit":"-webkit-filter","presto":"filter","trident":"-ms-filter","status":""}, | |
{"gecko":"flex","webkit":"-webkit-flex","presto":"","trident":"-ms-flex","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-flex-align","status":""}, | |
{"gecko":"flex-basis","webkit":"-webkit-flex-basis","presto":"","trident":"","status":""}, | |
{"gecko":"flex-direction","webkit":"-webkit-flex-direction","presto":"","trident":"-ms-flex-direction","status":""}, | |
{"gecko":"","webkit":"-webkit-flex-flow","presto":"","trident":"","status":""}, | |
{"gecko":"flex-grow","webkit":"-webkit-flex-grow","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-flex-order","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-flex-pack","status":""}, | |
{"gecko":"flex-shrink","webkit":"-webkit-flex-shrink","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-flex-wrap","presto":"","trident":"-ms-flex-wrap","status":""}, | |
{"gecko":"-moz-float-edge","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"","webkit":"-webkit-flow-from","presto":"","trident":"-ms-flow-from","status":""}, | |
{"gecko":"","webkit":"-webkit-flow-into","presto":"","trident":"-ms-flow-into","status":""}, | |
{"gecko":"","webkit":"","presto":"-o-focus-opacity","trident":"","status":""}, | |
{"gecko":"-moz-font-feature-settings","webkit":"-webkit-font-feature-settings","presto":"","trident":"font-feature-settings","status":""}, | |
{"gecko":"font-kerning","webkit":"-webkit-font-kerning","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-font-language-override","webkit":"","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-font-size-delta","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-font-smoothing","presto":"","trident":"","status":""}, | |
{"gecko":"font-variant-ligatures","webkit":"-webkit-font-variant-ligatures","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-force-broken-image-icon","webkit":"","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-grid-after","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-grid-auto-columns","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-grid-auto-flow","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-grid-auto-rows","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-grid-before","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-grid-column","presto":"","trident":"-ms-grid-column","status":"WD"}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-column-align","status":"WD"}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-column-span","status":"WD"}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-columns","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-grid-definition-columns","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-grid-definition-rows","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-grid-end","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-grid-row","presto":"","trident":"-ms-grid-row","status":"WD"}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-row-align","status":"WD"}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-row-span","status":"WD"}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-rows","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-grid-start","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-high-contrast-adjust","status":""}, | |
{"gecko":"","webkit":"-webkit-highlight","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-hyphenate-character","presto":"","trident":"","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-hyphenate-limit-after","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-hyphenate-limit-before","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-hyphenate-limit-chars","status":""}, | |
{"gecko":"","webkit":"-webkit-hyphenate-limit-lines","presto":"","trident":"-ms-hyphenate-limit-lines","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-hyphenate-limit-zone","status":""}, | |
{"gecko":"-moz-hyphens","webkit":"-epub-hyphens","presto":"","trident":"-ms-hyphens","status":"WD"}, | |
{"gecko":"-moz-image-region","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"ime-mode","webkit":"","presto":"","trident":"-ms-ime-mode","status":""}, | |
{"gecko":"","webkit":"","presto":"-wap-input-format","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-wap-input-required","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-interpolation-mode","status":""}, | |
{"gecko":"","webkit":"","presto":"-xv-interpret-as","trident":"","status":""}, | |
{"gecko":"justify-content","webkit":"-webkit-justify-content","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-flow","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-char","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-line","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-mode","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-type","status":""}, | |
{"gecko":"","webkit":"-webkit-line-align","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-line-box-contain","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-line-break","presto":"","trident":"line-break","status":""}, | |
{"gecko":"","webkit":"-webkit-line-clamp","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-line-grid","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-line-snap","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-o-link","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-o-link-source","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-locale","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-logical-height","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-logical-width","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-margin-after","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-margin-after-collapse","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-margin-before","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-margin-before-collapse","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-margin-bottom-collapse","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-margin-collapse","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-margin-end","webkit":"-webkit-margin-end","presto":"","trident":"","status":"ED"}, | |
{"gecko":"-moz-margin-start","webkit":"-webkit-margin-start","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-margin-top-collapse","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-marquee","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-wap-marquee-dir","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-marquee-direction","presto":"","trident":"","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-marquee-increment","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-wap-marquee-loop","trident":"","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-marquee-repetition","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-marquee-speed","presto":"-wap-marquee-speed","trident":"","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-marquee-style","presto":"-wap-marquee-style","trident":"","status":"WD"}, | |
{"gecko":"mask","webkit":"-webkit-mask","presto":"mask","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-box-image","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-box-image-outset","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-box-image-repeat","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-box-image-slice","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-box-image-source","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-box-image-width","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-clip","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-composite","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-image","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-origin","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-position","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-position-x","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-position-y","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-repeat","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-repeat-x","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-repeat-y","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-mask-size","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-max-logical-height","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-max-logical-width","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-min-logical-height","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-min-logical-width","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"","presto":"-o-mini-fold","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-nbsp-mode","presto":"","trident":"","status":"P"}, | |
{"gecko":"","webkit":"","presto":"-o-object-fit","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"","presto":"-o-object-position","trident":"","status":"ED"}, | |
{"gecko":"opacity","webkit":"-webkit-opacity","presto":"opacity","trident":"opacity","status":"WD"}, | |
{"gecko":"order","webkit":"-webkit-order","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-orient","webkit":"","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-outline-radius","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-outline-radius-bottomleft","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-outline-radius-bottomright","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-outline-radius-topleft","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-outline-radius-topright","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"","webkit":"-webkit-overflow-scrolling","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-overflow-style","status":"CR"}, | |
{"gecko":"overflow-x","webkit":"overflow-x","presto":"overflow-x","trident":"-ms-overflow-x","status":"WD"}, | |
{"gecko":"overflow-y","webkit":"overflow-y","presto":"overflow-y","trident":"-ms-overflow-y","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-padding-after","presto":"","trident":"","status":"ED"}, | |
{"gecko":"","webkit":"-webkit-padding-before","presto":"","trident":"","status":"ED"}, | |
{"gecko":"-moz-padding-end","webkit":"-webkit-padding-end","presto":"","trident":"","status":"ED"}, | |
{"gecko":"-moz-padding-start","webkit":"-webkit-padding-start","presto":"","trident":"","status":"ED"}, | |
{"gecko":"perspective","webkit":"-webkit-perspective","presto":"","trident":"perspective","status":"WD"}, | |
{"gecko":"perspective-origin","webkit":"-webkit-perspective-origin","presto":"","trident":"perspective-origin","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-perspective-origin-x","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-perspective-origin-y","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-xv-phonemes","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-print-color-adjust","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-progress-appearance","status":""}, | |
{"gecko":"","webkit":"-webkit-region-break-after","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-region-break-before","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-region-break-inside","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-region-fragment","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-rtl-ordering","presto":"","trident":"","status":"P"}, | |
{"gecko":"","webkit":"-webkit-ruby-position","presto":"","trident":"ruby-position","status":"CR"}, | |
{"gecko":"-moz-script-level","webkit":"","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-script-min-size","webkit":"","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-script-size-multiplier","webkit":"","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-chaining","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-limit","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-limit-x-max","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-limit-x-min","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-limit-y-max","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-limit-y-min","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-rails","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-snap-points-x","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-snap-points-y","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-snap-type","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-snap-x","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-snap-y","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-scroll-translation","status":""}, | |
{"gecko":"","webkit":"","presto":"scrollbar-arrow-color","trident":"-ms-scrollbar-arrow-color","status":"P"}, | |
{"gecko":"","webkit":"","presto":"scrollbar-base-color","trident":"-ms-scrollbar-base-color","status":"P"}, | |
{"gecko":"","webkit":"","presto":"scrollbar-darkshadow-color","trident":"-ms-scrollbar-darkshadow-color","status":"P"}, | |
{"gecko":"","webkit":"","presto":"scrollbar-face-color","trident":"-ms-scrollbar-face-color","status":"P"}, | |
{"gecko":"","webkit":"","presto":"scrollbar-highlight-color","trident":"-ms-scrollbar-highlight-color","status":"P"}, | |
{"gecko":"","webkit":"","presto":"scrollbar-shadow-color","trident":"-ms-scrollbar-shadow-color","status":"P"}, | |
{"gecko":"","webkit":"","presto":"scrollbar-track-color","trident":"-ms-scrollbar-track-color","status":"P"}, | |
{"gecko":"","webkit":"-webkit-shape-inside","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-shape-margin","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-shape-outside","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-shape-padding","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-stack-sizing","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"","webkit":"-webkit-svg-shadow","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-tab-size","webkit":"tab-size","presto":"-o-tab-size","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-o-table-baseline","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-tap-highlight-color","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-text-align-last","webkit":"-webkit-text-align-last","presto":"","trident":"-ms-text-align-last","status":"WD"}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-text-autospace","status":"WD"}, | |
{"gecko":"-moz-text-blink","webkit":"","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-epub-text-combine","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-text-decoration-color","webkit":"-webkit-text-decoration-color","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-text-decoration-line","webkit":"-webkit-text-decoration-line","presto":"","trident":"","status":""}, | |
{"gecko":"-moz-text-decoration-style","webkit":"-webkit-text-decoration-style","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-text-decorations-in-effect","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-epub-text-emphasis","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-epub-text-emphasis-color","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-text-emphasis-position","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-epub-text-emphasis-style","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-text-fill-color","presto":"","trident":"","status":"P"}, | |
{"gecko":"","webkit":"-webkit-text-justify","presto":"","trident":"-ms-text-justify","status":"WD"}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-text-kashida-space","status":"P"}, | |
{"gecko":"","webkit":"-epub-text-orientation","presto":"","trident":"","status":""}, | |
{"gecko":"text-overflow","webkit":"text-overflow","presto":"text-overflow","trident":"-ms-text-overflow","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-text-security","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-text-size-adjust","webkit":"","presto":"","trident":"","status":""}, | |
{"gecko":"","webkit":"-webkit-text-stroke","presto":"","trident":"","status":"P"}, | |
{"gecko":"","webkit":"-webkit-text-stroke-color","presto":"","trident":"","status":"P"}, | |
{"gecko":"","webkit":"-webkit-text-stroke-width","presto":"","trident":"","status":"P"}, | |
{"gecko":"text-transform","webkit":"-epub-text-transform","presto":"text-transform","trident":"text-transform","status":""}, | |
{"gecko":"","webkit":"-webkit-text-underline-position","presto":"","trident":"-ms-text-underline-position","status":"P"}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-touch-action","status":""}, | |
{"gecko":"","webkit":"-webkit-touch-callout","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-transform","webkit":"-webkit-transform","presto":"-o-transform","trident":"transform","status":"WD"}, | |
{"gecko":"transform-origin","webkit":"-webkit-transform-origin","presto":"-o-transform-origin","trident":"transform-origin","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-transform-origin-x","presto":"","trident":"","status":"P"}, | |
{"gecko":"","webkit":"-webkit-transform-origin-y","presto":"","trident":"","status":"P"}, | |
{"gecko":"","webkit":"-webkit-transform-origin-z","presto":"","trident":"","status":"P"}, | |
{"gecko":"transform-style","webkit":"-webkit-transform-style","presto":"","trident":"transform-style","status":"WD"}, | |
{"gecko":"transition","webkit":"-webkit-transition","presto":"-o-transition","trident":"transition","status":"WD"}, | |
{"gecko":"transition-delay","webkit":"-webkit-transition-delay","presto":"-o-transition-delay","trident":"transition-delay","status":"WD"}, | |
{"gecko":"transition-duration","webkit":"-webkit-transition-duration","presto":"-o-transition-duration","trident":"transition-duration","status":"WD"}, | |
{"gecko":"transition-property","webkit":"-webkit-transition-property","presto":"-o-transition-property","trident":"transition-property","status":"WD"}, | |
{"gecko":"transition-timing-function","webkit":"-webkit-transition-timing-function","presto":"-o-transition-timing-function","trident":"transition-timing-function","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-user-drag","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-user-focus","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-user-input","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-user-modify","webkit":"-webkit-user-modify","presto":"","trident":"","status":"P"}, | |
{"gecko":"-moz-user-select","webkit":"-webkit-user-select","presto":"","trident":"-ms-user-select","status":"P"}, | |
{"gecko":"","webkit":"","presto":"-xv-voice-balance","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-xv-voice-duration","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-xv-voice-pitch","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-xv-voice-pitch-range","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-xv-voice-rate","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-xv-voice-stress","trident":"","status":""}, | |
{"gecko":"","webkit":"","presto":"-xv-voice-volume","trident":"","status":""}, | |
{"gecko":"-moz-window-shadow","webkit":"","presto":"","trident":"","status":"P"}, | |
{"gecko":"word-break","webkit":"-epub-word-break","presto":"","trident":"-ms-word-break","status":"WD"}, | |
{"gecko":"word-wrap","webkit":"word-wrap","presto":"word-wrap","trident":"-ms-word-wrap","status":"WD"}, | |
{"gecko":"","webkit":"-webkit-wrap-flow","presto":"","trident":"-ms-wrap-flow","status":""}, | |
{"gecko":"","webkit":"","presto":"","trident":"-ms-wrap-margin","status":""}, | |
{"gecko":"","webkit":"-webkit-wrap-through","presto":"","trident":"-ms-wrap-through","status":""}, | |
{"gecko":"writing-mode","webkit":"-epub-writing-mode","presto":"writing-mode","trident":"-ms-writing-mode","status":"ED"}, | |
{"gecko":"","webkit":"zoom","presto":"","trident":"-ms-zoom","status":""}]}; | |
var PrefixHelper = { | |
mVENDOR_PREFIXES: null, | |
kEXPORTS_FOR_GECKO: true, | |
kEXPORTS_FOR_WEBKIT: true, | |
kEXPORTS_FOR_PRESTO: true, | |
kEXPORTS_FOR_TRIDENT: true, | |
cleanPrefixes: function() | |
{ | |
this.mVENDOR_PREFIXES = null; | |
}, | |
prefixesForProperty: function(aProperty) | |
{ | |
if (!this.mVENDOR_PREFIXES) { | |
this.mVENDOR_PREFIXES = {}; | |
for (var i = 0; i < kCSS_VENDOR_PREFIXES.properties.length; i++) { | |
var p = kCSS_VENDOR_PREFIXES.properties[i]; | |
if (p.gecko && (p.webkit || p.presto || p.trident)) { | |
var o = {}; | |
if (this.kEXPORTS_FOR_GECKO) o[p.gecko] = true; | |
if (this.kEXPORTS_FOR_WEBKIT && p.webkit) o[p.webkit] = true; | |
if (this.kEXPORTS_FOR_PRESTO && p.presto) o[p.presto] = true; | |
if (this.kEXPORTS_FOR_TRIDENT && p.trident) o[p.trident] = true; | |
this.mVENDOR_PREFIXES[p.gecko] = []; | |
for (var j in o) | |
this.mVENDOR_PREFIXES[p.gecko].push(j) | |
} | |
} | |
} | |
if (aProperty in this.mVENDOR_PREFIXES) | |
return this.mVENDOR_PREFIXES[aProperty].sort(); | |
return null; | |
} | |
}; | |
function ParseURL(buffer) { | |
var result = { }; | |
result.protocol = ""; | |
result.user = ""; | |
result.password = ""; | |
result.host = ""; | |
result.port = ""; | |
result.path = ""; | |
result.query = ""; | |
var section = "PROTOCOL"; | |
var start = 0; | |
var wasSlash = false; | |
while(start < buffer.length) { | |
if(section == "PROTOCOL") { | |
if(buffer.charAt(start) == ':') { | |
section = "AFTER_PROTOCOL"; | |
start++; | |
} else if(buffer.charAt(start) == '/' && result.protocol.length() == 0) { | |
section = PATH; | |
} else { | |
result.protocol += buffer.charAt(start++); | |
} | |
} else if(section == "AFTER_PROTOCOL") { | |
if(buffer.charAt(start) == '/') { | |
if(!wasSlash) { | |
wasSlash = true; | |
} else { | |
wasSlash = false; | |
section = "USER"; | |
} | |
start ++; | |
} else { | |
throw new ParseException("Protocol shell be separated with 2 slashes"); | |
} | |
} else if(section == "USER") { | |
if(buffer.charAt(start) == '/') { | |
result.host = result.user; | |
result.user = ""; | |
section = "PATH"; | |
} else if(buffer.charAt(start) == '?') { | |
result.host = result.user; | |
result.user = ""; | |
section = "QUERY"; | |
start++; | |
} else if(buffer.charAt(start) == ':') { | |
section = "PASSWORD"; | |
start++; | |
} else if(buffer.charAt(start) == '@') { | |
section = "HOST"; | |
start++; | |
} else { | |
result.user += buffer.charAt(start++); | |
} | |
} else if(section == "PASSWORD") { | |
if(buffer.charAt(start) == '/') { | |
result.host = result.user; | |
result.port = result.password; | |
result.user = ""; | |
result.password = ""; | |
section = "PATH"; | |
} else if(buffer.charAt(start) == '?') { | |
result.host = result.user; | |
result.port = result.password; | |
result.user = ""; | |
result.password = ""; | |
section = "QUERY"; | |
start ++; | |
} else if(buffer.charAt(start) == '@') { | |
section = "HOST"; | |
start++; | |
} else { | |
result.password += buffer.charAt(start++); | |
} | |
} else if(section == "HOST") { | |
if(buffer.charAt(start) == '/') { | |
section = "PATH"; | |
} else if(buffer.charAt(start) == ':') { | |
section = "PORT"; | |
start++; | |
} else if(buffer.charAt(start) == '?') { | |
section = "QUERY"; | |
start++; | |
} else { | |
result.host += buffer.charAt(start++); | |
} | |
} else if(section == "PORT") { | |
if(buffer.charAt(start) == '/') { | |
section = "PATH"; | |
} else if(buffer.charAt(start) == '?') { | |
section = "QUERY"; | |
start++; | |
} else { | |
result.port += buffer.charAt(start++); | |
} | |
} else if(section == "PATH") { | |
if(buffer.charAt(start) == '?') { | |
section = "QUERY"; | |
start ++; | |
} else { | |
result.path += buffer.charAt(start++); | |
} | |
} else if(section == "QUERY") { | |
result.query += buffer.charAt(start++); | |
} | |
} | |
if(section == "PROTOCOL") { | |
result.host = result.protocol; | |
result.protocol = "http"; | |
} else if(section == "AFTER_PROTOCOL") { | |
throw new ParseException("Invalid url"); | |
} else if(section == "USER") { | |
result.host = result.user; | |
result.user = ""; | |
} else if(section == "PASSWORD") { | |
result.host = result.user; | |
result.port = result.password; | |
result.user = ""; | |
result.password = ""; | |
} | |
return result; | |
} | |
function ParseException(description) { | |
this.description = description; | |
} | |
function CountLF(s) | |
{ | |
var nCR = s.match( /\n/g ); | |
return nCR ? nCR.length + 1 : 1; | |
} | |
function DisposablePartialParsing(aStringToParse, aMethodName) | |
{ | |
var parser = new CSSParser(); | |
parser._init(); | |
parser.mPreserveWS = false; | |
parser.mPreserveComments = false; | |
parser.mPreservedTokens = []; | |
parser.mScanner.init(aStringToParse); | |
return parser[aMethodName](); | |
} | |
function FilterLinearGradient(aValue, aEngine) | |
{ | |
var d = DisposablePartialParsing(aValue, "parseBackgroundImages"); | |
if (!d) | |
return null; | |
var g = d[0]; | |
if (!g.value) | |
return null; | |
var str = ""; | |
var position = ("position" in g.value) ? g.value.position.toLowerCase() : ""; | |
var angle = ("angle" in g.value) ? g.value.angle.toLowerCase() : ""; | |
if ("webkit20110101" == aEngine) { | |
var cancelled = false; | |
str = "-webkit-gradient(linear, "; | |
// normalize angle | |
if (angle) { | |
var match = angle.match(/^([0-9\-\.\\+]+)([a-z]*)/); | |
var angle = parseFloat(match[1]); | |
var unit = match[2]; | |
switch (unit) { | |
case "grad": angle = angle * 90 / 100; break; | |
case "rad": angle = angle * 180 / Math.PI; break; | |
default: break; | |
} | |
while (angle < 0) | |
angle += 360; | |
while (angle >= 360) | |
angle -= 360; | |
} | |
// get startpoint w/o keywords | |
var startpoint = []; | |
var endpoint = []; | |
if (position != "") { | |
if (position == "center") | |
position = "center center"; | |
startpoint = position.split(" "); | |
if (angle == "" && angle != 0) { | |
// no angle, then we just turn the point 180 degrees around center | |
switch (startpoint[0]) { | |
case "left": endpoint.push("right"); break; | |
case "center": endpoint.push("center"); break; | |
case "right": endpoint.push("left"); break; | |
default: { | |
var match = startpoint[0].match(/^([0-9\-\.\\+]+)([a-z]*)/); | |
var v = parseFloat(match[0]); | |
var unit = match[1]; | |
if (unit == "%") { | |
endpoint.push((100-v) + "%"); | |
} | |
else | |
cancelled = true; | |
} | |
break; | |
} | |
if (!cancelled) | |
switch (startpoint[1]) { | |
case "top": endpoint.push("bottom"); break; | |
case "center": endpoint.push("center"); break; | |
case "bottom": endpoint.push("top"); break; | |
default: { | |
var match = startpoint[1].match(/^([0-9\-\.\\+]+)([a-z]*)/); | |
var v = parseFloat(match[0]); | |
var unit = match[1]; | |
if (unit == "%") { | |
endpoint.push((100-v) + "%"); | |
} | |
else | |
cancelled = true; | |
} | |
break; | |
} | |
} | |
else { | |
switch (angle) { | |
case 0: endpoint.push("right"); endpoint.push(startpoint[1]); break; | |
case 90: endpoint.push(startpoint[0]); endpoint.push("top"); break; | |
case 180: endpoint.push("left"); endpoint.push(startpoint[1]); break; | |
case 270: endpoint.push(startpoint[0]); endpoint.push("bottom"); break; | |
default: cancelled = true; break; | |
} | |
} | |
} | |
else { | |
// no position defined, we accept only vertical and horizontal | |
if (angle == "") | |
angle = 270; | |
switch (angle) { | |
case 0: startpoint= ["left", "center"]; endpoint = ["right", "center"]; break; | |
case 90: startpoint= ["center", "bottom"]; endpoint = ["center", "top"]; break; | |
case 180: startpoint= ["right", "center"]; endpoint = ["left", "center"]; break; | |
case 270: startpoint= ["center", "top"]; endpoint = ["center", "bottom"]; break; | |
default: cancelled = true; break; | |
} | |
} | |
if (cancelled) | |
return ""; | |
str += startpoint.join(" ") + ", " + endpoint.join(" "); | |
if (!g.value.stops[0].position) | |
g.value.stops[0].position = "0%"; | |
if (!g.value.stops[g.value.stops.length-1].position) | |
g.value.stops[g.value.stops.length-1].position = "100%"; | |
var current = 0; | |
for (var i = 0; i < g.value.stops.length && !cancelled; i++) { | |
var s = g.value.stops[i]; | |
if (s.position) { | |
if (s.position.indexOf("%") == -1) { | |
cancelled = true; | |
break; | |
} | |
} | |
else { | |
var j = i + 1; | |
while (j < g.value.stops.length && !g.value.stops[j].position) | |
j++; | |
var inc = parseFloat(g.value.stops[j].position) - current; | |
for (var k = i; k < j; k++) { | |
g.value.stops[k].position = (current + inc * (k - i + 1) / (j - i + 1)) + "%"; | |
} | |
} | |
current = parseFloat(s.position); | |
str += ", color-stop(" + (parseFloat(current) / 100) + ", " + s.color + ")"; | |
} | |
if (cancelled) | |
return ""; | |
} | |
else { | |
str = (g.value.isRepeating ? "repeating-" : "") + "linear-gradient("; | |
if (angle || position) | |
str += (angle ? angle : position) + ", "; | |
for (var i = 0; i < g.value.stops.length; i++) { | |
var s = g.value.stops[i]; | |
str += s.color | |
+ (s.position ? " " + s.position : "") | |
+ ((i != g.value.stops.length -1) ? ", " : ""); | |
} | |
} | |
str += ")"; | |
switch (aEngine) { | |
case "webkit": str = "-webkit-" + str; break; | |
case "gecko1.9.2": str = "-moz-" + str; break; | |
case "presto": str = "-o-" + str; break; | |
case "trident": str = "-ms-" + str; break; | |
default: break; | |
} | |
return str; | |
} | |
function FilterRadialGradient(aValue, aEngine) | |
{ | |
var d = DisposablePartialParsing(aValue, "parseBackgroundImages"); | |
if (!d) | |
return null; | |
var g = d[0]; | |
if (!g.value) | |
return null; | |
// oh come on, this is now so painful to deal with ; no way I'm going to implement this | |
if ("webkit20110101" == aEngine) | |
return null; | |
var str = (g.value.isRepeating ? "repeating-" : "") + "radial-gradient("; | |
var shape = ("shape" in g.value) ? g.value.shape : ""; | |
var extent = ("extent" in g.value) ? g.value.extent : ""; | |
var lengths = ""; | |
switch (g.value.positions.length) { | |
case 1: | |
lengths = g.value.positions[0] + " " + g.value.positions[0]; | |
break; | |
case 2: | |
lengths = g.value.positions[0] + " " + g.value.positions[1]; | |
break; | |
default: | |
break; | |
} | |
var at = g.value.at; | |
str += (at ? at + ", " : "") | |
+ ((shape || extent || at) | |
? (shape ? shape + " " : "") | |
+ (extent ? extent + " " : "") | |
+ (lengths ? lengths + " " : "") | |
+ ", " | |
: ""); | |
for (var i = 0; i < g.value.stops.length; i++) { | |
var s = g.value.stops[i]; | |
str += s.color | |
+ (s.position ? " " + s.position : "") | |
+ ((i != g.value.stops.length -1) ? ", " : ""); | |
} | |
str += ")"; | |
switch (aEngine) { | |
case "webkit": str = "-webkit-" + str; break; | |
case "gecko1.9.2": str = "-moz-" + str; break; | |
case "presto": str = "-o-" + str; break; | |
case "trident": str = "-ms-" + str; break; | |
default: break; | |
} | |
return str; | |
} | |
var CSS_ESCAPE = '\\'; | |
var IS_HEX_DIGIT = 1; | |
var START_IDENT = 2; | |
var IS_IDENT = 4; | |
var IS_WHITESPACE = 8; | |
var W = IS_WHITESPACE; | |
var I = IS_IDENT; | |
var S = START_IDENT; | |
var SI = IS_IDENT|START_IDENT; | |
var XI = IS_IDENT |IS_HEX_DIGIT; | |
var XSI = IS_IDENT|START_IDENT|IS_HEX_DIGIT; | |
function CSSScanner(aString) | |
{ | |
this.init(aString); | |
} | |
CSSScanner.prototype = { | |
kLexTable: [ | |
// TAB LF FF CR | |
0, 0, 0, 0, 0, 0, 0, 0, 0, W, W, 0, W, W, 0, 0, | |
// | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
// SPC ! " # $ % & ' ( ) * + , - . / | |
W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, I, 0, 0, | |
// 0 1 2 3 4 5 6 7 8 9 : ; < = > ? | |
XI, XI, XI, XI, XI, XI, XI, XI, XI, XI, 0, 0, 0, 0, 0, 0, | |
// @ A B C D E F G H I J K L M N O | |
0, XSI,XSI,XSI,XSI,XSI,XSI,SI, SI, SI, SI, SI, SI, SI, SI, SI, | |
// P Q R S T U V W X Y Z [ \ ] ^ _ | |
SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, 0, S, 0, 0, SI, | |
// ` a b c d e f g h i j k l m n o | |
0, XSI,XSI,XSI,XSI,XSI,XSI,SI, SI, SI, SI, SI, SI, SI, SI, SI, | |
// p q r s t u v w x y z { | } ~ | |
SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, 0, 0, 0, 0, 0, | |
// | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
// | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
// ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬  ® ¯ | |
0, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, | |
// ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ | |
SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, | |
// À à Â Ã Ä Å Æ Ç È É Ê Ë Ì à Î à | |
SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, | |
// à Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü à Þ ß | |
SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, | |
// à á â ã ä å æ ç è é ê ë ì à î ï | |
SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, | |
// ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ | |
SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI | |
], | |
kHexValues: { | |
"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, | |
"a": 10, "b": 11, "c": 12, "d": 13, "e": 14, "f": 15 | |
}, | |
mString : "", | |
mPos : 0, | |
mPreservedPos : [], | |
init: function(aString) { | |
this.mString = aString; | |
this.mPos = 0; | |
this.mPreservedPos = []; | |
}, | |
getCurrentPos: function() { | |
return this.mPos; | |
}, | |
getAlreadyScanned: function() | |
{ | |
return this.mString.substr(0, this.mPos); | |
}, | |
preserveState: function() { | |
this.mPreservedPos.push(this.mPos); | |
}, | |
restoreState: function() { | |
if (this.mPreservedPos.length) { | |
this.mPos = this.mPreservedPos.pop(); | |
} | |
}, | |
forgetState: function() { | |
if (this.mPreservedPos.length) { | |
this.mPreservedPos.pop(); | |
} | |
}, | |
read: function() { | |
if (this.mPos < this.mString.length) | |
return this.mString.charAt(this.mPos++); | |
return -1; | |
}, | |
peek: function() { | |
if (this.mPos < this.mString.length) | |
return this.mString.charAt(this.mPos); | |
return -1; | |
}, | |
isHexDigit: function(c) { | |
var code = c.charCodeAt(0); | |
return (code < 256 && (this.kLexTable[code] & IS_HEX_DIGIT) != 0); | |
}, | |
isIdentStart: function(c) { | |
var code = c.charCodeAt(0); | |
return (code >= 256 || (this.kLexTable[code] & START_IDENT) != 0); | |
}, | |
startsWithIdent: function(aFirstChar, aSecondChar) { | |
var code = aFirstChar.charCodeAt(0); | |
return this.isIdentStart(aFirstChar) || | |
(aFirstChar == "-" && this.isIdentStart(aSecondChar)); | |
}, | |
isIdent: function(c) { | |
var code = c.charCodeAt(0); | |
return (code >= 256 || (this.kLexTable[code] & IS_IDENT) != 0); | |
}, | |
pushback: function() { | |
this.mPos--; | |
}, | |
nextHexValue: function() { | |
var c = this.read(); | |
if (c == -1 || !this.isHexDigit(c)) | |
return new jscsspToken(jscsspToken.NULL_TYPE, null); | |
var s = c; | |
c = this.read(); | |
while (c != -1 && this.isHexDigit(c)) { | |
s += c; | |
c = this.read(); | |
} | |
if (c != -1) | |
this.pushback(); | |
return new jscsspToken(jscsspToken.HEX_TYPE, s); | |
}, | |
gatherEscape: function() { | |
var c = this.peek(); | |
if (c == -1) | |
return ""; | |
if (this.isHexDigit(c)) { | |
var code = 0; | |
for (var i = 0; i < 6; i++) { | |
c = this.read(); | |
if (this.isHexDigit(c)) | |
code = code * 16 + this.kHexValues[c.toLowerCase()]; | |
else if (!this.isHexDigit(c) && !this.isWhiteSpace(c)) { | |
this.pushback(); | |
break; | |
} | |
else | |
break; | |
} | |
if (i == 6) { | |
c = this.peek(); | |
if (this.isWhiteSpace(c)) | |
this.read(); | |
} | |
return String.fromCharCode(code); | |
} | |
c = this.read(); | |
if (c != "\n") | |
return c; | |
return ""; | |
}, | |
gatherIdent: function(c) { | |
var s = ""; | |
if (c == CSS_ESCAPE) | |
s += this.gatherEscape(); | |
else | |
s += c; | |
c = this.read(); | |
while (c != -1 | |
&& (this.isIdent(c) || c == CSS_ESCAPE)) { | |
if (c == CSS_ESCAPE) | |
s += this.gatherEscape(); | |
else | |
s += c; | |
c = this.read(); | |
} | |
if (c != -1) | |
this.pushback(); | |
return s; | |
}, | |
parseIdent: function(c) { | |
var value = this.gatherIdent(c); | |
var nextChar = this.peek(); | |
if (nextChar == "(") { | |
value += this.read(); | |
return new jscsspToken(jscsspToken.FUNCTION_TYPE, value); | |
} | |
return new jscsspToken(jscsspToken.IDENT_TYPE, value); | |
}, | |
isDigit: function(c) { | |
return (c >= '0') && (c <= '9'); | |
}, | |
parseComment: function(c) { | |
var s = c; | |
while ((c = this.read()) != -1) { | |
s += c; | |
if (c == "*") { | |
c = this.read(); | |
if (c == -1) | |
break; | |
if (c == "/") { | |
s += c; | |
break; | |
} | |
this.pushback(); | |
} | |
} | |
return new jscsspToken(jscsspToken.COMMENT_TYPE, s); | |
}, | |
parseNumber: function(c) { | |
var s = c; | |
var foundDot = false; | |
while ((c = this.read()) != -1) { | |
if (c == ".") { | |
if (foundDot) | |
break; | |
else { | |
s += c; | |
foundDot = true; | |
} | |
} else if (this.isDigit(c)) | |
s += c; | |
else | |
break; | |
} | |
if (c != -1 && this.startsWithIdent(c, this.peek())) { // DIMENSION | |
var unit = this.gatherIdent(c); | |
s += unit; | |
return new jscsspToken(jscsspToken.DIMENSION_TYPE, s, unit); | |
} | |
else if (c == "%") { | |
s += "%"; | |
return new jscsspToken(jscsspToken.PERCENTAGE_TYPE, s); | |
} | |
else if (c != -1) | |
this.pushback(); | |
return new jscsspToken(jscsspToken.NUMBER_TYPE, s); | |
}, | |
parseString: function(aStop) { | |
var s = aStop; | |
var previousChar = aStop; | |
var c; | |
while ((c = this.read()) != -1) { | |
if (c == aStop && previousChar != CSS_ESCAPE) { | |
s += c; | |
break; | |
} | |
else if (c == CSS_ESCAPE) { | |
c = this.peek(); | |
if (c == -1) | |
break; | |
else if (c == "\n" || c == "\r" || c == "\f") { | |
d = c; | |
c = this.read(); | |
// special for Opera that preserves \r\n... | |
if (d == "\r") { | |
c = this.peek(); | |
if (c == "\n") | |
c = this.read(); | |
} | |
} | |
else { | |
s += this.gatherEscape(); | |
c = this.peek(); | |
} | |
} | |
else if (c == "\n" || c == "\r" || c == "\f") { | |
break; | |
} | |
else | |
s += c; | |
previousChar = c; | |
} | |
return new jscsspToken(jscsspToken.STRING_TYPE, s); | |
}, | |
isWhiteSpace: function(c) { | |
var code = c.charCodeAt(0); | |
return code < 256 && (this.kLexTable[code] & IS_WHITESPACE) != 0; | |
}, | |
eatWhiteSpace: function(c) { | |
var s = c; | |
while ((c = this.read()) != -1) { | |
if (!this.isWhiteSpace(c)) | |
break; | |
s += c; | |
} | |
if (c != -1) | |
this.pushback(); | |
return s; | |
}, | |
parseAtKeyword: function(c) { | |
return new jscsspToken(jscsspToken.ATRULE_TYPE, this.gatherIdent(c)); | |
}, | |
nextToken: function() { | |
var c = this.read(); | |
if (c == -1) | |
return new jscsspToken(jscsspToken.NULL_TYPE, null); | |
if (this.startsWithIdent(c, this.peek())) | |
return this.parseIdent(c); | |
if (c == '@') { | |
var nextChar = this.read(); | |
if (nextChar != -1) { | |
var followingChar = this.peek(); | |
this.pushback(); | |
if (this.startsWithIdent(nextChar, followingChar)) | |
return this.parseAtKeyword(c); | |
} | |
} | |
if (c == "." || c == "+" || c == "-") { | |
var nextChar = this.peek(); | |
if (this.isDigit(nextChar)) | |
return this.parseNumber(c); | |
else if (nextChar == "." && c != ".") { | |
firstChar = this.read(); | |
var secondChar = this.peek(); | |
this.pushback(); | |
if (this.isDigit(secondChar)) | |
return this.parseNumber(c); | |
} | |
} | |
if (this.isDigit(c)) { | |
return this.parseNumber(c); | |
} | |
if (c == "'" || c == '"') | |
return this.parseString(c); | |
if (this.isWhiteSpace(c)) { | |
var s = this.eatWhiteSpace(c); | |
return new jscsspToken(jscsspToken.WHITESPACE_TYPE, s); | |
} | |
if (c == "|" || c == "~" || c == "^" || c == "$" || c == "*") { | |
var nextChar = this.read(); | |
if (nextChar == "=") { | |
switch (c) { | |
case "~" : | |
return new jscsspToken(jscsspToken.INCLUDES_TYPE, "~="); | |
case "|" : | |
return new jscsspToken(jscsspToken.DASHMATCH_TYPE, "|="); | |
case "^" : | |
return new jscsspToken(jscsspToken.BEGINSMATCH_TYPE, "^="); | |
case "$" : | |
return new jscsspToken(jscsspToken.ENDSMATCH_TYPE, "$="); | |
case "*" : | |
return new jscsspToken(jscsspToken.CONTAINSMATCH_TYPE, "*="); | |
default : | |
break; | |
} | |
} else if (nextChar != -1) | |
this.pushback(); | |
} | |
if (c == "/" && this.peek() == "*") | |
return this.parseComment(c); | |
return new jscsspToken(jscsspToken.SYMBOL_TYPE, c); | |
} | |
}; | |
CSSParser.prototype.parseBackgroundImages = function() | |
{ | |
var backgrounds = []; | |
var token = this.getToken(true, true); | |
while (token.isNotNull()) { | |
if (token.isFunction("url(")) { | |
token = this.getToken(true, true); | |
var urlContent = this.parseURL(token); | |
backgrounds.push( { type: "image", value: "url(" + urlContent }); | |
token = this.getToken(true, true); | |
} | |
else if (token.isFunction("linear-gradient(") | |
|| token.isFunction("radial-gradient(") | |
|| token.isFunction("repeating-linear-gradient(") | |
|| token.isFunction("repeating-radial-gradient(")) { | |
this.ungetToken(); | |
var gradient = this.parseGradient(); | |
if (gradient) { | |
backgrounds.push({ | |
type: gradient.isRadial ? "radial-gradient" : "linear-gradient", | |
value: gradient | |
}); | |
token = this.getToken(true, true); | |
} | |
else | |
return null; | |
} | |
else if (token.isIdent("none") | |
|| token.isIdent("inherit") | |
|| token.isIdent("initial")) { | |
backgrounds.push( { type: token.value }); | |
token = this.getToken(true, true); | |
} | |
else | |
return null; | |
if (token.isSymbol(",")) { | |
token = this.getToken(true, true); | |
if (!token.isNotNull()) | |
return null; | |
} | |
} | |
return backgrounds; | |
}; | |
CSSParser.prototype.parseBackgroundShorthand = function(token, aDecl, aAcceptPriority) | |
{ | |
var kHPos = { | |
"left" : true, | |
"right" : true | |
}; | |
var kVPos = { | |
"top" : true, | |
"bottom" : true | |
}; | |
var kPos = { | |
"left" : true, | |
"right" : true, | |
"top" : true, | |
"bottom" : true, | |
"center" : true | |
}; | |
var bgColor = null; | |
var bgRepeat = null; | |
var bgAttachment = null; | |
var bgImage = null; | |
var bgPosition = null; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
if (token.isSymbol(";") | |
|| (aAcceptPriority && token.isSymbol("!")) | |
|| token.isSymbol("}")) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} | |
else if (!bgColor | |
&& !bgRepeat | |
&& !bgAttachment | |
&& !bgImage | |
&& !bgPosition | |
&& token.isIdent(this.kINHERIT)) { | |
bgColor = this.kINHERIT; | |
bgRepeat = this.kINHERIT; | |
bgAttachment = this.kINHERIT; | |
bgImage = this.kINHERIT; | |
bgPosition = this.kINHERIT; | |
} | |
else { | |
if (!bgAttachment | |
&& (token.isIdent("scroll") || token.isIdent("fixed"))) { | |
bgAttachment = token.value; | |
} | |
else if (!bgPosition | |
&& ((token.isIdent() && token.value in kPos) | |
|| token.isDimension() | |
|| token.isNumber("0") | |
|| token.isPercentage())) { | |
bgPosition = token.value; | |
token = this.getToken(true, true); | |
if (token.isDimension() | |
|| token.isNumber("0") | |
|| token.isPercentage()) { | |
bgPosition += " " + token.value; | |
} else if (token.isIdent() && token.value in kPos) { | |
if ((bgPosition in kHPos && token.value in kHPos) | |
|| (bgPosition in kVPos && token.value in kVPos)) | |
return ""; | |
bgPosition += " " + token.value; | |
} else { | |
this.ungetToken(); | |
bgPosition += " center"; | |
} | |
} | |
else if (!bgRepeat | |
&& (token.isIdent("repeat") | |
|| token.isIdent("repeat-x") | |
|| token.isIdent("repeat-y") | |
|| token.isIdent("no-repeat"))) { | |
bgRepeat = token.value; | |
} | |
else if (!bgImage | |
&& (token.isFunction("url(") || token.isIdent("none"))) { | |
bgImage = token.value; | |
if (token.isFunction("url(")) { | |
token = this.getToken(true, true); | |
var url = this.parseURL(token); // TODO | |
if (url) | |
bgImage += url; | |
else | |
return ""; | |
} | |
} | |
else if (!bgImage | |
&& (token.isFunction("linear-gradient(") | |
|| token.isFunction("radial-gradient(") | |
|| token.isFunction("repeating-linear-gradient(") || token.isFunction("repeating-radial-gradient("))) { | |
this.ungetToken(); | |
var gradient = this.parseGradient(); | |
if (gradient) | |
bgImage = this.serializeGradient(gradient); | |
else | |
return ""; | |
} | |
else { | |
var color = this.parseColor(token); | |
if (!bgColor && color) | |
bgColor = color; | |
else | |
return ""; | |
} | |
} | |
token = this.getToken(true, true); | |
} | |
// create the declarations | |
this.forgetState(); | |
bgColor = bgColor ? bgColor : "transparent"; | |
bgImage = bgImage ? bgImage : "none"; | |
bgRepeat = bgRepeat ? bgRepeat : "repeat"; | |
bgAttachment = bgAttachment ? bgAttachment : "scroll"; | |
bgPosition = bgPosition ? bgPosition : "top left"; | |
aDecl.push(this._createJscsspDeclarationFromValue("background-color", bgColor)); | |
aDecl.push(this._createJscsspDeclarationFromValue("background-image", bgImage)); | |
aDecl.push(this._createJscsspDeclarationFromValue("background-repeat", bgRepeat)); | |
aDecl.push(this._createJscsspDeclarationFromValue("background-attachment", bgAttachment)); | |
aDecl.push(this._createJscsspDeclarationFromValue("background-position", bgPosition)); | |
return bgColor + " " + bgImage + " " + bgRepeat + " " + bgAttachment + " " + bgPosition; | |
}; | |
CSSParser.prototype.parseBorderColorShorthand = function(token, aDecl, aAcceptPriority) | |
{ | |
var top = null; | |
var bottom = null; | |
var left = null; | |
var right = null; | |
var values = []; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
if (token.isSymbol(";") | |
|| (aAcceptPriority && token.isSymbol("!")) | |
|| token.isSymbol("}")) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} | |
else if (!values.length && token.isIdent(this.kINHERIT)) { | |
values.push(token.value); | |
token = this.getToken(true, true); | |
break; | |
} | |
else { | |
var color = this.parseColor(token); | |
if (color) | |
values.push(color); | |
else | |
return ""; | |
} | |
token = this.getToken(true, true); | |
} | |
var count = values.length; | |
switch (count) { | |
case 1: | |
top = values[0]; | |
bottom = top; | |
left = top; | |
right = top; | |
break; | |
case 2: | |
top = values[0]; | |
bottom = top; | |
left = values[1]; | |
right = left; | |
break; | |
case 3: | |
top = values[0]; | |
left = values[1]; | |
right = left; | |
bottom = values[2]; | |
break; | |
case 4: | |
top = values[0]; | |
right = values[1]; | |
bottom = values[2]; | |
left = values[3]; | |
break; | |
default: | |
return ""; | |
} | |
this.forgetState(); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-top-color", top)); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-right-color", right)); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-color", bottom)); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-left-color", left)); | |
return top + " " + right + " " + bottom + " " + left; | |
}; | |
CSSParser.prototype.parseBorderEdgeOrOutlineShorthand = function(token, aDecl, aAcceptPriority, aProperty) | |
{ | |
var bWidth = null; | |
var bStyle = null; | |
var bColor = null; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
if (token.isSymbol(";") | |
|| (aAcceptPriority && token.isSymbol("!")) | |
|| token.isSymbol("}")) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} | |
else if (!bWidth | |
&& !bStyle | |
&& !bColor | |
&& token.isIdent(this.kINHERIT)) { | |
bWidth = this.kINHERIT; | |
bStyle = this.kINHERIT; | |
bColor = this.kINHERIT; | |
} | |
else if (!bWidth && | |
(token.isDimension() | |
|| (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES) | |
|| token.isNumber("0"))) { | |
bWidth = token.value; | |
} | |
else if (!bStyle && | |
(token.isIdent() && token.value in this.kBORDER_STYLE_NAMES)) { | |
bStyle = token.value; | |
} | |
else { | |
var color = (aProperty == "outline" && token.isIdent("invert")) | |
? "invert" : this.parseColor(token); | |
if (!bColor && color) | |
bColor = color; | |
else | |
return ""; | |
} | |
token = this.getToken(true, true); | |
} | |
// create the declarations | |
this.forgetState(); | |
bWidth = bWidth ? bWidth : "medium"; | |
bStyle = bStyle ? bStyle : "none"; | |
bColor = bColor ? bColor : "-moz-initial"; | |
function addPropertyToDecl(aSelf, aDecl, property, w, s, c) { | |
aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-width", w)); | |
aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-style", s)); | |
aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-color", c)); | |
} | |
if (aProperty == "border") { | |
addPropertyToDecl(this, aDecl, "border-top", bWidth, bStyle, bColor); | |
addPropertyToDecl(this, aDecl, "border-right", bWidth, bStyle, bColor); | |
addPropertyToDecl(this, aDecl, "border-bottom", bWidth, bStyle, bColor); | |
addPropertyToDecl(this, aDecl, "border-left", bWidth, bStyle, bColor); | |
} | |
else | |
addPropertyToDecl(this, aDecl, aProperty, bWidth, bStyle, bColor); | |
return bWidth + " " + bStyle + " " + bColor; | |
}; | |
CSSParser.prototype.parseBorderImage = function() | |
{ | |
var borderImage = {url: "", offsets: [], widths: [], sizes: []}; | |
var token = this.getToken(true, true); | |
if (token.isFunction("url(")) { | |
token = this.getToken(true, true); | |
var urlContent = this.parseURL(token); | |
if (urlContent) { | |
borderImage.url = urlContent.substr(0, urlContent.length - 1).trim(); | |
if ((borderImage.url[0] == '"' && borderImage.url[borderImage.url.length - 1] == '"') | |
|| (borderImage.url[0] == "'" && borderImage.url[borderImage.url.length - 1] == "'")) | |
borderImage.url = borderImage.url.substr(1, borderImage.url.length - 2); | |
} | |
else | |
return null; | |
} | |
else | |
return null; | |
token = this.getToken(true, true); | |
if (token.isNumber() | |
|| token.isPercentage()) | |
borderImage.offsets.push(token.value); | |
else | |
return null; | |
var i; | |
for (i= 0; i < 3; i++) { | |
token = this.getToken(true, true); | |
if (token.isNumber() | |
|| token.isPercentage()) | |
borderImage.offsets.push(token.value); | |
else | |
break; | |
} | |
if (i == 3) | |
token = this.getToken(true, true); | |
if (token.isSymbol("/")) { | |
token = this.getToken(true, true); | |
if (token.isDimension() | |
|| token.isNumber("0") | |
|| (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES)) | |
borderImage.widths.push(token.value); | |
else | |
return null; | |
for (var i = 0; i < 3; i++) { | |
token = this.getToken(true, true); | |
if (token.isDimension() | |
|| token.isNumber("0") | |
|| (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES)) | |
borderImage.widths.push(token.value); | |
else | |
break; | |
} | |
if (i == 3) | |
token = this.getToken(true, true); | |
} | |
for (var i = 0; i < 2; i++) { | |
if (token.isIdent("stretch") | |
|| token.isIdent("repeat") | |
|| token.isIdent("round")) | |
borderImage.sizes.push(token.value); | |
else if (!token.isNotNull()) | |
return borderImage; | |
else | |
return null; | |
token = this.getToken(true, true); | |
} | |
if (!token.isNotNull()) | |
return borderImage; | |
return null; | |
}; | |
CSSParser.prototype.parseBorderStyleShorthand = function(token, aDecl, aAcceptPriority) | |
{ | |
var top = null; | |
var bottom = null; | |
var left = null; | |
var right = null; | |
var values = []; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
if (token.isSymbol(";") | |
|| (aAcceptPriority && token.isSymbol("!")) | |
|| token.isSymbol("}")) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} | |
else if (!values.length && token.isIdent(this.kINHERIT)) { | |
values.push(token.value); | |
} | |
else if (token.isIdent() && token.value in this.kBORDER_STYLE_NAMES) { | |
values.push(token.value); | |
} | |
else | |
return ""; | |
token = this.getToken(true, true); | |
} | |
var count = values.length; | |
switch (count) { | |
case 1: | |
top = values[0]; | |
bottom = top; | |
left = top; | |
right = top; | |
break; | |
case 2: | |
top = values[0]; | |
bottom = top; | |
left = values[1]; | |
right = left; | |
break; | |
case 3: | |
top = values[0]; | |
left = values[1]; | |
right = left; | |
bottom = values[2]; | |
break; | |
case 4: | |
top = values[0]; | |
right = values[1]; | |
bottom = values[2]; | |
left = values[3]; | |
break; | |
default: | |
return ""; | |
} | |
this.forgetState(); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-top-style", top)); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-right-style", right)); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-style", bottom)); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-left-style", left)); | |
return top + " " + right + " " + bottom + " " + left; | |
}; | |
CSSParser.prototype.parseBorderWidthShorthand = function(token, aDecl, aAcceptPriority) | |
{ | |
var top = null; | |
var bottom = null; | |
var left = null; | |
var right = null; | |
var values = []; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
if (token.isSymbol(";") | |
|| (aAcceptPriority && token.isSymbol("!")) | |
|| token.isSymbol("}")) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} | |
else if (!values.length && token.isIdent(this.kINHERIT)) { | |
values.push(token.value); | |
} | |
else if (token.isDimension() | |
|| token.isNumber("0") | |
|| (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES)) { | |
values.push(token.value); | |
} | |
else | |
return ""; | |
token = this.getToken(true, true); | |
} | |
var count = values.length; | |
switch (count) { | |
case 1: | |
top = values[0]; | |
bottom = top; | |
left = top; | |
right = top; | |
break; | |
case 2: | |
top = values[0]; | |
bottom = top; | |
left = values[1]; | |
right = left; | |
break; | |
case 3: | |
top = values[0]; | |
left = values[1]; | |
right = left; | |
bottom = values[2]; | |
break; | |
case 4: | |
top = values[0]; | |
right = values[1]; | |
bottom = values[2]; | |
left = values[3]; | |
break; | |
default: | |
return ""; | |
} | |
this.forgetState(); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-top-width", top)); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-right-width", right)); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-width", bottom)); | |
aDecl.push(this._createJscsspDeclarationFromValue("border-left-width", left)); | |
return top + " " + right + " " + bottom + " " + left; | |
}; | |
CSSParser.prototype.parseBoxShadows = function() | |
{ | |
var shadows = []; | |
var token = this.getToken(true, true); | |
var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px", spreadRadius = "0px"; | |
var inset = false; | |
while (token.isNotNull()) { | |
if (token.isIdent("none")) { | |
shadows.push( { none: true } ); | |
token = this.getToken(true, true); | |
} | |
else { | |
if (token.isIdent('inset')) { | |
inset = true; | |
token = this.getToken(true, true); | |
} | |
if (token.isPercentage() || | |
token.isDimensionOfUnit("cm") || | |
token.isDimensionOfUnit("mm") || | |
token.isDimensionOfUnit("in") || | |
token.isDimensionOfUnit("pc") || | |
token.isDimensionOfUnit("px") || | |
token.isDimensionOfUnit("em") || | |
token.isDimensionOfUnit("ex") || | |
token.isDimensionOfUnit("pt")) { | |
var offsetX = token.value; | |
token = this.getToken(true, true); | |
} | |
else | |
return []; | |
if (!inset && token.isIdent('inset')) { | |
inset = true; | |
token = this.getToken(true, true); | |
} | |
if (token.isPercentage() || | |
token.isDimensionOfUnit("cm") || | |
token.isDimensionOfUnit("mm") || | |
token.isDimensionOfUnit("in") || | |
token.isDimensionOfUnit("pc") || | |
token.isDimensionOfUnit("px") || | |
token.isDimensionOfUnit("em") || | |
token.isDimensionOfUnit("ex") || | |
token.isDimensionOfUnit("pt")) { | |
var offsetY = token.value; | |
token = this.getToken(true, true); | |
} | |
else | |
return []; | |
if (!inset && token.isIdent('inset')) { | |
inset = true; | |
token = this.getToken(true, true); | |
} | |
if (token.isPercentage() || | |
token.isDimensionOfUnit("cm") || | |
token.isDimensionOfUnit("mm") || | |
token.isDimensionOfUnit("in") || | |
token.isDimensionOfUnit("pc") || | |
token.isDimensionOfUnit("px") || | |
token.isDimensionOfUnit("em") || | |
token.isDimensionOfUnit("ex") || | |
token.isDimensionOfUnit("pt")) { | |
var blurRadius = token.value; | |
token = this.getToken(true, true); | |
} | |
if (!inset && token.isIdent('inset')) { | |
inset = true; | |
token = this.getToken(true, true); | |
} | |
if (token.isPercentage() || | |
token.isDimensionOfUnit("cm") || | |
token.isDimensionOfUnit("mm") || | |
token.isDimensionOfUnit("in") || | |
token.isDimensionOfUnit("pc") || | |
token.isDimensionOfUnit("px") || | |
token.isDimensionOfUnit("em") || | |
token.isDimensionOfUnit("ex") || | |
token.isDimensionOfUnit("pt")) { | |
var spreadRadius = token.value; | |
token = this.getToken(true, true); | |
} | |
if (!inset && token.isIdent('inset')) { | |
inset = true; | |
token = this.getToken(true, true); | |
} | |
if (token.isFunction("rgb(") || | |
token.isFunction("rgba(") || | |
token.isFunction("hsl(") || | |
token.isFunction("hsla(") || | |
token.isSymbol("#") || | |
token.isIdent()) { | |
var color = this.parseColor(token); | |
token = this.getToken(true, true); | |
} | |
if (!inset && token.isIdent('inset')) { | |
inset = true; | |
token = this.getToken(true, true); | |
} | |
shadows.push( { none: false, | |
color: color, | |
offsetX: offsetX, offsetY: offsetY, | |
blurRadius: blurRadius, | |
spreadRadius: spreadRadius, | |
inset: inset | |
} ); | |
if (token.isSymbol(",")) { | |
inset = false; | |
color = ""; | |
blurRadius = "0px"; | |
spreadRadius = "0px" | |
offsetX = "0px"; | |
offsetY = "0px"; | |
token = this.getToken(true, true); | |
} | |
else if (!token.isNotNull()) | |
return shadows; | |
else | |
return []; | |
} | |
} | |
return shadows; | |
}; | |
CSSParser.prototype.parseCharsetRule = function(aSheet) { | |
var token = this.getToken(false, false); | |
if (token.isAtRule("@charset") && token.value == "@charset") { // lowercase check | |
var s = token.value; | |
token = this.getToken(false, false); | |
s += token.value; | |
if (token.isWhiteSpace(" ")) { | |
token = this.getToken(false, false); | |
s += token.value; | |
if (token.isString()) { | |
var encoding = token.value; | |
token = this.getToken(false, false); | |
s += token.value; | |
if (token.isSymbol(";")) { | |
var rule = new jscsspCharsetRule(); | |
rule.encoding = encoding; | |
rule.parsedCssText = s; | |
rule.parentStyleSheet = aSheet; | |
aSheet.cssRules.push(rule); | |
return true; | |
} | |
else | |
this.reportError(kCHARSET_RULE_MISSING_SEMICOLON); | |
} | |
else | |
this.reportError(kCHARSET_RULE_CHARSET_IS_STRING); | |
} | |
else | |
this.reportError(kCHARSET_RULE_MISSING_WS); | |
} | |
this.addUnknownAtRule(aSheet, s); | |
return false; | |
}; | |
CSSParser.prototype.parseColor = function(token) | |
{ | |
var color = ""; | |
if (token.isFunction("rgb(") | |
|| token.isFunction("rgba(")) { | |
color = token.value; | |
var isRgba = token.isFunction("rgba(") | |
token = this.getToken(true, true); | |
if (!token.isNumber() && !token.isPercentage()) | |
return ""; | |
color += token.value; | |
token = this.getToken(true, true); | |
if (!token.isSymbol(",")) | |
return ""; | |
color += ", "; | |
token = this.getToken(true, true); | |
if (!token.isNumber() && !token.isPercentage()) | |
return ""; | |
color += token.value; | |
token = this.getToken(true, true); | |
if (!token.isSymbol(",")) | |
return ""; | |
color += ", "; | |
token = this.getToken(true, true); | |
if (!token.isNumber() && !token.isPercentage()) | |
return ""; | |
color += token.value; | |
if (isRgba) { | |
token = this.getToken(true, true); | |
if (!token.isSymbol(",")) | |
return ""; | |
color += ", "; | |
token = this.getToken(true, true); | |
if (!token.isNumber()) | |
return ""; | |
color += token.value; | |
} | |
token = this.getToken(true, true); | |
if (!token.isSymbol(")")) | |
return ""; | |
color += token.value; | |
} | |
else if (token.isFunction("hsl(") | |
|| token.isFunction("hsla(")) { | |
color = token.value; | |
var isHsla = token.isFunction("hsla(") | |
token = this.getToken(true, true); | |
if (!token.isNumber()) | |
return ""; | |
color += token.value; | |
token = this.getToken(true, true); | |
if (!token.isSymbol(",")) | |
return ""; | |
color += ", "; | |
token = this.getToken(true, true); | |
if (!token.isPercentage()) | |
return ""; | |
color += token.value; | |
token = this.getToken(true, true); | |
if (!token.isSymbol(",")) | |
return ""; | |
color += ", "; | |
token = this.getToken(true, true); | |
if (!token.isPercentage()) | |
return ""; | |
color += token.value; | |
if (isHsla) { | |
token = this.getToken(true, true); | |
if (!token.isSymbol(",")) | |
return ""; | |
color += ", "; | |
token = this.getToken(true, true); | |
if (!token.isNumber()) | |
return ""; | |
color += token.value; | |
} | |
token = this.getToken(true, true); | |
if (!token.isSymbol(")")) | |
return ""; | |
color += token.value; | |
} | |
else if (token.isIdent() | |
&& (token.value in this.kCOLOR_NAMES)) | |
color = token.value; | |
else if (token.isSymbol("#")) { | |
token = this.getHexValue(); | |
if (!token.isHex()) | |
return ""; | |
var length = token.value.length; | |
if (length != 3 && length != 6) | |
return ""; | |
if (token.value.match( /[a-fA-F0-9]/g ).length != length) | |
return ""; | |
color = "#" + token.value; | |
} | |
return color; | |
}; | |
CSSParser.prototype.parseCueShorthand = function(token, declarations, aAcceptPriority) | |
{ | |
var before = ""; | |
var after = ""; | |
var values = []; | |
var values = []; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
if (token.isSymbol(";") | |
|| (aAcceptPriority && token.isSymbol("!")) | |
|| token.isSymbol("}")) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} | |
else if (!values.length && token.isIdent(this.kINHERIT)) { | |
values.push(token.value); | |
} | |
else if (token.isIdent("none")) | |
values.push(token.value); | |
else if (token.isFunction("url(")) { | |
token = this.getToken(true, true); | |
var urlContent = this.parseURL(token); | |
if (urlContent) | |
values.push("url(" + urlContent); | |
else | |
return ""; | |
} | |
else | |
return ""; | |
token = this.getToken(true, true); | |
} | |
var count = values.length; | |
switch (count) { | |
case 1: | |
before = values[0]; | |
after = before; | |
break; | |
case 2: | |
before = values[0]; | |
after = values[1]; | |
break; | |
default: | |
return ""; | |
} | |
this.forgetState(); | |
aDecl.push(this._createJscsspDeclarationFromValue("cue-before", before)); | |
aDecl.push(this._createJscsspDeclarationFromValue("cue-after", after)); | |
return before + " " + after; | |
}; | |
CSSParser.prototype.parseDeclaration = function(aToken, aDecl, aAcceptPriority, aExpandShorthands, aSheet) { | |
this.preserveState(); | |
var blocks = []; | |
if (aToken.isIdent()) { | |
var descriptor = aToken.value.toLowerCase(); | |
var token = this.getToken(true, true); | |
if (token.isSymbol(":")) { | |
var token = this.getToken(true, true); | |
var value = ""; | |
var declarations = []; | |
if (aExpandShorthands) | |
switch (descriptor) { | |
case "background": | |
value = this.parseBackgroundShorthand(token, declarations, aAcceptPriority); | |
break; | |
case "margin": | |
case "padding": | |
value = this.parseMarginOrPaddingShorthand(token, declarations, aAcceptPriority, descriptor); | |
break; | |
case "border-color": | |
value = this.parseBorderColorShorthand(token, declarations, aAcceptPriority); | |
break; | |
case "border-style": | |
value = this.parseBorderStyleShorthand(token, declarations, aAcceptPriority); | |
break; | |
case "border-width": | |
value = this.parseBorderWidthShorthand(token, declarations, aAcceptPriority); | |
break; | |
case "border-top": | |
case "border-right": | |
case "border-bottom": | |
case "border-left": | |
case "border": | |
case "outline": | |
value = this.parseBorderEdgeOrOutlineShorthand(token, declarations, aAcceptPriority, descriptor); | |
break; | |
case "cue": | |
value = this.parseCueShorthand(token, declarations, aAcceptPriority); | |
break; | |
case "pause": | |
value = this.parsePauseShorthand(token, declarations, aAcceptPriority); | |
break; | |
case "font": | |
value = this.parseFontShorthand(token, declarations, aAcceptPriority); | |
break; | |
case "list-style": | |
value = this.parseListStyleShorthand(token, declarations, aAcceptPriority); | |
break; | |
default: | |
value = this.parseDefaultPropertyValue(token, declarations, aAcceptPriority, descriptor, aSheet); | |
break; | |
} | |
else | |
value = this.parseDefaultPropertyValue(token, declarations, aAcceptPriority, descriptor, aSheet); | |
token = this.currentToken(); | |
if (value) // no error above | |
{ | |
var priority = false; | |
if (token.isSymbol("!")) { | |
token = this.getToken(true, true); | |
if (token.isIdent("important")) { | |
priority = true; | |
token = this.getToken(true, true); | |
if (token.isSymbol(";") || token.isSymbol("}")) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
} | |
else return ""; | |
} | |
else return ""; | |
} | |
else if (token.isNotNull() && !token.isSymbol(";") && !token.isSymbol("}")) | |
return ""; | |
for (var i = 0; i < declarations.length; i++) { | |
declarations[i].priority = priority; | |
aDecl.push(declarations[i]); | |
} | |
return descriptor + ": " + value + ";"; | |
} | |
} | |
} | |
else if (aToken.isComment()) { | |
if (this.mPreserveComments) { | |
this.forgetState(); | |
var comment = new jscsspComment(); | |
comment.parsedCssText = aToken.value; | |
aDecl.push(comment); | |
} | |
return aToken.value; | |
} | |
// we have an error here, let's skip it | |
this.restoreState(); | |
var s = aToken.value; | |
blocks = []; | |
var token = this.getToken(false, false); | |
while (token.isNotNull()) { | |
s += token.value; | |
if ((token.isSymbol(";") || token.isSymbol("}")) && !blocks.length) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} else if (token.isSymbol("{") | |
|| token.isSymbol("(") | |
|| token.isSymbol("[") | |
|| token.isFunction()) { | |
blocks.push(token.isFunction() ? "(" : token.value); | |
} else if (token.isSymbol("}") | |
|| token.isSymbol(")") | |
|| token.isSymbol("]")) { | |
if (blocks.length) { | |
var ontop = blocks[blocks.length - 1]; | |
if ((token.isSymbol("}") && ontop == "{") | |
|| (token.isSymbol(")") && ontop == "(") | |
|| (token.isSymbol("]") && ontop == "[")) { | |
blocks.pop(); | |
} | |
} | |
} | |
token = this.getToken(false, false); | |
} | |
return ""; | |
}; | |
CSSParser.prototype.reportError = function(aMsg) { | |
this.mError = aMsg; | |
}; | |
CSSParser.prototype.consumeError = function() { | |
var e = this.mError; | |
this.mError = null; | |
return e; | |
}; | |
function CSSParser(aString) | |
{ | |
this.mToken = null; | |
this.mLookAhead = null; | |
this.mScanner = new CSSScanner(aString); | |
this.mPreserveWS = true; | |
this.mPreserveComments = true; | |
this.mPreservedTokens = []; | |
this.mError = null; | |
} | |
CSSParser.prototype._init = function() { | |
this.mToken = null; | |
this.mLookAhead = null; | |
}; | |
CSSParser.prototype.kINHERIT = "inherit", | |
CSSParser.prototype.kBORDER_WIDTH_NAMES = { | |
"thin": true, | |
"medium": true, | |
"thick": true | |
}; | |
CSSParser.prototype.kBORDER_STYLE_NAMES = { | |
"none": true, | |
"hidden": true, | |
"dotted": true, | |
"dashed": true, | |
"solid": true, | |
"double": true, | |
"groove": true, | |
"ridge": true, | |
"inset": true, | |
"outset": true | |
}; | |
CSSParser.prototype.kCOLOR_NAMES = { | |
"transparent": true, | |
"black": true, | |
"silver": true, | |
"gray": true, | |
"white": true, | |
"maroon": true, | |
"red": true, | |
"purple": true, | |
"fuchsia": true, | |
"green": true, | |
"lime": true, | |
"olive": true, | |
"yellow": true, | |
"navy": true, | |
"blue": true, | |
"teal": true, | |
"aqua": true, | |
"aliceblue": true, | |
"antiquewhite": true, | |
"aquamarine": true, | |
"azure": true, | |
"beige": true, | |
"bisque": true, | |
"blanchedalmond": true, | |
"blueviolet": true, | |
"brown": true, | |
"burlywood": true, | |
"cadetblue": true, | |
"chartreuse": true, | |
"chocolate": true, | |
"coral": true, | |
"cornflowerblue": true, | |
"cornsilk": true, | |
"crimson": true, | |
"cyan": true, | |
"darkblue": true, | |
"darkcyan": true, | |
"darkgoldenrod": true, | |
"darkgray": true, | |
"darkgreen": true, | |
"darkgrey": true, | |
"darkkhaki": true, | |
"darkmagenta": true, | |
"darkolivegreen": true, | |
"darkorange": true, | |
"darkorchid": true, | |
"darkred": true, | |
"darksalmon": true, | |
"darkseagreen": true, | |
"darkslateblue": true, | |
"darkslategray": true, | |
"darkslategrey": true, | |
"darkturquoise": true, | |
"darkviolet": true, | |
"deeppink": true, | |
"deepskyblue": true, | |
"dimgray": true, | |
"dimgrey": true, | |
"dodgerblue": true, | |
"firebrick": true, | |
"floralwhite": true, | |
"forestgreen": true, | |
"gainsboro": true, | |
"ghostwhite": true, | |
"gold": true, | |
"goldenrod": true, | |
"greenyellow": true, | |
"grey": true, | |
"honeydew": true, | |
"hotpink": true, | |
"indianred": true, | |
"indigo": true, | |
"ivory": true, | |
"khaki": true, | |
"lavender": true, | |
"lavenderblush": true, | |
"lawngreen": true, | |
"lemonchiffon": true, | |
"lightblue": true, | |
"lightcoral": true, | |
"lightcyan": true, | |
"lightgoldenrodyellow": true, | |
"lightgray": true, | |
"lightgreen": true, | |
"lightgrey": true, | |
"lightpink": true, | |
"lightsalmon": true, | |
"lightseagreen": true, | |
"lightskyblue": true, | |
"lightslategray": true, | |
"lightslategrey": true, | |
"lightsteelblue": true, | |
"lightyellow": true, | |
"limegreen": true, | |
"linen": true, | |
"magenta": true, | |
"mediumaquamarine": true, | |
"mediumblue": true, | |
"mediumorchid": true, | |
"mediumpurple": true, | |
"mediumseagreen": true, | |
"mediumslateblue": true, | |
"mediumspringgreen": true, | |
"mediumturquoise": true, | |
"mediumvioletred": true, | |
"midnightblue": true, | |
"mintcream": true, | |
"mistyrose": true, | |
"moccasin": true, | |
"navajowhite": true, | |
"oldlace": true, | |
"olivedrab": true, | |
"orange": true, | |
"orangered": true, | |
"orchid": true, | |
"palegoldenrod": true, | |
"palegreen": true, | |
"paleturquoise": true, | |
"palevioletred": true, | |
"papayawhip": true, | |
"peachpuff": true, | |
"peru": true, | |
"pink": true, | |
"plum": true, | |
"powderblue": true, | |
"rosybrown": true, | |
"royalblue": true, | |
"saddlebrown": true, | |
"salmon": true, | |
"sandybrown": true, | |
"seagreen": true, | |
"seashell": true, | |
"sienna": true, | |
"skyblue": true, | |
"slateblue": true, | |
"slategray": true, | |
"slategrey": true, | |
"snow": true, | |
"springgreen": true, | |
"steelblue": true, | |
"tan": true, | |
"thistle": true, | |
"tomato": true, | |
"turquoise": true, | |
"violet": true, | |
"wheat": true, | |
"whitesmoke": true, | |
"yellowgreen": true, | |
"activeborder": true, | |
"activecaption": true, | |
"appworkspace": true, | |
"background": true, | |
"buttonface": true, | |
"buttonhighlight": true, | |
"buttonshadow": true, | |
"buttontext": true, | |
"captiontext": true, | |
"graytext": true, | |
"highlight": true, | |
"highlighttext": true, | |
"inactiveborder": true, | |
"inactivecaption": true, | |
"inactivecaptiontext": true, | |
"infobackground": true, | |
"infotext": true, | |
"menu": true, | |
"menutext": true, | |
"scrollbar": true, | |
"threeddarkshadow": true, | |
"threedface": true, | |
"threedhighlight": true, | |
"threedlightshadow": true, | |
"threedshadow": true, | |
"window": true, | |
"windowframe": true, | |
"windowtext": true | |
}; | |
CSSParser.prototype.kLIST_STYLE_TYPE_NAMES = { | |
"decimal": true, | |
"decimal-leading-zero": true, | |
"lower-roman": true, | |
"upper-roman": true, | |
"georgian": true, | |
"armenian": true, | |
"lower-latin": true, | |
"lower-alpha": true, | |
"upper-latin": true, | |
"upper-alpha": true, | |
"lower-greek": true, | |
"disc": true, | |
"circle": true, | |
"square": true, | |
"none": true, | |
/* CSS 3 */ | |
"box": true, | |
"check": true, | |
"diamond": true, | |
"hyphen": true, | |
"lower-armenian": true, | |
"cjk-ideographic": true, | |
"ethiopic-numeric": true, | |
"hebrew": true, | |
"japanese-formal": true, | |
"japanese-informal": true, | |
"simp-chinese-formal": true, | |
"simp-chinese-informal": true, | |
"syriac": true, | |
"tamil": true, | |
"trad-chinese-formal": true, | |
"trad-chinese-informal": true, | |
"upper-armenian": true, | |
"arabic-indic": true, | |
"binary": true, | |
"bengali": true, | |
"cambodian": true, | |
"khmer": true, | |
"devanagari": true, | |
"gujarati": true, | |
"gurmukhi": true, | |
"kannada": true, | |
"lower-hexadecimal": true, | |
"lao": true, | |
"malayalam": true, | |
"mongolian": true, | |
"myanmar": true, | |
"octal": true, | |
"oriya": true, | |
"persian": true, | |
"urdu": true, | |
"telugu": true, | |
"tibetan": true, | |
"upper-hexadecimal": true, | |
"afar": true, | |
"ethiopic-halehame-aa-et": true, | |
"ethiopic-halehame-am-et": true, | |
"amharic-abegede": true, | |
"ehiopic-abegede-am-et": true, | |
"cjk-earthly-branch": true, | |
"cjk-heavenly-stem": true, | |
"ethiopic": true, | |
"ethiopic-abegede": true, | |
"ethiopic-abegede-gez": true, | |
"hangul-consonant": true, | |
"hangul": true, | |
"hiragana-iroha": true, | |
"hiragana": true, | |
"katakana-iroha": true, | |
"katakana": true, | |
"lower-norwegian": true, | |
"oromo": true, | |
"ethiopic-halehame-om-et": true, | |
"sidama": true, | |
"ethiopic-halehame-sid-et": true, | |
"somali": true, | |
"ethiopic-halehame-so-et": true, | |
"tigre": true, | |
"ethiopic-halehame-tig": true, | |
"tigrinya-er-abegede": true, | |
"ethiopic-abegede-ti-er": true, | |
"tigrinya-et": true, | |
"ethiopic-halehame-ti-et": true, | |
"upper-greek": true, | |
"asterisks": true, | |
"footnotes": true, | |
"circled-decimal": true, | |
"circled-lower-latin": true, | |
"circled-upper-latin": true, | |
"dotted-decimal": true, | |
"double-circled-decimal": true, | |
"filled-circled-decimal": true, | |
"parenthesised-decimal": true, | |
"parenthesised-lower-latin": true | |
}; | |
CSSParser.prototype.parseFontFaceRule = function(aToken, aSheet) { | |
var currentLine = CountLF(this.mScanner.getAlreadyScanned()); | |
var s = aToken.value; | |
var valid = false; | |
var descriptors = []; | |
this.preserveState(); | |
var token = this.getToken(true, true); | |
if (token.isNotNull()) { | |
// expecting block start | |
if (token.isSymbol("{")) { | |
s += " " + token.value; | |
var token = this.getToken(true, false); | |
while (true) { | |
if (token.isSymbol("}")) { | |
s += "}"; | |
valid = true; | |
break; | |
} else { | |
var d = this.parseDeclaration(token, descriptors, false, false, aSheet); | |
s += ((d && descriptors.length) ? " " : "") + d; | |
} | |
token = this.getToken(true, false); | |
} | |
} | |
} | |
if (valid) { | |
this.forgetState(); | |
var rule = new jscsspFontFaceRule(); | |
rule.currentLine = currentLine; | |
rule.parsedCssText = s; | |
rule.descriptors = descriptors; | |
rule.parentStyleSheet = aSheet; | |
aSheet.cssRules.push(rule) | |
return true; | |
} | |
this.restoreState(); | |
return false; | |
}; | |
CSSParser.prototype.parseFontShorthand = function(token, aDecl, aAcceptPriority) | |
{ | |
var kStyle = {"italic": true, "oblique": true }; | |
var kVariant = {"small-caps": true }; | |
var kWeight = { "bold": true, "bolder": true, "lighter": true, | |
"100": true, "200": true, "300": true, "400": true, | |
"500": true, "600": true, "700": true, "800": true, | |
"900": true }; | |
var kSize = { "xx-small": true, "x-small": true, "small": true, "medium": true, | |
"large": true, "x-large": true, "xx-large": true, | |
"larger": true, "smaller": true }; | |
var kValues = { "caption": true, "icon": true, "menu": true, "message-box": true, "small-caption": true, "status-bar": true }; | |
var kFamily = { "serif": true, "sans-serif": true, "cursive": true, "fantasy": true, "monospace": true }; | |
var fStyle = null; | |
var fVariant = null; | |
var fWeight = null; | |
var fSize = null; | |
var fLineHeight = null; | |
var fFamily = ""; | |
var fSystem = null; | |
var fFamilyValues = []; | |
var normalCount = 0; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
if (token.isSymbol(";") | |
|| (aAcceptPriority && token.isSymbol("!")) | |
|| token.isSymbol("}")) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} | |
else if (!fStyle && !fVariant && !fWeight | |
&& !fSize && !fLineHeight && !fFamily | |
&& !fSystem | |
&& token.isIdent(this.kINHERIT)) { | |
fStyle = this.kINHERIT; | |
fVariant = this.kINHERIT; | |
fWeight = this.kINHERIT; | |
fSize = this.kINHERIT; | |
fLineHeight = this.kINHERIT; | |
fFamily = this.kINHERIT; | |
fSystem = this.kINHERIT; | |
} | |
else { | |
if (!fSystem && (token.isIdent() && token.value in kValues)) { | |
fSystem = token.value; | |
break; | |
} | |
else { | |
if (!fStyle | |
&& token.isIdent() | |
&& (token.value in kStyle)) { | |
fStyle = token.value; | |
} | |
else if (!fVariant | |
&& token.isIdent() | |
&& (token.value in kVariant)) { | |
fVariant = token.value; | |
} | |
else if (!fWeight | |
&& (token.isIdent() || token.isNumber()) | |
&& (token.value in kWeight)) { | |
fWeight = token.value; | |
} | |
else if (!fSize | |
&& ((token.isIdent() && (token.value in kSize)) | |
|| token.isDimension() | |
|| token.isPercentage())) { | |
fSize = token.value; | |
token = this.getToken(false, false); | |
if (token.isSymbol("/")) { | |
token = this.getToken(false, false); | |
if (!fLineHeight && | |
(token.isDimension() || token.isNumber() || token.isPercentage())) { | |
fLineHeight = token.value; | |
} | |
else | |
return ""; | |
} | |
else if (!token.isWhiteSpace()) | |
continue; | |
} | |
else if (token.isIdent("normal")) { | |
normalCount++; | |
if (normalCount > 3) | |
return ""; | |
} | |
else if (!fFamily && // *MUST* be last to be tested here | |
(token.isString() | |
|| token.isIdent())) { | |
var lastWasComma = false; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
else if (token.isSymbol(";") | |
|| (aAcceptPriority && token.isSymbol("!")) | |
|| token.isSymbol("}")) { | |
this.ungetToken(); | |
break; | |
} | |
else if (token.isIdent() && token.value in kFamily) { | |
var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null); | |
value.value = token.value; | |
fFamilyValues.push(value); | |
fFamily += token.value; | |
break; | |
} | |
else if (token.isString() || token.isIdent()) { | |
var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null); | |
value.value = token.value; | |
fFamilyValues.push(value); | |
fFamily += token.value; | |
lastWasComma = false; | |
} | |
else if (!lastWasComma && token.isSymbol(",")) { | |
fFamily += ", "; | |
lastWasComma = true; | |
} | |
else | |
return ""; | |
token = this.getToken(true, true); | |
} | |
} | |
else { | |
return ""; | |
} | |
} | |
} | |
token = this.getToken(true, true); | |
} | |
// create the declarations | |
this.forgetState(); | |
if (fSystem) { | |
aDecl.push(this._createJscsspDeclarationFromValue("font", fSystem)); | |
return fSystem; | |
} | |
fStyle = fStyle ? fStyle : "normal"; | |
fVariant = fVariant ? fVariant : "normal"; | |
fWeight = fWeight ? fWeight : "normal"; | |
fSize = fSize ? fSize : "medium"; | |
fLineHeight = fLineHeight ? fLineHeight : "normal"; | |
fFamily = fFamily ? fFamily : "-moz-initial"; | |
aDecl.push(this._createJscsspDeclarationFromValue("font-style", fStyle)); | |
aDecl.push(this._createJscsspDeclarationFromValue("font-variant", fVariant)); | |
aDecl.push(this._createJscsspDeclarationFromValue("font-weight", fWeight)); | |
aDecl.push(this._createJscsspDeclarationFromValue("font-size", fSize)); | |
aDecl.push(this._createJscsspDeclarationFromValue("line-height", fLineHeight)); | |
aDecl.push(this._createJscsspDeclarationFromValuesArray("font-family", fFamilyValues, fFamily)); | |
return fStyle + " " + fVariant + " " + fWeight + " " + fSize + "/" + fLineHeight + " " + fFamily; | |
}; | |
CSSParser.prototype.parseFunctionArgument = function(token) | |
{ | |
var value = ""; | |
if (token.isString()) | |
{ | |
value += token.value; | |
token = this.getToken(true, true); | |
} | |
else { | |
var parenthesis = 1; | |
while (true) | |
{ | |
if (!token.isNotNull()) | |
return ""; | |
if (token.isFunction() || token.isSymbol("(")) | |
parenthesis++; | |
if (token.isSymbol(")")) { | |
parenthesis--; | |
if (!parenthesis) | |
break; | |
} | |
value += token.value; | |
token = this.getToken(false, false); | |
} | |
} | |
if (token.isSymbol(")")) | |
return value + ")"; | |
return ""; | |
}; | |
CSSParser.prototype.parseColorStop = function(token) | |
{ | |
var color = this.parseColor(token); | |
var position = ""; | |
if (!color) | |
return null; | |
token = this.getToken(true, true); | |
if (token.isLength()) { | |
position = token.value; | |
token = this.getToken(true, true); | |
} | |
return { color: color, position: position } | |
}; | |
CSSParser.prototype.parseGradient = function () | |
{ | |
var kHPos = {"left": true, "right": true }; | |
var kVPos = {"top": true, "bottom": true }; | |
var kPos = {"left": true, "right": true, "top": true, "bottom": true, "center": true}; | |
var isRadial = false; | |
var gradient = { isRepeating: false }; | |
var token = this.getToken(true, true); | |
if (token.isNotNull()) { | |
if (token.isFunction("linear-gradient(") || | |
token.isFunction("radial-gradient(") || | |
token.isFunction("repeating-linear-gradient(") || | |
token.isFunction("repeating-radial-gradient(")) { | |
if (token.isFunction("radial-gradient(") || | |
token.isFunction("repeating-radial-gradient(")) { | |
gradient.isRadial = true; | |
} | |
if (token.isFunction("repeating-linear-gradient(") || | |
token.isFunction("repeating-radial-gradient(")) { | |
gradient.isRepeating = true; | |
} | |
token = this.getToken(true, true); | |
var foundPosition = false; | |
var haveAngle = false; | |
/********** LINEAR **********/ | |
if (token.isAngle()) { | |
gradient.angle = token.value; | |
haveAngle = true; | |
token = this.getToken(true, true); | |
if (!token.isSymbol(",")) | |
return null; | |
token = this.getToken(true, true); | |
} | |
else if (token.isIdent("to")) { | |
foundPosition = true; | |
token = this.getToken(true, true); | |
if (token.isIdent("top") | |
|| token.isIdent("bottom") | |
|| token.isIdent("left") | |
|| token.isIdent("right")) { | |
gradient.position = token.value; | |
token = this.getToken(true, true); | |
if (((gradient.position == "top" || gradient.position == "bottom") && (token.isIdent("left") || token.isIdent("right"))) | |
|| ((gradient.position == "left" || gradient.position == "right") && (token.isIdent("top") || token.isIdent("bottom")))) { | |
gradient.position += " " + token.value; | |
token = this.getToken(true, true); | |
} | |
} | |
else | |
return null; | |
if (!token.isSymbol(",")) | |
return null; | |
token = this.getToken(true, true); | |
} | |
/********** RADIAL **********/ | |
else if (gradient.isRadial) { | |
gradient.shape = ""; | |
gradient.extent = ""; | |
gradient.positions = []; | |
gradient.at = ""; | |
while (!token.isIdent("at") && !token.isSymbol(",")) { | |
if (!gradient.shape | |
&& (token.isIdent("circle") || token.isIdent("ellipse"))) { | |
gradient.shape = token.value; | |
token = this.getToken(true, true); | |
} | |
else if (!gradient.extent | |
&& (token.isIdent("closest-corner") | |
|| token.isIdent("closes-side") | |
|| token.isIdent("farthest-corner") | |
|| token.isIdent("farthest-corner"))) { | |
gradient.extent = token.value; | |
token = this.getToken(true, true); | |
} | |
else if (gradient.positions.length < 2 && token.isLength()){ | |
gradient.positions.push(token.value); | |
token = this.getToken(true, true); | |
} | |
else | |
break; | |
} | |
// verify if the shape is null of well defined | |
if ((gradient.positions.length == 1 && !gradient.extent && (gradient.shape == "circle" || !gradient.shape)) | |
|| (gradient.positions.length == 2 && !gradient.extent && (gradient.shape == "ellipse" || !gradient.shape)) | |
|| (!gradient.positions.length && gradient.extent) | |
|| (!gradient.positions.length && !gradient.extent)) { | |
// shape ok | |
} | |
else { | |
return null; | |
} | |
if (token.isIdent("at")) { | |
token = this.getToken(true, true); | |
if (((token.isIdent() && token.value in kPos) | |
|| token.isDimension() | |
|| token.isNumber("0") | |
|| token.isPercentage())) { | |
gradient.at = token.value; | |
token = this.getToken(true, true); | |
if (token.isDimension() || token.isNumber("0") || token.isPercentage()) { | |
gradient.at += " " + token.value; | |
} | |
else if (token.isIdent() && token.value in kPos) { | |
if ((gradient.at in kHPos && token.value in kHPos) || | |
(gradient.at in kVPos && token.value in kVPos)) | |
return ""; | |
gradient.at += " " + token.value; | |
} | |
else { | |
this.ungetToken(); | |
gradient.at += " center"; | |
} | |
} | |
else | |
return null; | |
token = this.getToken(true, true); | |
} | |
if (gradient.shape || gradient.extent || gradient.positions.length || gradient.at) { | |
if (!token.isSymbol(",")) | |
return null; | |
token = this.getToken(true, true); | |
} | |
} | |
// now color stops... | |
var stop1 = this.parseColorStop(token); | |
if (!stop1) | |
return null; | |
token = this.currentToken(); | |
if (!token.isSymbol(",")) | |
return null; | |
token = this.getToken(true, true); | |
var stop2 = this.parseColorStop(token); | |
if (!stop2) | |
return null; | |
token = this.currentToken(); | |
if (token.isSymbol(",")) { | |
token = this.getToken(true, true); | |
} | |
// ok we have at least two color stops | |
gradient.stops = [stop1, stop2]; | |
while (!token.isSymbol(")")) { | |
var colorstop = this.parseColorStop(token); | |
if (!colorstop) | |
return null; | |
token = this.currentToken(); | |
if (!token.isSymbol(")") && !token.isSymbol(",")) | |
return null; | |
if (token.isSymbol(",")) | |
token = this.getToken(true, true); | |
gradient.stops.push(colorstop); | |
} | |
return gradient; | |
} | |
} | |
return null; | |
}; | |
CSSParser.prototype.serializeGradient = function(gradient) | |
{ | |
var s = gradient.isRadial | |
? (gradient.isRepeating ? "repeating-radial-gradient(" : "radial-gradient(" ) | |
: (gradient.isRepeating ? "repeating-linear-gradient(" : "linear-gradient(" ); | |
if (gradient.angle || gradient.position) | |
s += (gradient.angle ? gradient.angle: "") + | |
(gradient.position ? "to " + gradient.position : "") + | |
", "; | |
if (gradient.isRadial) | |
s += (gradient.shape ? gradient.shape + " " : "") + | |
(gradient.extent ? gradient.extent + " " : "") + | |
(gradient.positions.length ? gradient.positions.join(" ") + " " : "") + | |
(gradient.at ? "at " + gradient.at + " " : "") + | |
(gradient.shape || gradient.extent || gradient.positions.length || gradient.at ? ", " : ""); | |
for (var i = 0; i < gradient.stops.length; i++) { | |
var colorstop = gradient.stops[i]; | |
s += colorstop.color + (colorstop.position ? " " + colorstop.position : ""); | |
if (i != gradient.stops.length -1) | |
s += ", "; | |
} | |
s += ")"; | |
return s; | |
}; | |
CSSParser.prototype.parseImportRule = function(aToken, aSheet) { | |
var currentLine = CountLF(this.mScanner.getAlreadyScanned()); | |
var s = aToken.value; | |
this.preserveState(); | |
var token = this.getToken(true, true); | |
var media = []; | |
var href = ""; | |
if (token.isString()) { | |
href = token.value; | |
s += " " + href; | |
} | |
else if (token.isFunction("url(")) { | |
token = this.getToken(true, true); | |
var urlContent = this.parseURL(token); | |
if (urlContent) { | |
href = "url(" + urlContent; | |
s += " " + href; | |
} | |
} | |
else | |
this.reportError(kIMPORT_RULE_MISSING_URL); | |
if (href) { | |
token = this.getToken(true, true); | |
while (token.isIdent()) { | |
s += " " + token.value; | |
media.push(token.value); | |
token = this.getToken(true, true); | |
if (!token) | |
break; | |
if (token.isSymbol(",")) { | |
s += ","; | |
} else if (token.isSymbol(";")) { | |
break; | |
} else | |
break; | |
token = this.getToken(true, true); | |
} | |
if (!media.length) { | |
media.push("all"); | |
} | |
if (token.isSymbol(";")) { | |
s += ";" | |
this.forgetState(); | |
var rule = new jscsspImportRule(); | |
rule.currentLine = currentLine; | |
rule.parsedCssText = s; | |
rule.href = href; | |
rule.media = media; | |
rule.parentStyleSheet = aSheet; | |
aSheet.cssRules.push(rule); | |
return true; | |
} | |
} | |
this.restoreState(); | |
this.addUnknownAtRule(aSheet, "@import"); | |
return false; | |
}; | |
CSSParser.prototype.parseKeyframesRule = function(aToken, aSheet) { | |
var currentLine = CountLF(this.mScanner.getAlreadyScanned()); | |
var s = aToken.value; | |
var valid = false; | |
var keyframesRule = new jscsspKeyframesRule(); | |
keyframesRule.currentLine = currentLine; | |
this.preserveState(); | |
var token = this.getToken(true, true); | |
var foundName = false; | |
while (token.isNotNull()) { | |
if (token.isIdent()) { | |
// should be the keyframes' name | |
foundName = true; | |
s += " " + token.value; | |
keyframesRule.name = token.value; | |
token = this.getToken(true, true); | |
if (token.isSymbol("{")) | |
this.ungetToken(); | |
else { | |
// error... | |
token.type = jscsspToken.NULL_TYPE; | |
break; | |
} | |
} | |
else if (token.isSymbol("{")) { | |
if (!foundName) { | |
token.type = jscsspToken.NULL_TYPE; | |
// not a valid keyframes at-rule | |
} | |
break; | |
} | |
else { | |
token.type = jscsspToken.NULL_TYPE; | |
// not a valid keyframes at-rule | |
break; | |
} | |
token = this.getToken(true, true); | |
} | |
if (token.isSymbol("{") && keyframesRule.name) { | |
// ok let's parse keyframe rules now... | |
s += " { "; | |
token = this.getToken(true, false); | |
while (token.isNotNull()) { | |
if (token.isComment() && this.mPreserveComments) { | |
s += " " + token.value; | |
var comment = new jscsspComment(); | |
comment.parsedCssText = token.value; | |
keyframesRule.cssRules.push(comment); | |
} else if (token.isSymbol("}")) { | |
valid = true; | |
break; | |
} else { | |
var r = this.parseKeyframeRule(token, keyframesRule, true); | |
if (r) | |
s += r; | |
} | |
token = this.getToken(true, false); | |
} | |
} | |
if (valid) { | |
this.forgetState(); | |
keyframesRule.currentLine = currentLine; | |
keyframesRule.parsedCssText = s; | |
aSheet.cssRules.push(keyframesRule); | |
return true; | |
} | |
this.restoreState(); | |
return false; | |
}; | |
CSSParser.prototype.parseKeyframeRule = function(aToken, aOwner) { | |
var currentLine = CountLF(this.mScanner.getAlreadyScanned()); | |
this.preserveState(); | |
var token = aToken; | |
// find the keyframe keys | |
var key = ""; | |
while (token.isNotNull()) { | |
if (token.isIdent() || token.isPercentage()) { | |
if (token.isIdent() | |
&& !token.isIdent("from") | |
&& !token.isIdent("to")) { | |
key = ""; | |
break; | |
} | |
key += token.value; | |
token = this.getToken(true, true); | |
if (token.isSymbol("{")) { | |
this.ungetToken(); | |
break; | |
} | |
else | |
if (token.isSymbol(",")) { | |
key += ", "; | |
} | |
else { | |
key = ""; | |
break; | |
} | |
} | |
else { | |
key = ""; | |
break; | |
} | |
token = this.getToken(true, true); | |
} | |
var valid = false; | |
var declarations = []; | |
if (key) { | |
var s = key; | |
token = this.getToken(true, true); | |
if (token.isSymbol("{")) { | |
s += " { "; | |
token = this.getToken(true, false); | |
while (true) { | |
if (!token.isNotNull()) { | |
valid = true; | |
break; | |
} | |
if (token.isSymbol("}")) { | |
s += "}"; | |
valid = true; | |
break; | |
} else { | |
var d = this.parseDeclaration(token, declarations, true, true, aOwner); | |
s += ((d && declarations.length) ? " " : "") + d; | |
} | |
token = this.getToken(true, false); | |
} | |
} | |
} | |
else { | |
// key is invalid so the whole rule is invalid with it | |
} | |
if (valid) { | |
var rule = new jscsspKeyframeRule(); | |
rule.currentLine = currentLine; | |
rule.parsedCssText = s; | |
rule.declarations = declarations; | |
rule.keyText = key; | |
rule.parentRule = aOwner; | |
aOwner.cssRules.push(rule); | |
return s; | |
} | |
this.restoreState(); | |
s = this.currentToken().value; | |
this.addUnknownAtRule(aOwner, s); | |
return ""; | |
}; | |
CSSParser.prototype.parseListStyleShorthand = function(token, aDecl, aAcceptPriority) | |
{ | |
var kPosition = { "inside": true, "outside": true }; | |
var lType = null; | |
var lPosition = null; | |
var lImage = null; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
if (token.isSymbol(";") | |
|| (aAcceptPriority && token.isSymbol("!")) | |
|| token.isSymbol("}")) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} | |
else if (!lType && !lPosition && ! lImage | |
&& token.isIdent(this.kINHERIT)) { | |
lType = this.kINHERIT; | |
lPosition = this.kINHERIT; | |
lImage = this.kINHERIT; | |
} | |
else if (!lType && | |
(token.isIdent() && token.value in this.kLIST_STYLE_TYPE_NAMES)) { | |
lType = token.value; | |
} | |
else if (!lPosition && | |
(token.isIdent() && token.value in kPosition)) { | |
lPosition = token.value; | |
} | |
else if (!lImage && token.isFunction("url")) { | |
token = this.getToken(true, true); | |
var urlContent = this.parseURL(token); | |
if (urlContent) { | |
lImage = "url(" + urlContent; | |
} | |
else | |
return ""; | |
} | |
else if (!token.isIdent("none")) | |
return ""; | |
token = this.getToken(true, true); | |
} | |
// create the declarations | |
this.forgetState(); | |
lType = lType ? lType : "none"; | |
lImage = lImage ? lImage : "none"; | |
lPosition = lPosition ? lPosition : "outside"; | |
aDecl.push(this._createJscsspDeclarationFromValue("list-style-type", lType)); | |
aDecl.push(this._createJscsspDeclarationFromValue("list-style-position", lPosition)); | |
aDecl.push(this._createJscsspDeclarationFromValue("list-style-image", lImage)); | |
return lType + " " + lPosition + " " + lImage; | |
}; | |
CSSParser.prototype.parse = function(aString, aTryToPreserveWhitespaces, aTryToPreserveComments) { | |
if (!aString) | |
return null; // early way out if we can | |
this.mPreserveWS = aTryToPreserveWhitespaces; | |
this.mPreserveComments = aTryToPreserveComments; | |
this.mPreservedTokens = []; | |
this.mScanner.init(aString); | |
var sheet = new jscsspStylesheet(); | |
// @charset can only appear at first char of the stylesheet | |
var token = this.getToken(false, false); | |
if (!token.isNotNull()) | |
return sheet; | |
if (token.isAtRule("@charset")) { | |
this.ungetToken(); | |
this.parseCharsetRule(sheet); | |
token = this.getToken(false, false); | |
} | |
var foundStyleRules = false; | |
var foundImportRules = false; | |
var foundNameSpaceRules = false; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
if (token.isWhiteSpace()) | |
{ | |
if (aTryToPreserveWhitespaces) | |
this.addWhitespace(sheet, token.value); | |
} | |
else if (token.isComment()) | |
{ | |
if (this.mPreserveComments) | |
this.addComment(sheet, token.value); | |
} | |
else if (token.isAtRule()) { | |
if (token.isAtRule("@variables")) { | |
if (!foundImportRules && !foundStyleRules) | |
this.parseVariablesRule(token, sheet); | |
else { | |
this.reportError(kVARIABLES_RULE_POSITION); | |
this.addUnknownAtRule(sheet, token.value); | |
} | |
} | |
else if (token.isAtRule("@import")) { | |
// @import rules MUST occur before all style and namespace | |
// rules | |
if (!foundStyleRules && !foundNameSpaceRules) | |
foundImportRules = this.parseImportRule(token, sheet); | |
else { | |
this.reportError(kIMPORT_RULE_POSITION); | |
this.addUnknownAtRule(sheet, token.value); | |
} | |
} | |
else if (token.isAtRule("@namespace")) { | |
// @namespace rules MUST occur before all style rule and | |
// after all @import rules | |
if (!foundStyleRules) | |
foundNameSpaceRules = this.parseNamespaceRule(token, sheet); | |
else { | |
this.reportError(kNAMESPACE_RULE_POSITION); | |
this.addUnknownAtRule(sheet, token.value); | |
} | |
} | |
else if (token.isAtRule("@font-face")) { | |
if (this.parseFontFaceRule(token, sheet)) | |
foundStyleRules = true; | |
else | |
this.addUnknownAtRule(sheet, token.value); | |
} | |
else if (token.isAtRule("@page")) { | |
if (this.parsePageRule(token, sheet)) | |
foundStyleRules = true; | |
else | |
this.addUnknownAtRule(sheet, token.value); | |
} | |
else if (token.isAtRule("@media")) { | |
if (this.parseMediaRule(token, sheet)) | |
foundStyleRules = true; | |
else | |
this.addUnknownAtRule(sheet, token.value); | |
} | |
else if (token.isAtRule("@keyframes")) { | |
if (!this.parseKeyframesRule(token, sheet)) | |
this.addUnknownAtRule(sheet, token.value); | |
} | |
else if (token.isAtRule("@charset")) { | |
this.reportError(kCHARSET_RULE_CHARSET_SOF); | |
this.addUnknownAtRule(sheet, token.value); | |
} | |
else { | |
this.reportError(kUNKNOWN_AT_RULE); | |
this.addUnknownAtRule(sheet, token.value); | |
} | |
} | |
else // plain style rules | |
{ | |
var ruleText = this.parseStyleRule(token, sheet, false); | |
if (ruleText) | |
foundStyleRules = true; | |
} | |
token = this.getToken(false); | |
} | |
return sheet; | |
}; | |
CSSParser.prototype.parseMarginOrPaddingShorthand = function(token, aDecl, aAcceptPriority, aProperty) | |
{ | |
var top = null; | |
var bottom = null; | |
var left = null; | |
var right = null; | |
var values = []; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
if (token.isSymbol(";") | |
|| (aAcceptPriority && token.isSymbol("!")) | |
|| token.isSymbol("}")) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} | |
else if (!values.length && token.isIdent(this.kINHERIT)) { | |
values.push(token.value); | |
token = this.getToken(true, true); | |
break; | |
} | |
else if (token.isDimension() | |
|| token.isNumber("0") | |
|| token.isPercentage() | |
|| token.isIdent("auto")) { | |
values.push(token.value); | |
} | |
else | |
return ""; | |
token = this.getToken(true, true); | |
} | |
var count = values.length; | |
switch (count) { | |
case 1: | |
top = values[0]; | |
bottom = top; | |
left = top; | |
right = top; | |
break; | |
case 2: | |
top = values[0]; | |
bottom = top; | |
left = values[1]; | |
right = left; | |
break; | |
case 3: | |
top = values[0]; | |
left = values[1]; | |
right = left; | |
bottom = values[2]; | |
break; | |
case 4: | |
top = values[0]; | |
right = values[1]; | |
bottom = values[2]; | |
left = values[3]; | |
break; | |
default: | |
return ""; | |
} | |
this.forgetState(); | |
aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-top", top)); | |
aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-right", right)); | |
aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-bottom", bottom)); | |
aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-left", left)); | |
return top + " " + right + " " + bottom + " " + left; | |
}; | |
CSSParser.prototype.parseMediaQuery = function() | |
{ | |
var kCONSTRAINTS = { | |
"width": true, | |
"min-width": true, | |
"max-width": true, | |
"height": true, | |
"min-height": true, | |
"max-height": true, | |
"device-width": true, | |
"min-device-width": true, | |
"max-device-width": true, | |
"device-height": true, | |
"min-device-height": true, | |
"max-device-height": true, | |
"orientation": true, | |
"aspect-ratio": true, | |
"min-aspect-ratio": true, | |
"max-aspect-ratio": true, | |
"device-aspect-ratio": true, | |
"min-device-aspect-ratio": true, | |
"max-device-aspect-ratio": true, | |
"color": true, | |
"min-color": true, | |
"max-color": true, | |
"color-index": true, | |
"min-color-index": true, | |
"max-color-index": true, | |
"monochrome": true, | |
"min-monochrome": true, | |
"max-monochrome": true, | |
"resolution": true, | |
"min-resolution": true, | |
"max-resolution": true, | |
"scan": true, | |
"grid": true | |
}; | |
var m = {cssText: "", amplifier: "", medium: "", constraints: []}; | |
var token = this.getToken(true, true); | |
if (token.isIdent("all") || | |
token.isIdent("aural") || | |
token.isIdent("braille") || | |
token.isIdent("handheld") || | |
token.isIdent("print") || | |
token.isIdent("projection") || | |
token.isIdent("screen") || | |
token.isIdent("tty") || | |
token.isIdent("tv")) { | |
m.medium = token.value; | |
m.cssText += token.value; | |
token = this.getToken(true, true); | |
} | |
else if (token.isIdent("not") || token.isIdent("only")) { | |
m.amplifier = token.value.toLowerCase(); | |
m.cssText += token.value.toLowerCase(); | |
token = this.getToken(true, true); | |
if (token.isIdent("all") || | |
token.isIdent("aural") || | |
token.isIdent("braille") || | |
token.isIdent("handheld") || | |
token.isIdent("print") || | |
token.isIdent("projection") || | |
token.isIdent("screen") || | |
token.isIdent("tty") || | |
token.isIdent("tv")) { | |
m.cssText += " " + token.value; | |
m.medium = token.value; | |
token = this.getToken(true, true); | |
} | |
else | |
return null; | |
} | |
if (m.medium) { | |
if (!token.isNotNull()) | |
return m; | |
if (token.isIdent("and")) { | |
m.cssText += " and"; | |
token = this.getToken(true, true); | |
} | |
else if (!token.isSymbol("{")) | |
return null; | |
} | |
while (token.isSymbol("(")) { | |
token = this.getToken(true, true); | |
if (token.isIdent() && (token.value in kCONSTRAINTS)) { | |
var constraint = token.value; | |
token = this.getToken(true, true); | |
if (token.isSymbol(":")) { | |
token = this.getToken(true, true); | |
var values = []; | |
while (!token.isSymbol(")")) { | |
values.push(token.value); | |
token = this.getToken(true, true); | |
} | |
if (token.isSymbol(")")) { | |
m.constraints.push({constraint: constraint, value: values}); | |
m.cssText += " (" + constraint + ": " + values.join(" ") + ")"; | |
token = this.getToken(true, true); | |
if (token.isNotNull()) { | |
if (token.isIdent("and")) { | |
m.cssText += " and"; | |
token = this.getToken(true, true); | |
} | |
else if (!token.isSymbol("{")) | |
return null; | |
} | |
else | |
return m; | |
} | |
else | |
return null; | |
} | |
else if (token.isSymbol(")")) { | |
m.constraints.push({constraint: constraint, value: null}); | |
m.cssText += " (" + constraint + ")"; | |
token = this.getToken(true, true); | |
if (token.isNotNull()) { | |
if (token.isIdent("and")) { | |
m.cssText += " and"; | |
token = this.getToken(true, true); | |
} | |
else | |
return null; | |
} | |
else | |
return m; | |
} | |
else | |
return null; | |
} | |
else | |
return null; | |
} | |
return m; | |
}; | |
CSSParser.prototype.parseMediaRule = function(aToken, aSheet) { | |
var currentLine = CountLF(this.mScanner.getAlreadyScanned()); | |
var s = aToken.value; | |
var valid = false; | |
var mediaRule = new jscsspMediaRule(); | |
mediaRule.currentLine = currentLine; | |
this.preserveState(); | |
var token = this.getToken(true, true); | |
var foundMedia = false; | |
while (token.isNotNull()) { | |
this.ungetToken(); | |
var mediaQuery = this.parseMediaQuery(); | |
token = this.currentToken(); | |
if (mediaQuery) { | |
foundMedia = true; | |
s += " " + mediaQuery.cssText; | |
mediaRule.media.push(mediaQuery.cssText); | |
if (token.isSymbol(",")) { | |
s += ","; | |
} else { | |
if (token.isSymbol("{")) | |
break; | |
else { | |
// error... | |
token.type = jscsspToken.NULL_TYPE; | |
break; | |
} | |
} | |
} | |
else if (token.isSymbol("{")) | |
break; | |
else if (foundMedia) { | |
token.type = jscsspToken.NULL_TYPE; | |
// not a media list | |
break; | |
} | |
token = this.getToken(true, true); | |
} | |
if (token.isSymbol("{") && mediaRule.media.length) { | |
// ok let's parse style rules now... | |
s += " { "; | |
token = this.getToken(true, false); | |
while (token.isNotNull()) { | |
if (token.isComment()) { | |
if (this.mPreserveComments) { | |
s += " " + token.value; | |
var comment = new jscsspComment(); | |
comment.parsedCssText = token.value; | |
mediaRule.cssRules.push(comment); | |
} | |
} else if (token.isSymbol("}")) { | |
valid = true; | |
break; | |
} else { | |
var r = this.parseStyleRule(token, mediaRule, true); | |
if (r) | |
s += r; | |
} | |
token = this.getToken(true, false); | |
} | |
} | |
if (valid) { | |
this.forgetState(); | |
mediaRule.parsedCssText = s; | |
aSheet.cssRules.push(mediaRule); | |
return true; | |
} | |
this.restoreState(); | |
return false; | |
}; | |
CSSParser.prototype.parseNamespaceRule = function(aToken, aSheet) { | |
var currentLine = CountLF(this.mScanner.getAlreadyScanned()); | |
var s = aToken.value; | |
var valid = false; | |
this.preserveState(); | |
var token = this.getToken(true, true); | |
if (token.isNotNull()) { | |
var prefix = ""; | |
var url = ""; | |
if (token.isIdent()) { | |
prefix = token.value; | |
s += " " + prefix; | |
token = this.getToken(true, true); | |
} | |
if (token) { | |
var foundURL = false; | |
if (token.isString()) { | |
foundURL = true; | |
url = token.value; | |
s += " " + url; | |
} else if (token.isFunction("url(")) { | |
// get a url here... | |
token = this.getToken(true, true); | |
var urlContent = this.parseURL(token); | |
if (urlContent) { | |
url += "url(" + urlContent; | |
foundURL = true; | |
s += " " + urlContent; | |
} | |
} | |
} | |
if (foundURL) { | |
token = this.getToken(true, true); | |
if (token.isSymbol(";")) { | |
s += ";"; | |
this.forgetState(); | |
var rule = new jscsspNamespaceRule(); | |
rule.currentLine = currentLine; | |
rule.parsedCssText = s; | |
rule.prefix = prefix; | |
rule.url = url; | |
rule.parentStyleSheet = aSheet; | |
aSheet.cssRules.push(rule); | |
return true; | |
} | |
} | |
} | |
this.restoreState(); | |
this.addUnknownAtRule(aSheet, "@namespace"); | |
return false; | |
}; | |
CSSParser.prototype.parsePageRule = function(aToken, aSheet) { | |
var currentLine = CountLF(this.mScanner.getAlreadyScanned()); | |
var s = aToken.value; | |
var valid = false; | |
var declarations = []; | |
this.preserveState(); | |
var token = this.getToken(true, true); | |
var pageSelector = ""; | |
if (token.isSymbol(":") || token.isIdent()) { | |
if (token.isSymbol(":")) { | |
pageSelector = ":"; | |
token = this.getToken(false, false); | |
} | |
if (token.isIdent()) { | |
pageSelector += token.value; | |
s += " " + pageSelector; | |
token = this.getToken(true, true); | |
} | |
} | |
if (token.isNotNull()) { | |
// expecting block start | |
if (token.isSymbol("{")) { | |
s += " " + token.value; | |
var token = this.getToken(true, false); | |
while (true) { | |
if (token.isSymbol("}")) { | |
s += "}"; | |
valid = true; | |
break; | |
} else { | |
var d = this.parseDeclaration(token, declarations, true, true, aSheet); | |
s += ((d && declarations.length) ? " " : "") + d; | |
} | |
token = this.getToken(true, false); | |
} | |
} | |
} | |
if (valid) { | |
this.forgetState(); | |
var rule = new jscsspPageRule(); | |
rule.currentLine = currentLine; | |
rule.parsedCssText = s; | |
rule.pageSelector = pageSelector; | |
rule.declarations = declarations; | |
rule.parentStyleSheet = aSheet; | |
aSheet.cssRules.push(rule) | |
return true; | |
} | |
this.restoreState(); | |
return false; | |
}; | |
CSSParser.prototype.parsePauseShorthand = function(token, declarations, aAcceptPriority) | |
{ | |
var before = ""; | |
var after = ""; | |
var values = []; | |
var values = []; | |
while (true) { | |
if (!token.isNotNull()) | |
break; | |
if (token.isSymbol(";") | |
|| (aAcceptPriority && token.isSymbol("!")) | |
|| token.isSymbol("}")) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} | |
else if (!values.length && token.isIdent(this.kINHERIT)) { | |
values.push(token.value); | |
} | |
else if (token.isDimensionOfUnit("ms") | |
|| token.isDimensionOfUnit("s") | |
|| token.isPercentage() | |
|| token.isNumber("0")) | |
values.push(token.value); | |
else | |
return ""; | |
token = this.getToken(true, true); | |
} | |
var count = values.length; | |
switch (count) { | |
case 1: | |
before = values[0]; | |
after = before; | |
break; | |
case 2: | |
before = values[0]; | |
after = values[1]; | |
break; | |
default: | |
return ""; | |
} | |
this.forgetState(); | |
aDecl.push(this._createJscsspDeclarationFromValue("pause-before", before)); | |
aDecl.push(this._createJscsspDeclarationFromValue("pause-after", after)); | |
return before + " " + after; | |
}; | |
CSSParser.prototype.parseDefaultPropertyValue = function(token, aDecl, aAcceptPriority, descriptor, aSheet) { | |
var valueText = ""; | |
var blocks = []; | |
var foundPriority = false; | |
var values = []; | |
while (token.isNotNull()) { | |
if ((token.isSymbol(";") | |
|| token.isSymbol("}") | |
|| token.isSymbol("!")) | |
&& !blocks.length) { | |
if (token.isSymbol("}")) | |
this.ungetToken(); | |
break; | |
} | |
if (token.isIdent(this.kINHERIT)) { | |
if (values.length) { | |
return ""; | |
} | |
else { | |
valueText = this.kINHERIT; | |
var value = new jscsspVariable(kJscsspINHERIT_VALUE, aSheet); | |
values.push(value); | |
token = this.getToken(true, true); | |
break; | |
} | |
} | |
else if (token.isSymbol("{") | |
|| token.isSymbol("(") | |
|| token.isSymbol("[")) { | |
blocks.push(token.value); | |
} | |
else if (token.isSymbol("}") | |
|| token.isSymbol("]")) { | |
if (blocks.length) { | |
var ontop = blocks[blocks.length - 1]; | |
if ((token.isSymbol("}") && ontop == "{") | |
|| (token.isSymbol(")") && ontop == "(") | |
|| (token.isSymbol("]") && ontop == "[")) { | |
blocks.pop(); | |
} | |
} | |
} | |
// XXX must find a better way to store individual values | |
// probably a |values: []| field holding dimensions, percentages | |
// functions, idents, numbers and symbols, in that order. | |
if (token.isFunction()) { | |
if (token.isFunction("var(")) { | |
token = this.getToken(true, true); | |
if (token.isIdent()) { | |
var name = token.value; | |
token = this.getToken(true, true); | |
if (token.isSymbol(")")) { | |
var value = new jscsspVariable(kJscsspVARIABLE_VALUE, aSheet); | |
valueText += "var(" + name + ")"; | |
value.name = name; | |
values.push(value); | |
} | |
else | |
return ""; | |
} | |
else | |
return ""; | |
} | |
else { | |
var fn = token.value; | |
token = this.getToken(false, true); | |
var arg = this.parseFunctionArgument(token); | |
if (arg) { | |
valueText += fn + arg; | |
var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); | |
value.value = fn + arg; | |
values.push(value); | |
} | |
else | |
return ""; | |
} | |
} | |
else if (token.isSymbol("#")) { | |
var color = this.parseColor(token); | |
if (color) { | |
valueText += color; | |
var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); | |
value.value = color; | |
values.push(value); | |
} | |
else | |
return ""; | |
} | |
else if (!token.isWhiteSpace() && !token.isSymbol(",")) { | |
var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); | |
value.value = token.value; | |
values.push(value); | |
valueText += token.value; | |
} | |
else | |
valueText += token.value; | |
token = this.getToken(false, true); | |
} | |
if (values.length && valueText) { | |
this.forgetState(); | |
aDecl.push(this._createJscsspDeclarationFromValuesArray(descriptor, values, valueText)); | |
return valueText; | |
} | |
return ""; | |
}; | |
CSSParser.prototype.parseSelector = function(aToken, aParseSelectorOnly) { | |
var s = ""; | |
var specificity = {a: 0, b: 0, c: 0, d: 0}; // CSS 2.1 section 6.4.3 | |
var isFirstInChain = true; | |
var token = aToken; | |
var valid = false; | |
var combinatorFound = false; | |
while (true) { | |
if (!token.isNotNull()) { | |
if (aParseSelectorOnly) | |
return {selector: s, specificity: specificity }; | |
return ""; | |
} | |
if (!aParseSelectorOnly && token.isSymbol("{")) { | |
// end of selector | |
valid = !combinatorFound; | |
// don't unget if invalid since addUnknownRule is going to restore state anyway | |
if (valid) | |
this.ungetToken(); | |
break; | |
} | |
if (token.isSymbol(",")) { // group of selectors | |
s += token.value; | |
isFirstInChain = true; | |
combinatorFound = false; | |
token = this.getToken(false, true); | |
continue; | |
} | |
// now combinators and grouping... | |
else if (!combinatorFound | |
&& (token.isWhiteSpace() | |
|| token.isSymbol(">") | |
|| token.isSymbol("+") | |
|| token.isSymbol("~"))) { | |
if (token.isWhiteSpace()) { | |
s += " "; | |
var nextToken = this.lookAhead(true, true); | |
if (!nextToken.isNotNull()) { | |
if (aParseSelectorOnly) | |
return {selector: s, specificity: specificity }; | |
return ""; | |
} | |
if (nextToken.isSymbol(">") | |
|| nextToken.isSymbol("+") | |
|| nextToken.isSymbol("~")) { | |
token = this.getToken(true, true); | |
s += token.value + " "; | |
combinatorFound = true; | |
} | |
} | |
else { | |
s += token.value; | |
combinatorFound = true; | |
} | |
isFirstInChain = true; | |
token = this.getToken(true, true); | |
continue; | |
} | |
else { | |
var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, true); | |
if (!simpleSelector) | |
break; // error | |
s += simpleSelector.selector; | |
specificity.b += simpleSelector.specificity.b; | |
specificity.c += simpleSelector.specificity.c; | |
specificity.d += simpleSelector.specificity.d; | |
isFirstInChain = false; | |
combinatorFound = false; | |
} | |
token = this.getToken(false, true); | |
} | |
if (valid) { | |
return {selector: s, specificity: specificity }; | |
} | |
return ""; | |
}; | |
CSSParser.prototype.isPseudoElement = function(aIdent) | |
{ | |
switch (aIdent) { | |
case "first-letter": | |
case "first-line": | |
case "before": | |
case "after": | |
case "marker": | |
return true; | |
break; | |
default: | |
break; | |
} | |
return false; | |
}; | |
CSSParser.prototype.parseSimpleSelector = function(token, isFirstInChain, canNegate) | |
{ | |
var s = ""; | |
var specificity = {a: 0, b: 0, c: 0, d: 0}; // CSS 2.1 section 6.4.3 | |
if (isFirstInChain | |
&& (token.isSymbol("*") || token.isSymbol("|") || token.isIdent())) { | |
// type or universal selector | |
if (token.isSymbol("*") || token.isIdent()) { | |
// we don't know yet if it's a prefix or a universal | |
// selector | |
s += token.value; | |
var isIdent = token.isIdent(); | |
token = this.getToken(false, true); | |
if (token.isSymbol("|")) { | |
// it's a prefix | |
s += token.value; | |
token = this.getToken(false, true); | |
if (token.isIdent() || token.isSymbol("*")) { | |
// ok we now have a type element or universal | |
// selector | |
s += token.value; | |
if (token.isIdent()) | |
specificity.d++; | |
} else | |
// oops that's an error... | |
return null; | |
} else { | |
this.ungetToken(); | |
if (isIdent) | |
specificity.d++; | |
} | |
} else if (token.isSymbol("|")) { | |
s += token.value; | |
token = this.getToken(false, true); | |
if (token.isIdent() || token.isSymbol("*")) { | |
s += token.value; | |
if (token.isIdent()) | |
specificity.d++; | |
} else | |
// oops that's an error | |
return null; | |
} | |
} | |
else if (token.isSymbol(".") || token.isSymbol("#")) { | |
var isClass = token.isSymbol("."); | |
s += token.value; | |
token = this.getToken(false, true); | |
if (token.isIdent()) { | |
s += token.value; | |
if (isClass) | |
specificity.c++; | |
else | |
specificity.b++; | |
} | |
else | |
return null; | |
} | |
else if (token.isSymbol(":")) { | |
s += token.value; | |
token = this.getToken(false, true); | |
if (token.isSymbol(":")) { | |
s += token.value; | |
token = this.getToken(false, true); | |
} | |
if (token.isIdent()) { | |
s += token.value; | |
if (this.isPseudoElement(token.value)) | |
specificity.d++; | |
else | |
specificity.c++; | |
} | |
else if (token.isFunction()) { | |
s += token.value; | |
if (token.isFunction(":not(")) { | |
if (!canNegate) | |
return null; | |
token = this.getToken(true, true); | |
var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, false); | |
if (!simpleSelector) | |
return null; | |
else { | |
s += simpleSelector.selector; | |
token = this.getToken(true, true); | |
if (token.isSymbol(")")) | |
s += ")"; | |
else | |
return null; | |
} | |
specificity.c++; | |
} | |
else { | |
while (true) { | |
token = this.getToken(false, true); | |
if (token.isSymbol(")")) { | |
s += ")"; | |
break; | |
} else | |
s += token.value; | |
} | |
specificity.c++; | |
} | |
} else | |
return null; | |
} else if (token.isSymbol("[")) { | |
s += "["; | |
token = this.getToken(true, true); | |
if (token.isIdent() || token.isSymbol("*")) { | |
s += token.value; | |
var nextToken = this.getToken(true, true); | |
if (nextToken.isSymbol("|")) { | |
s += "|"; | |
token = this.getToken(true, true); | |
if (token.isIdent()) | |
s += token.value; | |
else | |
return null; | |
} else | |
this.ungetToken(); | |
} else if (token.isSymbol("|")) { | |
s += "|"; | |
token = this.getToken(true, true); | |
if (token.isIdent()) | |
s += token.value; | |
else | |
return null; | |
} | |
else | |
return null; | |
// nothing, =, *=, $=, ^=, |= | |
token = this.getToken(true, true); | |
if (token.isIncludes() | |
|| token.isDashmatch() | |
|| token.isBeginsmatch() | |
|| token.isEndsmatch() | |
|| token.isContainsmatch() | |
|| token.isSymbol("=")) { | |
s += token.value; | |
token = this.getToken(true, true); | |
if (token.isString() || token.isIdent()) { | |
s += token.value; | |
token = this.getToken(true, true); | |
} | |
else | |
return null; | |
if (token.isSymbol("]")) { | |
s += token.value; | |
specificity.c++; | |
} | |
else | |
return null; | |
} | |
else if (token.isSymbol("]")) { | |
s += token.value; | |
specificity.c++; | |
} | |
else | |
return null; | |
} | |
else if (token.isWhiteSpace()) { | |
var t = this.lookAhead(true, true); | |
if (t.isSymbol('{')) | |
return "" | |
} | |
if (s) | |
return {selector: s, specificity: specificity }; | |
return null; | |
}; | |
CSSParser.prototype.trim11 = function(str) { | |
str = str.replace(/^\s+/, ''); | |
for (var i = str.length - 1; i >= 0; i--) { | |
if (/\S/.test( str.charAt(i) )) { // XXX charat | |
str = str.substring(0, i + 1); | |
break; | |
} | |
} | |
return str; | |
}; | |
CSSParser.prototype.parseStyleRule = function(aToken, aOwner, aIsInsideMediaRule) | |
{ | |
var currentLine = CountLF(this.mScanner.getAlreadyScanned()); | |
this.preserveState(); | |
// first let's see if we have a selector here... | |
var selector = this.parseSelector(aToken, false); | |
var valid = false; | |
var declarations = []; | |
if (selector) { | |
selector = this.trim11(selector.selector); | |
var s = selector; | |
var token = this.getToken(true, true); | |
if (token.isSymbol("{")) { | |
s += " { "; | |
var token = this.getToken(true, false); | |
while (true) { | |
if (!token.isNotNull()) { | |
valid = true; | |
break; | |
} | |
if (token.isSymbol("}")) { | |
s += "}"; | |
valid = true; | |
break; | |
} else { | |
var d = this.parseDeclaration(token, declarations, true, true, aOwner); | |
s += ((d && declarations.length) ? " " : "") + d; | |
} | |
token = this.getToken(true, false); | |
} | |
} | |
} | |
else { | |
// selector is invalid so the whole rule is invalid with it | |
} | |
if (valid) { | |
var rule = new jscsspStyleRule(); | |
rule.currentLine = currentLine; | |
rule.parsedCssText = s; | |
rule.declarations = declarations; | |
rule.mSelectorText = selector; | |
if (aIsInsideMediaRule) | |
rule.parentRule = aOwner; | |
else | |
rule.parentStyleSheet = aOwner; | |
aOwner.cssRules.push(rule); | |
return s; | |
} | |
this.restoreState(); | |
s = this.currentToken().value; | |
this.addUnknownAtRule(aOwner, s); | |
return ""; | |
}; | |
CSSParser.prototype.parseTextShadows = function() | |
{ | |
var shadows = []; | |
var token = this.getToken(true, true); | |
var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px"; | |
while (token.isNotNull()) { | |
if (token.isIdent("none")) { | |
shadows.push( { none: true } ); | |
token = this.getToken(true, true); | |
} | |
else { | |
if (token.isFunction("rgb(") || | |
token.isFunction("rgba(") || | |
token.isFunction("hsl(") || | |
token.isFunction("hsla(") || | |
token.isSymbol("#") || | |
token.isIdent()) { | |
var color = this.parseColor(token); | |
token = this.getToken(true, true); | |
} | |
if (token.isPercentage() || | |
token.isDimensionOfUnit("cm") || | |
token.isDimensionOfUnit("mm") || | |
token.isDimensionOfUnit("in") || | |
token.isDimensionOfUnit("pc") || | |
token.isDimensionOfUnit("px") || | |
token.isDimensionOfUnit("em") || | |
token.isDimensionOfUnit("ex") || | |
token.isDimensionOfUnit("pt")) { | |
var offsetX = token.value; | |
token = this.getToken(true, true); | |
} | |
else | |
return []; | |
if (token.isPercentage() || | |
token.isDimensionOfUnit("cm") || | |
token.isDimensionOfUnit("mm") || | |
token.isDimensionOfUnit("in") || | |
token.isDimensionOfUnit("pc") || | |
token.isDimensionOfUnit("px") || | |
token.isDimensionOfUnit("em") || | |
token.isDimensionOfUnit("ex") || | |
token.isDimensionOfUnit("pt")) { | |
var offsetY = token.value; | |
token = this.getToken(true, true); | |
} | |
else | |
return []; | |
if (token.isPercentage() || | |
token.isDimensionOfUnit("cm") || | |
token.isDimensionOfUnit("mm") || | |
token.isDimensionOfUnit("in") || | |
token.isDimensionOfUnit("pc") || | |
token.isDimensionOfUnit("px") || | |
token.isDimensionOfUnit("em") || | |
token.isDimensionOfUnit("ex") || | |
token.isDimensionOfUnit("pt")) { | |
var blurRadius = token.value; | |
token = this.getToken(true, true); | |
} | |
if (!color && | |
(token.isFunction("rgb(") || | |
token.isFunction("rgba(") || | |
token.isFunction("hsl(") || | |
token.isFunction("hsla(") || | |
token.isSymbol("#") || | |
token.isIdent())) { | |
var color = this.parseColor(token); | |
token = this.getToken(true, true); | |
} | |
shadows.push( { none: false, | |
color: color, | |
offsetX: offsetX, offsetY: offsetY, | |
blurRadius: blurRadius } ); | |
if (token.isSymbol(",")) { | |
color = ""; | |
blurRadius = "0px"; | |
offsetX = "0px"; | |
offsetY = "0px"; | |
token = this.getToken(true, true); | |
} | |
else if (!token.isNotNull()) | |
return shadows; | |
else | |
return []; | |
} | |
} | |
return shadows; | |
}; | |
CSSParser.prototype.currentToken = function() { | |
return this.mToken; | |
}; | |
CSSParser.prototype.getHexValue = function() { | |
this.mToken = this.mScanner.nextHexValue(); | |
return this.mToken; | |
}; | |
CSSParser.prototype.getToken = function(aSkipWS, aSkipComment) { | |
if (this.mLookAhead) { | |
this.mToken = this.mLookAhead; | |
this.mLookAhead = null; | |
return this.mToken; | |
} | |
this.mToken = this.mScanner.nextToken(); | |
while (this.mToken && | |
((aSkipWS && this.mToken.isWhiteSpace()) || | |
(aSkipComment && this.mToken.isComment()))) | |
this.mToken = this.mScanner.nextToken(); | |
return this.mToken; | |
}; | |
CSSParser.prototype.lookAhead = function(aSkipWS, aSkipComment) { | |
var preservedToken = this.mToken; | |
this.mScanner.preserveState(); | |
var token = this.getToken(aSkipWS, aSkipComment); | |
this.mScanner.restoreState(); | |
this.mToken = preservedToken; | |
return token; | |
}; | |
CSSParser.prototype.ungetToken = function() { | |
this.mLookAhead = this.mToken; | |
}; | |
CSSParser.prototype.addWhitespace = function(aSheet, aString) { | |
var rule = new jscsspWhitespace(); | |
rule.parsedCssText = aString; | |
rule.parentStyleSheet = aSheet; | |
aSheet.cssRules.push(rule); | |
}; | |
CSSParser.prototype.addComment = function(aSheet, aString) { | |
var rule = new jscsspComment(); | |
rule.parsedCssText = aString; | |
rule.parentStyleSheet = aSheet; | |
aSheet.cssRules.push(rule); | |
}; | |
CSSParser.prototype._createJscsspDeclaration = function(property, value) | |
{ | |
var decl = new jscsspDeclaration(); | |
decl.property = property; | |
decl.value = this.trim11(value); | |
decl.parsedCssText = property + ": " + value + ";"; | |
return decl; | |
}; | |
CSSParser.prototype._createJscsspDeclarationFromValue = function(property, valueText) | |
{ | |
var decl = new jscsspDeclaration(); | |
decl.property = property; | |
var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null); | |
value.value = valueText; | |
decl.values = [value]; | |
decl.valueText = valueText; | |
decl.parsedCssText = property + ": " + valueText + ";"; | |
return decl; | |
}; | |
CSSParser.prototype._createJscsspDeclarationFromValuesArray = function(property, values, valueText) | |
{ | |
var decl = new jscsspDeclaration(); | |
decl.property = property; | |
decl.values = values; | |
decl.valueText = valueText; | |
decl.parsedCssText = property + ": " + valueText + ";"; | |
return decl; | |
}; | |
CSSParser.prototype.preserveState = function() { | |
this.mPreservedTokens.push(this.currentToken()); | |
this.mScanner.preserveState(); | |
}; | |
CSSParser.prototype.restoreState = function() { | |
if (this.mPreservedTokens.length) { | |
this.mScanner.restoreState(); | |
this.mToken = this.mPreservedTokens.pop(); | |
} | |
}; | |
CSSParser.prototype.forgetState = function() { | |
if (this.mPreservedTokens.length) { | |
this.mScanner.forgetState(); | |
this.mPreservedTokens.pop(); | |
} | |
}; | |
CSSParser.prototype.addUnknownAtRule = function(aSheet, aString) { | |
var currentLine = CountLF(this.mScanner.getAlreadyScanned()); | |
var blocks = []; | |
var token = this.getToken(false, false); | |
while (token.isNotNull()) { | |
aString += token.value; | |
if (token.isSymbol(";") && !blocks.length) | |
break; | |
else if (token.isSymbol("{") | |
|| token.isSymbol("(") | |
|| token.isSymbol("[") | |
|| token.type == "function") { | |
blocks.push(token.isFunction() ? "(" : token.value); | |
} else if (token.isSymbol("}") | |
|| token.isSymbol(")") | |
|| token.isSymbol("]")) { | |
if (blocks.length) { | |
var ontop = blocks[blocks.length - 1]; | |
if ((token.isSymbol("}") && ontop == "{") | |
|| (token.isSymbol(")") && ontop == "(") | |
|| (token.isSymbol("]") && ontop == "[")) { | |
blocks.pop(); | |
if (!blocks.length && token.isSymbol("}")) | |
break; | |
} | |
} | |
} | |
token = this.getToken(false, false); | |
} | |
this.addUnknownRule(aSheet, aString, currentLine); | |
}; | |
CSSParser.prototype.addUnknownRule = function(aSheet, aString, aCurrentLine) { | |
var errorMsg = this.consumeError(); | |
var rule = new jscsspErrorRule(errorMsg); | |
rule.currentLine = aCurrentLine; | |
rule.parsedCssText = aString; | |
rule.parentStyleSheet = aSheet; | |
aSheet.cssRules.push(rule); | |
}; | |
CSSParser.prototype.parseURL = function(token) | |
{ | |
var value = ""; | |
if (token.isString()) | |
{ | |
value += token.value; | |
token = this.getToken(true, true); | |
} | |
else | |
while (true) | |
{ | |
if (!token.isNotNull()) { | |
this.reportError(kURL_EOF); | |
return ""; | |
} | |
if (token.isWhiteSpace()) { | |
nextToken = this.lookAhead(true, true); | |
// if next token is not a closing parenthesis, that's an error | |
if (!nextToken.isSymbol(")")) { | |
this.reportError(kURL_WS_INSIDE); | |
token = this.currentToken(); | |
break; | |
} | |
} | |
if (token.isSymbol(")")) { | |
break; | |
} | |
value += token.value; | |
token = this.getToken(false, false); | |
} | |
if (token.isSymbol(")")) { | |
return value + ")"; | |
} | |
return ""; | |
}; | |
CSSParser.prototype.parseVariablesRule = function(token, aSheet) { | |
var currentLine = CountLF(this.mScanner.getAlreadyScanned()); | |
var s = token.value; | |
var declarations = []; | |
var valid = false; | |
this.preserveState(); | |
token = this.getToken(true, true); | |
var media = []; | |
var foundMedia = false; | |
while (token.isNotNull()) { | |
if (token.isIdent()) { | |
foundMedia = true; | |
s += " " + token.value; | |
media.push(token.value); | |
token = this.getToken(true, true); | |
if (token.isSymbol(",")) { | |
s += ","; | |
} else { | |
if (token.isSymbol("{")) | |
this.ungetToken(); | |
else { | |
// error... | |
token.type = jscsspToken.NULL_TYPE; | |
break; | |
} | |
} | |
} else if (token.isSymbol("{")) | |
break; | |
else if (foundMedia) { | |
token.type = jscsspToken.NULL_TYPE; | |
// not a media list | |
break; | |
} | |
token = this.getToken(true, true); | |
} | |
if (token.isSymbol("{")) { | |
s += " {"; | |
token = this.getToken(true, true); | |
while (true) { | |
if (!token.isNotNull()) { | |
valid = true; | |
break; | |
} | |
if (token.isSymbol("}")) { | |
s += "}"; | |
valid = true; | |
break; | |
} else { | |
var d = this.parseDeclaration(token, declarations, true, false, aSheet); | |
s += ((d && declarations.length) ? " " : "") + d; | |
} | |
token = this.getToken(true, false); | |
} | |
} | |
if (valid) { | |
this.forgetState(); | |
var rule = new jscsspVariablesRule(); | |
rule.currentLine = currentLine; | |
rule.parsedCssText = s; | |
rule.declarations = declarations; | |
rule.media = media; | |
rule.parentStyleSheet = aSheet; | |
aSheet.cssRules.push(rule) | |
return true; | |
} | |
this.restoreState(); | |
return false; | |
}; | |
function jscsspToken(aType, aValue, aUnit) | |
{ | |
this.type = aType; | |
this.value = aValue; | |
this.unit = aUnit; | |
} | |
jscsspToken.NULL_TYPE = 0; | |
jscsspToken.WHITESPACE_TYPE = 1; | |
jscsspToken.STRING_TYPE = 2; | |
jscsspToken.COMMENT_TYPE = 3; | |
jscsspToken.NUMBER_TYPE = 4; | |
jscsspToken.IDENT_TYPE = 5; | |
jscsspToken.FUNCTION_TYPE = 6; | |
jscsspToken.ATRULE_TYPE = 7; | |
jscsspToken.INCLUDES_TYPE = 8; | |
jscsspToken.DASHMATCH_TYPE = 9; | |
jscsspToken.BEGINSMATCH_TYPE = 10; | |
jscsspToken.ENDSMATCH_TYPE = 11; | |
jscsspToken.CONTAINSMATCH_TYPE = 12; | |
jscsspToken.SYMBOL_TYPE = 13; | |
jscsspToken.DIMENSION_TYPE = 14; | |
jscsspToken.PERCENTAGE_TYPE = 15; | |
jscsspToken.HEX_TYPE = 16; | |
jscsspToken.prototype = { | |
isNotNull: function () | |
{ | |
return this.type; | |
}, | |
_isOfType: function (aType, aValue) | |
{ | |
return (this.type == aType && (!aValue || this.value.toLowerCase() == aValue)); | |
}, | |
isWhiteSpace: function(w) | |
{ | |
return this._isOfType(jscsspToken.WHITESPACE_TYPE, w); | |
}, | |
isString: function() | |
{ | |
return this._isOfType(jscsspToken.STRING_TYPE); | |
}, | |
isComment: function() | |
{ | |
return this._isOfType(jscsspToken.COMMENT_TYPE); | |
}, | |
isNumber: function(n) | |
{ | |
return this._isOfType(jscsspToken.NUMBER_TYPE, n); | |
}, | |
isIdent: function(i) | |
{ | |
return this._isOfType(jscsspToken.IDENT_TYPE, i); | |
}, | |
isFunction: function(f) | |
{ | |
return this._isOfType(jscsspToken.FUNCTION_TYPE, f); | |
}, | |
isAtRule: function(a) | |
{ | |
return this._isOfType(jscsspToken.ATRULE_TYPE, a); | |
}, | |
isIncludes: function() | |
{ | |
return this._isOfType(jscsspToken.INCLUDES_TYPE); | |
}, | |
isDashmatch: function() | |
{ | |
return this._isOfType(jscsspToken.DASHMATCH_TYPE); | |
}, | |
isBeginsmatch: function() | |
{ | |
return this._isOfType(jscsspToken.BEGINSMATCH_TYPE); | |
}, | |
isEndsmatch: function() | |
{ | |
return this._isOfType(jscsspToken.ENDSMATCH_TYPE); | |
}, | |
isContainsmatch: function() | |
{ | |
return this._isOfType(jscsspToken.CONTAINSMATCH_TYPE); | |
}, | |
isSymbol: function(c) | |
{ | |
return this._isOfType(jscsspToken.SYMBOL_TYPE, c); | |
}, | |
isDimension: function() | |
{ | |
return this._isOfType(jscsspToken.DIMENSION_TYPE); | |
}, | |
isPercentage: function() | |
{ | |
return this._isOfType(jscsspToken.PERCENTAGE_TYPE); | |
}, | |
isHex: function() | |
{ | |
return this._isOfType(jscsspToken.HEX_TYPE); | |
}, | |
isDimensionOfUnit: function(aUnit) | |
{ | |
return (this.isDimension() && this.unit == aUnit); | |
}, | |
isLength: function() | |
{ | |
return (this.isPercentage() || | |
this.isDimensionOfUnit("cm") || | |
this.isDimensionOfUnit("mm") || | |
this.isDimensionOfUnit("in") || | |
this.isDimensionOfUnit("pc") || | |
this.isDimensionOfUnit("px") || | |
this.isDimensionOfUnit("em") || | |
this.isDimensionOfUnit("ex") || | |
this.isDimensionOfUnit("pt")); | |
}, | |
isAngle: function() | |
{ | |
return (this.isDimensionOfUnit("deg") || | |
this.isDimensionOfUnit("rad") || | |
this.isDimensionOfUnit("grad")); | |
} | |
} | |
/* kJscsspCHARSET_RULE */ | |
function jscsspCharsetRule() | |
{ | |
this.type = kJscsspCHARSET_RULE; | |
this.encoding = null; | |
this.parsedCssText = null; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspCharsetRule.prototype = { | |
cssText: function() { | |
return "@charset " + this.encoding + ";"; | |
}, | |
setCssText: function(val) { | |
var sheet = {cssRules: []}; | |
var parser = new CSSParser(val); | |
if (parser.parseCharsetRule(sheet)) { | |
var newRule = sheet.cssRules[0]; | |
this.encoding = newRule.encoding; | |
this.parsedCssText = newRule.parsedCssText; | |
return; | |
} | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
/* kJscsspCOMMENT */ | |
function jscsspComment() | |
{ | |
this.type = kJscsspCOMMENT; | |
this.parsedCssText = null; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspComment.prototype = { | |
cssText: function() { | |
return this.parsedCssText; | |
}, | |
setCssText: function(val) { | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, false); | |
if (token.isComment()) | |
this.parsedCssText = token.value; | |
else | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
/* kJscsspSTYLE_DECLARATION */ | |
function jscsspDeclaration() | |
{ | |
this.type = kJscsspSTYLE_DECLARATION; | |
this.property = null; | |
this.values = []; | |
this.valueText = null; | |
this.priority = null; | |
this.parsedCssText = null; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspDeclaration.prototype = { | |
kCOMMA_SEPARATED: { | |
"cursor": true, | |
"font-family": true, | |
"voice-family": true, | |
"background-image": true | |
}, | |
kUNMODIFIED_COMMA_SEPARATED_PROPERTIES: { | |
"text-shadow": true, | |
"box-shadow": true, | |
"-moz-transition": true, | |
"-moz-transition-property": true, | |
"-moz-transition-duration": true, | |
"-moz-transition-timing-function": true, | |
"-moz-transition-delay": true, | |
"src": true, | |
"-moz-font-feature-settings": true | |
}, | |
cssText: function() { | |
var prefixes = PrefixHelper.prefixesForProperty(this.property); | |
var rv = ""; | |
if (this.property in this.kUNMODIFIED_COMMA_SEPARATED_PROPERTIES) { | |
if (prefixes) { | |
rv = ""; | |
for (var propertyIndex = 0; propertyIndex < prefixes.length; propertyIndex++) { | |
var property = prefixes[propertyIndex]; | |
rv += (propertyIndex ? gTABS : "") + property + ": "; | |
rv += this.valueText + (this.priority ? " !important" : "") + ";"; | |
rv += ((prefixes.length > 1 && propertyIndex != prefixes.length -1) ? "\n" : ""); | |
} | |
return rv; | |
} | |
return this.property + ": " + this.valueText + | |
(this.priority ? " !important" : "") + ";" | |
} | |
if (prefixes) { | |
rv = ""; | |
for (var propertyIndex = 0; propertyIndex < prefixes.length; propertyIndex++) { | |
var property = prefixes[propertyIndex]; | |
rv += (propertyIndex ? gTABS : "") + property + ": "; | |
var separator = (property in this.kCOMMA_SEPARATED) ? ", " : " "; | |
for (var i = 0; i < this.values.length; i++) | |
if (this.values[i].cssText() != null) | |
rv += (i ? separator : "") + this.values[i].cssText(); | |
else | |
return null; | |
rv += (this.priority ? " !important" : "") + ";" + | |
((prefixes.length > 1 && propertyIndex != prefixes.length -1) ? "\n" : ""); | |
} | |
return rv; | |
} | |
var separator = (this.property in this.kCOMMA_SEPARATED) ? ", " : " "; | |
var extras = {"webkit": false, "presto": false, "trident": false, "gecko1.9.2": false, "generic": false } | |
for (var i = 0; i < this.values.length; i++) { | |
var v = this.values[i].cssText(); | |
if (v != null) { | |
var paren = v.indexOf("("); | |
var kwd = v; | |
if (paren != -1) | |
kwd = v.substr(0, paren); | |
if (kwd in kCSS_VENDOR_VALUES) { | |
for (var j in kCSS_VENDOR_VALUES[kwd]) { | |
extras[j] = extras[j] || (kCSS_VENDOR_VALUES[kwd][j] != ""); | |
} | |
} | |
} | |
else | |
return null; | |
} | |
for (var j in extras) { | |
if (extras[j]) { | |
var str = "\n" + gTABS + this.property + ": "; | |
for (var i = 0; i < this.values.length; i++) { | |
var v = this.values[i].cssText(); | |
if (v != null) { | |
var paren = v.indexOf("("); | |
var kwd = v; | |
if (paren != -1) | |
kwd = v.substr(0, paren); | |
if (kwd in kCSS_VENDOR_VALUES) { | |
functor = kCSS_VENDOR_VALUES[kwd][j]; | |
if (functor) { | |
v = (typeof functor == "string") ? functor : functor(v, j); | |
if (!v) { | |
str = null; | |
break; | |
} | |
} | |
} | |
str += (i ? separator : "") + v; | |
} | |
else | |
return null; | |
} | |
if (str) | |
rv += str + ";" | |
else | |
rv += "\n" + gTABS + "/* Impossible to translate property " + this.property + " for " + j + " */"; | |
} | |
} | |
rv += "\n" + gTABS + this.property + ": "; | |
for (var i = 0; i < this.values.length; i++) { | |
var v = this.values[i].cssText(); | |
if (v != null) { | |
rv += (i ? separator : "") + v; | |
} | |
} | |
rv += (this.priority ? " !important" : "") + ";"; | |
return rv; | |
}, | |
setCssText: function(val) { | |
var declarations = []; | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, true); | |
if (parser.parseDeclaration(token, declarations, true, true, null) | |
&& declarations.length | |
&& declarations[0].type == kJscsspSTYLE_DECLARATION) { | |
var newDecl = declarations.cssRules[0]; | |
this.property = newDecl.property; | |
this.value = newDecl.value; | |
this.priority = newDecl.priority; | |
this.parsedCssText = newRule.parsedCssText; | |
return; | |
} | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
/* kJscsspUNKNOWN_RULE */ | |
function jscsspErrorRule(aErrorMsg) | |
{ | |
this.error = aErrorMsg ? aErrorMsg : "INVALID"; | |
this.type = kJscsspUNKNOWN_RULE; | |
this.parsedCssText = null; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspErrorRule.prototype = { | |
cssText: function() { | |
return this.parsedCssText; | |
} | |
}; | |
/* kJscsspFONT_FACE_RULE */ | |
function jscsspFontFaceRule() | |
{ | |
this.type = kJscsspFONT_FACE_RULE; | |
this.parsedCssText = null; | |
this.descriptors = []; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspFontFaceRule.prototype = { | |
cssText: function() { | |
var rv = gTABS + "@font-face {\n"; | |
var preservedGTABS = gTABS; | |
gTABS += " "; | |
for (var i = 0; i < this.descriptors.length; i++) | |
rv += gTABS + this.descriptors[i].cssText() + "\n"; | |
gTABS = preservedGTABS; | |
return rv + gTABS + "}"; | |
}, | |
setCssText: function(val) { | |
var sheet = {cssRules: []}; | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, true); | |
if (token.isAtRule("@font-face")) { | |
if (parser.parseFontFaceRule(token, sheet)) { | |
var newRule = sheet.cssRules[0]; | |
this.descriptors = newRule.descriptors; | |
this.parsedCssText = newRule.parsedCssText; | |
return; | |
} | |
} | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
/* kJscsspIMPORT_RULE */ | |
function jscsspImportRule() | |
{ | |
this.type = kJscsspIMPORT_RULE; | |
this.parsedCssText = null; | |
this.href = null; | |
this.media = []; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspImportRule.prototype = { | |
cssText: function() { | |
var mediaString = this.media.join(", "); | |
return "@import " + this.href | |
+ ((mediaString && mediaString != "all") ? mediaString + " " : "") | |
+ ";"; | |
}, | |
setCssText: function(val) { | |
var sheet = {cssRules: []}; | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, true); | |
if (token.isAtRule("@import")) { | |
if (parser.parseImportRule(token, sheet)) { | |
var newRule = sheet.cssRules[0]; | |
this.href = newRule.href; | |
this.media = newRule.media; | |
this.parsedCssText = newRule.parsedCssText; | |
return; | |
} | |
} | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
/* kJscsspKEYFRAME_RULE */ | |
function jscsspKeyframeRule() | |
{ | |
this.type = kJscsspKEYFRAME_RULE; | |
this.parsedCssText = null; | |
this.declarations = [] | |
this.keyText = null; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspKeyframeRule.prototype = { | |
cssText: function() { | |
var rv = this.keyText + " {\n"; | |
var preservedGTABS = gTABS; | |
gTABS += " "; | |
for (var i = 0; i < this.declarations.length; i++) { | |
var declText = this.declarations[i].cssText(); | |
if (declText) | |
rv += gTABS + this.declarations[i].cssText() + "\n"; | |
} | |
gTABS = preservedGTABS; | |
return rv + gTABS + "}"; | |
}, | |
setCssText: function(val) { | |
var sheet = {cssRules: []}; | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, true); | |
if (!token.isNotNull()) { | |
if (parser.parseKeyframeRule(token, sheet, false)) { | |
var newRule = sheet.cssRules[0]; | |
this.keyText = newRule.keyText; | |
this.declarations = newRule.declarations; | |
this.parsedCssText = newRule.parsedCssText; | |
return; | |
} | |
} | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
/* kJscsspKEYFRAMES_RULE */ | |
function jscsspKeyframesRule() | |
{ | |
this.type = kJscsspKEYFRAMES_RULE; | |
this.parsedCssText = null; | |
this.cssRules = []; | |
this.name = null; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspKeyframesRule.prototype = { | |
cssText: function() { | |
var rv = ""; | |
var prefixes = ["moz", "webkit", "ms", "o", ""]; | |
for (var p = 0; p < prefixes.length; p++) { | |
rv += gTABS | |
+ "@" + (prefixes[p] ? "-" + prefixes[p] + "-" : "") + "keyframes " | |
+ this.name + " {\n"; | |
var preservedGTABS = gTABS; | |
gTABS += " "; | |
for (var i = 0; i < this.cssRules.length; i++) | |
rv += gTABS + this.cssRules[i].cssText() + "\n"; | |
gTABS = preservedGTABS; | |
rv += gTABS + "}\n\n"; | |
} | |
return rv; | |
}, | |
setCssText: function(val) { | |
var sheet = {cssRules: []}; | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, true); | |
if (token.isAtRule("@-mozkeyframes")) { | |
if (parser.parseKeyframesRule(token, sheet)) { | |
var newRule = sheet.cssRules[0]; | |
this.cssRules = newRule.cssRules; | |
this.name = newRule.name; | |
this.parsedCssText = newRule.parsedCssText; | |
return; | |
} | |
} | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
/* kJscsspMEDIA_RULE */ | |
function jscsspMediaRule() | |
{ | |
this.type = kJscsspMEDIA_RULE; | |
this.parsedCssText = null; | |
this.cssRules = []; | |
this.media = []; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspMediaRule.prototype = { | |
cssText: function() { | |
var rv = gTABS + "@media " + this.media.join(", ") + " {\n"; | |
var preservedGTABS = gTABS; | |
gTABS += " "; | |
for (var i = 0; i < this.cssRules.length; i++) | |
rv += this.cssRules[i].cssText() + "\n"; | |
gTABS = preservedGTABS; | |
return rv + gTABS + "}"; | |
}, | |
setCssText: function(val) { | |
var sheet = {cssRules: []}; | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, true); | |
if (token.isAtRule("@media")) { | |
if (parser.parseMediaRule(token, sheet)) { | |
var newRule = sheet.cssRules[0]; | |
this.cssRules = newRule.cssRules; | |
this.media = newRule.media; | |
this.parsedCssText = newRule.parsedCssText; | |
return; | |
} | |
} | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
/* kJscsspNAMESPACE_RULE */ | |
function jscsspNamespaceRule() | |
{ | |
this.type = kJscsspNAMESPACE_RULE; | |
this.parsedCssText = null; | |
this.prefix = null; | |
this.url = null; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspNamespaceRule.prototype = { | |
cssText: function() { | |
return "@namespace " + (this.prefix ? this.prefix + " ": "") | |
+ this.url | |
+ ";"; | |
}, | |
setCssText: function(val) { | |
var sheet = {cssRules: []}; | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, true); | |
if (token.isAtRule("@namespace")) { | |
if (parser.parseNamespaceRule(token, sheet)) { | |
var newRule = sheet.cssRules[0]; | |
this.url = newRule.url; | |
this.prefix = newRule.prefix; | |
this.parsedCssText = newRule.parsedCssText; | |
return; | |
} | |
} | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
/* kJscsspPAGE_RULE */ | |
function jscsspPageRule() | |
{ | |
this.type = kJscsspPAGE_RULE; | |
this.parsedCssText = null; | |
this.pageSelector = null; | |
this.declarations = []; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspPageRule.prototype = { | |
cssText: function() { | |
var rv = gTABS + "@page " | |
+ (this.pageSelector ? this.pageSelector + " ": "") | |
+ "{\n"; | |
var preservedGTABS = gTABS; | |
gTABS += " "; | |
for (var i = 0; i < this.declarations.length; i++) | |
rv += gTABS + this.declarations[i].cssText() + "\n"; | |
gTABS = preservedGTABS; | |
return rv + gTABS + "}"; | |
}, | |
setCssText: function(val) { | |
var sheet = {cssRules: []}; | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, true); | |
if (token.isAtRule("@page")) { | |
if (parser.parsePageRule(token, sheet)) { | |
var newRule = sheet.cssRules[0]; | |
this.pageSelector = newRule.pageSelector; | |
this.declarations = newRule.declarations; | |
this.parsedCssText = newRule.parsedCssText; | |
return; | |
} | |
} | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
/* kJscsspSTYLE_RULE */ | |
function jscsspStyleRule() | |
{ | |
this.type = kJscsspSTYLE_RULE; | |
this.parsedCssText = null; | |
this.declarations = [] | |
this.mSelectorText = null; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspStyleRule.prototype = { | |
cssText: function() { | |
var rv = gTABS + this.mSelectorText + " {"; | |
var preservedGTABS = gTABS; | |
gTABS += " "; | |
for (var i = 0; i < this.declarations.length; i++) { | |
var declText = this.declarations[i].cssText(); | |
if (declText) | |
rv += gTABS + this.declarations[i].cssText() ; | |
} | |
gTABS = preservedGTABS; | |
return rv + "\n" + gTABS + "}"; | |
}, | |
setCssText: function(val) { | |
var sheet = {cssRules: []}; | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, true); | |
if (!token.isNotNull()) { | |
if (parser.parseStyleRule(token, sheet, false)) { | |
var newRule = sheet.cssRules[0]; | |
this.mSelectorText = newRule.mSelectorText; | |
this.declarations = newRule.declarations; | |
this.parsedCssText = newRule.parsedCssText; | |
return; | |
} | |
} | |
throw DOMException.SYNTAX_ERR; | |
}, | |
selectorText: function() { | |
return this.mSelectorText; | |
}, | |
setSelectorText: function(val) { | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, true); | |
if (!token.isNotNull()) { | |
var s = parser.parseSelector(token, true); | |
if (s) { | |
this.mSelectorText = s.selector; | |
return; | |
} | |
} | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
function jscsspStylesheet() | |
{ | |
this.cssRules = []; | |
this.variables = {}; | |
} | |
jscsspStylesheet.prototype = { | |
insertRule: function(aRule, aIndex) { | |
try { | |
this.cssRules.splice(aIndex, 1, aRule); | |
} | |
catch(e) { | |
} | |
}, | |
deleteRule: function(aIndex) { | |
try { | |
this.cssRules.splice(aIndex); | |
} | |
catch(e) { | |
} | |
}, | |
cssText: function() { | |
var rv = ""; | |
for (var i = 0; i < this.cssRules.length; i++) | |
rv += this.cssRules[i].cssText() + "\n\n"; | |
return rv; | |
} | |
}; | |
var kJscsspINHERIT_VALUE = 0; | |
var kJscsspPRIMITIVE_VALUE = 1; | |
var kJscsspVARIABLE_VALUE = 4; | |
function jscsspVariable(aType, aSheet) | |
{ | |
this.value = ""; | |
this.type = aType; | |
this.name = null; | |
this.parentRule = null; | |
this.parentStyleSheet = aSheet; | |
} | |
jscsspVariable.prototype = { | |
cssText: function() { | |
if (this.type == kJscsspVARIABLE_VALUE) | |
return this.resolveVariable(this.name, this.parentRule, this.parentStyleSheet); | |
else | |
return this.value; | |
}, | |
setCssText: function(val) { | |
if (this.type == kJscsspVARIABLE_VALUE) | |
throw DOMException.SYNTAX_ERR; | |
else | |
this.value = val; | |
}, | |
resolveVariable: function(aName, aRule, aSheet) | |
{ | |
return "var(" + aName + ")"; | |
} | |
}; | |
/* kJscsspVARIABLES_RULE */ | |
function jscsspVariablesRule() | |
{ | |
this.type = kJscsspVARIABLES_RULE; | |
this.parsedCssText = null; | |
this.declarations = []; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
this.media = null; | |
} | |
jscsspVariablesRule.prototype = { | |
cssText: function() { | |
var rv = gTABS + "@variables " + | |
(this.media.length ? this.media.join(", ") + " " : "") + | |
"{\n"; | |
var preservedGTABS = gTABS; | |
gTABS += " "; | |
for (var i = 0; i < this.declarations.length; i++) | |
rv += gTABS + this.declarations[i].cssText() + "\n"; | |
gTABS = preservedGTABS; | |
return rv + gTABS + "}"; | |
}, | |
setCssText: function(val) { | |
var sheet = {cssRules: []}; | |
var parser = new CSSParser(val); | |
var token = parser.getToken(true, true); | |
if (token.isAtRule("@variables")) { | |
if (parser.parseVariablesRule(token, sheet)) { | |
var newRule = sheet.cssRules[0]; | |
this.declarations = newRule.declarations; | |
this.parsedCssText = newRule.parsedCssText; | |
return; | |
} | |
} | |
throw DOMException.SYNTAX_ERR; | |
} | |
}; | |
/* kJscsspWHITE_SPACE */ | |
function jscsspWhitespace() | |
{ | |
this.type = kJscsspWHITE_SPACE; | |
this.parsedCssText = null; | |
this.parentStyleSheet = null; | |
this.parentRule = null; | |
} | |
jscsspWhitespace.prototype = { | |
cssText: function() { | |
return this.parsedCssText; | |
} | |
}; | |
var kJscsspUNKNOWN_RULE = 0; | |
var kJscsspSTYLE_RULE = 1 | |
var kJscsspCHARSET_RULE = 2; | |
var kJscsspIMPORT_RULE = 3; | |
var kJscsspMEDIA_RULE = 4; | |
var kJscsspFONT_FACE_RULE = 5; | |
var kJscsspPAGE_RULE = 6; | |
var kJscsspKEYFRAMES_RULE = 7; | |
var kJscsspKEYFRAME_RULE = 8; | |
var kJscsspNAMESPACE_RULE = 100; | |
var kJscsspCOMMENT = 101; | |
var kJscsspWHITE_SPACE = 102; | |
var kJscsspVARIABLES_RULE = 200; | |
var kJscsspSTYLE_DECLARATION = 1000; | |
var gTABS = ""; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment