1 /*! 2 * wef.cssParser 3 * Copyright (c) 2011 Pablo Escalada 4 * MIT Licensed 5 * 6 * Uses a lightly modified version of JSCSSP 7 * by Daniel Glazman <daniel.glazman@disruptive-innovations.com> 8 * licensed under MPL 1.1/GPL 2.0/LGPL 2.1 9 * 10 * Changelog: 11 * - Add module pattern to jscsp 12 * - Change const declarations to var for IE9 compatibility 13 */ 14 (function (wef) { 15 /**#nocode+*/ 16 17 /* ***** BEGIN LICENSE BLOCK ***** 18 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 19 * 20 * The contents of this file are subject to the Mozilla Public License Version 21 * 1.1 (the "License"); you may not use this file except in compliance with 22 * the License. You may obtain a copy of the License at 23 * http://www.mozilla.org/MPL/ 24 * 25 * Software distributed under the License is distributed on an "AS IS" basis, 26 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 27 * for the specific language governing rights and limitations under the 28 * License. 29 * 30 * The Original Code is mozilla.org code. 31 * 32 * The Initial Developer of the Original Code is 33 * Netscape Communications Corporation. 34 * Portions created by the Initial Developer are Copyright (C) 1998 35 * the Initial Developer. All Rights Reserved. 36 * 37 * Contributor(s): 38 * emk <VYV03354@nifty.ne.jp> 39 * Daniel Glazman <glazman@netscape.com> 40 * L. David Baron <dbaron@dbaron.org> 41 * Boris Zbarsky <bzbarsky@mit.edu> 42 * Mats Palmgren <mats.palmgren@bredband.net> 43 * Christian Biesinger <cbiesinger@web.de> 44 * Jeff Walden <jwalden+code@mit.edu> 45 * Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd. 46 * Siraj Razick <siraj.razick@collabora.co.uk>, Collabora Ltd. 47 * Daniel Glazman <daniel.glazman@disruptive-innovations.com> 48 * 49 * Alternatively, the contents of this file may be used under the terms of 50 * either of the GNU General Public License Version 2 or later (the "GPL"), 51 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 52 * in which case the provisions of the GPL or the LGPL are applicable instead 53 * of those above. If you wish to allow use of your version of this file only 54 * under the terms of either the GPL or the LGPL, and not to allow others to 55 * use your version of this file under the terms of the MPL, indicate your 56 * decision by deleting the provisions above and replace them with the notice 57 * and other provisions required by the GPL or the LGPL. If you do not delete 58 * the provisions above, a recipient may use your version of this file under 59 * the terms of any one of the MPL, the GPL or the LGPL. 60 * 61 * ***** END LICENSE BLOCK ***** */ 62 63 /* FROM http://peter.sh/data/vendor-prefixed-css.php?js=1 */ 64 65 var kENGINES = [ 66 "webkit", "presto", "trident", "generic" 67 ]; 68 69 var kCSS_VENDOR_VALUES = { 70 "-moz-box":{"webkit":"-webkit-box", "presto":"", "trident":"", "generic":"box" }, 71 "-moz-inline-box":{"webkit":"-webkit-inline-box", "presto":"", "trident":"", "generic":"inline-box" }, 72 "-moz-initial":{"webkit":"", "presto":"", "trident":"", "generic":"initial" }, 73 "-moz-linear-gradient":{"webkit20110101":FilterLinearGradientForOutput, 74 "webkit":FilterLinearGradientForOutput, 75 "presto":"", 76 "trident":"", 77 "generic":FilterLinearGradientForOutput }, 78 "-moz-radial-gradient":{"webkit20110101":FilterRadialGradientForOutput, 79 "webkit":FilterRadialGradientForOutput, 80 "presto":"", 81 "trident":"", 82 "generic":FilterRadialGradientForOutput }, 83 "-moz-repeating-linear-gradient":{"webkit20110101":"", 84 "webkit":FilterRepeatingGradientForOutput, 85 "presto":"", 86 "trident":"", 87 "generic":FilterRepeatingGradientForOutput }, 88 "-moz-repeating-radial-gradient":{"webkit20110101":"", 89 "webkit":FilterRepeatingGradientForOutput, 90 "presto":"", 91 "trident":"", 92 "generic":FilterRepeatingGradientForOutput } 93 }; 94 95 var kCSS_VENDOR_PREFIXES = {"lastUpdate":1304175007, "properties":[ 96 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-accelerator", "status":"P"}, 97 {"gecko":"", "webkit":"", "presto":"-wap-accesskey", "trident":"", "status":""}, 98 {"gecko":"-moz-animation", "webkit":"-webkit-animation", "presto":"", "trident":"", "status":"WD"}, 99 {"gecko":"-moz-animation-delay", "webkit":"-webkit-animation-delay", "presto":"", "trident":"", "status":"WD"}, 100 {"gecko":"-moz-animation-direction", "webkit":"-webkit-animation-direction", "presto":"", "trident":"", "status":"WD"}, 101 {"gecko":"-moz-animation-duration", "webkit":"-webkit-animation-duration", "presto":"", "trident":"", "status":"WD"}, 102 {"gecko":"-moz-animation-fill-mode", "webkit":"-webkit-animation-fill-mode", "presto":"", "trident":"", "status":"ED"}, 103 {"gecko":"-moz-animation-iteration-count", "webkit":"-webkit-animation-iteration-count", "presto":"", "trident":"", "status":"WD"}, 104 {"gecko":"-moz-animation-name", "webkit":"-webkit-animation-name", "presto":"", "trident":"", "status":"WD"}, 105 {"gecko":"-moz-animation-play-state", "webkit":"-webkit-animation-play-state", "presto":"", "trident":"", "status":"WD"}, 106 {"gecko":"-moz-animation-timing-function", "webkit":"-webkit-animation-timing-function", "presto":"", "trident":"", "status":"WD"}, 107 {"gecko":"-moz-appearance", "webkit":"-webkit-appearance", "presto":"", "trident":"", "status":"CR"}, 108 {"gecko":"", "webkit":"-webkit-backface-visibility", "presto":"", "trident":"", "status":"WD"}, 109 {"gecko":"background-clip", "webkit":"-webkit-background-clip", "presto":"background-clip", "trident":"background-clip", "status":"WD"}, 110 {"gecko":"", "webkit":"-webkit-background-composite", "presto":"", "trident":"", "status":""}, 111 {"gecko":"-moz-background-inline-policy", "webkit":"", "presto":"", "trident":"", "status":"P"}, 112 {"gecko":"background-origin", "webkit":"-webkit-background-origin", "presto":"background-origin", "trident":"background-origin", "status":"WD"}, 113 {"gecko":"", "webkit":"background-position-x", "presto":"", "trident":"-ms-background-position-x", "status":""}, 114 {"gecko":"", "webkit":"background-position-y", "presto":"", "trident":"-ms-background-position-y", "status":""}, 115 {"gecko":"background-size", "webkit":"-webkit-background-size", "presto":"background-size", "trident":"background-size", "status":"WD"}, 116 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-behavior", "status":""}, 117 {"gecko":"-moz-binding", "webkit":"", "presto":"", "trident":"", "status":"P"}, 118 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-block-progression", "status":""}, 119 {"gecko":"", "webkit":"-webkit-border-after", "presto":"", "trident":"", "status":"ED"}, 120 {"gecko":"", "webkit":"-webkit-border-after-color", "presto":"", "trident":"", "status":"ED"}, 121 {"gecko":"", "webkit":"-webkit-border-after-style", "presto":"", "trident":"", "status":"ED"}, 122 {"gecko":"", "webkit":"-webkit-border-after-width", "presto":"", "trident":"", "status":"ED"}, 123 {"gecko":"", "webkit":"-webkit-border-before", "presto":"", "trident":"", "status":"ED"}, 124 {"gecko":"", "webkit":"-webkit-border-before-color", "presto":"", "trident":"", "status":"ED"}, 125 {"gecko":"", "webkit":"-webkit-border-before-style", "presto":"", "trident":"", "status":"ED"}, 126 {"gecko":"", "webkit":"-webkit-border-before-width", "presto":"", "trident":"", "status":"ED"}, 127 {"gecko":"-moz-border-bottom-colors", "webkit":"", "presto":"", "trident":"", "status":"P"}, 128 {"gecko":"border-bottom-left-radius", "webkit":"-webkit-border-bottom-left-radius", "presto":"border-bottom-left-radius", "trident":"border-bottom-left-radius", "status":"WD"}, 129 {"gecko":"", "webkit":"-webkit-border-bottom-left-radius = border-bottom-left-radius", "presto":"", "trident":"", "status":""}, 130 {"gecko":"border-bottom-right-radius", "webkit":"-webkit-border-bottom-right-radius", "presto":"border-bottom-right-radius", "trident":"border-bottom-right-radius", "status":"WD"}, 131 {"gecko":"", "webkit":"-webkit-border-bottom-right-radius = border-bottom-right-radius", "presto":"", "trident":"", "status":""}, 132 {"gecko":"-moz-border-end", "webkit":"-webkit-border-end", "presto":"", "trident":"", "status":"ED"}, 133 {"gecko":"-moz-border-end-color", "webkit":"-webkit-border-end-color", "presto":"", "trident":"", "status":"ED"}, 134 {"gecko":"-moz-border-end-style", "webkit":"-webkit-border-end-style", "presto":"", "trident":"", "status":"ED"}, 135 {"gecko":"-moz-border-end-width", "webkit":"-webkit-border-end-width", "presto":"", "trident":"", "status":"ED"}, 136 {"gecko":"", "webkit":"-webkit-border-fit", "presto":"", "trident":"", "status":""}, 137 {"gecko":"", "webkit":"-webkit-border-horizontal-spacing", "presto":"", "trident":"", "status":""}, 138 {"gecko":"-moz-border-image", "webkit":"-webkit-border-image", "presto":"-o-border-image", "trident":"", "status":"WD"}, 139 {"gecko":"-moz-border-left-colors", "webkit":"", "presto":"", "trident":"", "status":"P"}, 140 {"gecko":"border-radius", "webkit":"-webkit-border-radius", "presto":"border-radius", "trident":"border-radius", "status":"WD"}, 141 {"gecko":"-moz-border-right-colors", "webkit":"", "presto":"", "trident":"", "status":"P"}, 142 {"gecko":"-moz-border-start", "webkit":"-webkit-border-start", "presto":"", "trident":"", "status":"ED"}, 143 {"gecko":"-moz-border-start-color", "webkit":"-webkit-border-start-color", "presto":"", "trident":"", "status":"ED"}, 144 {"gecko":"-moz-border-start-style", "webkit":"-webkit-border-start-style", "presto":"", "trident":"", "status":"ED"}, 145 {"gecko":"-moz-border-start-width", "webkit":"-webkit-border-start-width", "presto":"", "trident":"", "status":"ED"}, 146 {"gecko":"-moz-border-top-colors", "webkit":"", "presto":"", "trident":"", "status":"P"}, 147 {"gecko":"border-top-left-radius", "webkit":"-webkit-border-top-left-radius", "presto":"border-top-left-radius", "trident":"border-top-left-radius", "status":"WD"}, 148 {"gecko":"", "webkit":"-webkit-border-top-left-radius = border-top-left-radius", "presto":"", "trident":"", "status":""}, 149 {"gecko":"border-top-right-radius", "webkit":"-webkit-border-top-right-radius", "presto":"border-top-right-radius", "trident":"border-top-right-radius", "status":"WD"}, 150 {"gecko":"", "webkit":"-webkit-border-top-right-radius = border-top-right-radius", "presto":"", "trident":"", "status":""}, 151 {"gecko":"", "webkit":"-webkit-border-vertical-spacing", "presto":"", "trident":"", "status":""}, 152 {"gecko":"-moz-box-align", "webkit":"-webkit-box-align", "presto":"", "trident":"-ms-box-align", "status":"WD"}, 153 {"gecko":"-moz-box-direction", "webkit":"-webkit-box-direction", "presto":"", "trident":"-ms-box-direction", "status":"WD"}, 154 {"gecko":"-moz-box-flex", "webkit":"-webkit-box-flex", "presto":"", "trident":"-ms-box-flex", "status":"WD"}, 155 {"gecko":"", "webkit":"-webkit-box-flex-group", "presto":"", "trident":"", "status":"WD"}, 156 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-box-line-progression", "status":""}, 157 {"gecko":"", "webkit":"-webkit-box-lines", "presto":"", "trident":"-ms-box-lines", "status":"WD"}, 158 {"gecko":"-moz-box-ordinal-group", "webkit":"-webkit-box-ordinal-group", "presto":"", "trident":"-ms-box-ordinal-group", "status":"WD"}, 159 {"gecko":"-moz-box-orient", "webkit":"-webkit-box-orient", "presto":"", "trident":"-ms-box-orient", "status":"WD"}, 160 {"gecko":"-moz-box-pack", "webkit":"-webkit-box-pack", "presto":"", "trident":"-ms-box-pack", "status":"WD"}, 161 {"gecko":"", "webkit":"-webkit-box-reflect", "presto":"", "trident":"", "status":""}, 162 {"gecko":"box-shadow", "webkit":"-webkit-box-shadow", "presto":"box-shadow", "trident":"box-shadow", "status":"WD"}, 163 {"gecko":"-moz-box-sizing", "webkit":"box-sizing", "presto":"box-sizing", "trident":"", "status":"CR"}, 164 {"gecko":"", "webkit":"-webkit-box-sizing = box-sizing", "presto":"", "trident":"", "status":""}, 165 {"gecko":"", "webkit":"-epub-caption-side = caption-side", "presto":"", "trident":"", "status":""}, 166 {"gecko":"", "webkit":"-webkit-color-correction", "presto":"", "trident":"", "status":""}, 167 {"gecko":"", "webkit":"-webkit-column-break-after", "presto":"", "trident":"", "status":""}, 168 {"gecko":"", "webkit":"-webkit-column-break-before", "presto":"", "trident":"", "status":""}, 169 {"gecko":"", "webkit":"-webkit-column-break-inside", "presto":"", "trident":"", "status":""}, 170 {"gecko":"-moz-column-count", "webkit":"-webkit-column-count", "presto":"column-count", "trident":"column-count", "status":"CR"}, 171 {"gecko":"-moz-column-gap", "webkit":"-webkit-column-gap", "presto":"column-gap", "trident":"column-gap", "status":"CR"}, 172 {"gecko":"-moz-column-rule", "webkit":"-webkit-column-rule", "presto":"column-rule", "trident":"column-rule", "status":"CR"}, 173 {"gecko":"-moz-column-rule-color", "webkit":"-webkit-column-rule-color", "presto":"column-rule-color", "trident":"column-rule-color", "status":"CR"}, 174 {"gecko":"-moz-column-rule-style", "webkit":"-webkit-column-rule-style", "presto":"column-rule-style", "trident":"column-rule-style", "status":"CR"}, 175 {"gecko":"-moz-column-rule-width", "webkit":"-webkit-column-rule-width", "presto":"column-rule-width", "trident":"column-rule-width", "status":"CR"}, 176 {"gecko":"", "webkit":"-webkit-column-span", "presto":"column-span", "trident":"column-span", "status":"CR"}, 177 {"gecko":"-moz-column-width", "webkit":"-webkit-column-width", "presto":"column-width", "trident":"column-width", "status":"CR"}, 178 {"gecko":"", "webkit":"-webkit-columns", "presto":"columns", "trident":"columns", "status":"CR"}, 179 {"gecko":"", "webkit":"-webkit-dashboard-region", "presto":"-apple-dashboard-region", "trident":"", "status":""}, 180 {"gecko":"filter", "webkit":"", "presto":"filter", "trident":"-ms-filter", "status":""}, 181 {"gecko":"-moz-float-edge", "webkit":"", "presto":"", "trident":"", "status":"P"}, 182 {"gecko":"", "webkit":"", "presto":"-o-focus-opacity", "trident":"", "status":""}, 183 {"gecko":"-moz-font-feature-settings", "webkit":"", "presto":"", "trident":"", "status":""}, 184 {"gecko":"-moz-font-language-override", "webkit":"", "presto":"", "trident":"", "status":""}, 185 {"gecko":"", "webkit":"-webkit-font-size-delta", "presto":"", "trident":"", "status":""}, 186 {"gecko":"", "webkit":"-webkit-font-smoothing", "presto":"", "trident":"", "status":""}, 187 {"gecko":"-moz-force-broken-image-icon", "webkit":"", "presto":"", "trident":"", "status":""}, 188 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-grid-column", "status":"WD"}, 189 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-grid-column-align", "status":"WD"}, 190 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-grid-column-span", "status":"WD"}, 191 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-grid-columns", "status":"WD"}, 192 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-grid-layer", "status":"WD"}, 193 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-grid-row", "status":"WD"}, 194 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-grid-row-align", "status":"WD"}, 195 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-grid-row-span", "status":"WD"}, 196 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-grid-rows", "status":"WD"}, 197 {"gecko":"", "webkit":"-webkit-highlight", "presto":"", "trident":"", "status":""}, 198 {"gecko":"", "webkit":"-webkit-hyphenate-character", "presto":"", "trident":"", "status":"WD"}, 199 {"gecko":"", "webkit":"-webkit-hyphenate-limit-after", "presto":"", "trident":"", "status":""}, 200 {"gecko":"", "webkit":"-webkit-hyphenate-limit-before", "presto":"", "trident":"", "status":""}, 201 {"gecko":"", "webkit":"-webkit-hyphens", "presto":"", "trident":"", "status":"WD"}, 202 {"gecko":"", "webkit":"-epub-hyphens = -webkit-hyphens", "presto":"", "trident":"", "status":""}, 203 {"gecko":"-moz-image-region", "webkit":"", "presto":"", "trident":"", "status":"P"}, 204 {"gecko":"ime-mode", "webkit":"", "presto":"", "trident":"-ms-ime-mode", "status":""}, 205 {"gecko":"", "webkit":"", "presto":"-wap-input-format", "trident":"", "status":""}, 206 {"gecko":"", "webkit":"", "presto":"-wap-input-required", "trident":"", "status":""}, 207 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-interpolation-mode", "status":""}, 208 {"gecko":"", "webkit":"", "presto":"-xv-interpret-as", "trident":"", "status":""}, 209 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-layout-flow", "status":""}, 210 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-layout-grid", "status":""}, 211 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-layout-grid-char", "status":""}, 212 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-layout-grid-line", "status":""}, 213 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-layout-grid-mode", "status":""}, 214 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-layout-grid-type", "status":""}, 215 {"gecko":"", "webkit":"-webkit-line-box-contain", "presto":"", "trident":"", "status":""}, 216 {"gecko":"", "webkit":"-webkit-line-break", "presto":"", "trident":"-ms-line-break", "status":""}, 217 {"gecko":"", "webkit":"-webkit-line-clamp", "presto":"", "trident":"", "status":""}, 218 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-line-grid-mode", "status":""}, 219 {"gecko":"", "webkit":"", "presto":"-o-link", "trident":"", "status":""}, 220 {"gecko":"", "webkit":"", "presto":"-o-link-source", "trident":"", "status":""}, 221 {"gecko":"", "webkit":"-webkit-locale", "presto":"", "trident":"", "status":""}, 222 {"gecko":"", "webkit":"-webkit-logical-height", "presto":"", "trident":"", "status":"ED"}, 223 {"gecko":"", "webkit":"-webkit-logical-width", "presto":"", "trident":"", "status":"ED"}, 224 {"gecko":"", "webkit":"-webkit-margin-after", "presto":"", "trident":"", "status":"ED"}, 225 {"gecko":"", "webkit":"-webkit-margin-after-collapse", "presto":"", "trident":"", "status":""}, 226 {"gecko":"", "webkit":"-webkit-margin-before", "presto":"", "trident":"", "status":"ED"}, 227 {"gecko":"", "webkit":"-webkit-margin-before-collapse", "presto":"", "trident":"", "status":""}, 228 {"gecko":"", "webkit":"-webkit-margin-bottom-collapse", "presto":"", "trident":"", "status":""}, 229 {"gecko":"", "webkit":"-webkit-margin-collapse", "presto":"", "trident":"", "status":""}, 230 {"gecko":"-moz-margin-end", "webkit":"-webkit-margin-end", "presto":"", "trident":"", "status":"ED"}, 231 {"gecko":"-moz-margin-start", "webkit":"-webkit-margin-start", "presto":"", "trident":"", "status":"ED"}, 232 {"gecko":"", "webkit":"-webkit-margin-top-collapse", "presto":"", "trident":"", "status":""}, 233 {"gecko":"", "webkit":"-webkit-marquee", "presto":"", "trident":"", "status":""}, 234 {"gecko":"", "webkit":"", "presto":"-wap-marquee-dir", "trident":"", "status":""}, 235 {"gecko":"", "webkit":"-webkit-marquee-direction", "presto":"", "trident":"", "status":"WD"}, 236 {"gecko":"", "webkit":"-webkit-marquee-increment", "presto":"", "trident":"", "status":""}, 237 {"gecko":"", "webkit":"", "presto":"-wap-marquee-loop", "trident":"", "status":"WD"}, 238 {"gecko":"", "webkit":"-webkit-marquee-repetition", "presto":"", "trident":"", "status":""}, 239 {"gecko":"", "webkit":"-webkit-marquee-speed", "presto":"-wap-marquee-speed", "trident":"", "status":"WD"}, 240 {"gecko":"", "webkit":"-webkit-marquee-style", "presto":"-wap-marquee-style", "trident":"", "status":"WD"}, 241 {"gecko":"mask", "webkit":"-webkit-mask", "presto":"mask", "trident":"", "status":""}, 242 {"gecko":"", "webkit":"-webkit-mask-attachment", "presto":"", "trident":"", "status":""}, 243 {"gecko":"", "webkit":"-webkit-mask-box-image", "presto":"", "trident":"", "status":""}, 244 {"gecko":"", "webkit":"-webkit-mask-clip", "presto":"", "trident":"", "status":""}, 245 {"gecko":"", "webkit":"-webkit-mask-composite", "presto":"", "trident":"", "status":""}, 246 {"gecko":"", "webkit":"-webkit-mask-image", "presto":"", "trident":"", "status":""}, 247 {"gecko":"", "webkit":"-webkit-mask-origin", "presto":"", "trident":"", "status":""}, 248 {"gecko":"", "webkit":"-webkit-mask-position", "presto":"", "trident":"", "status":""}, 249 {"gecko":"", "webkit":"-webkit-mask-position-x", "presto":"", "trident":"", "status":""}, 250 {"gecko":"", "webkit":"-webkit-mask-position-y", "presto":"", "trident":"", "status":""}, 251 {"gecko":"", "webkit":"-webkit-mask-repeat", "presto":"", "trident":"", "status":""}, 252 {"gecko":"", "webkit":"-webkit-mask-repeat-x", "presto":"", "trident":"", "status":""}, 253 {"gecko":"", "webkit":"-webkit-mask-repeat-y", "presto":"", "trident":"", "status":""}, 254 {"gecko":"", "webkit":"-webkit-mask-size", "presto":"", "trident":"", "status":""}, 255 {"gecko":"", "webkit":"-webkit-match-nearest-mail-blockquote-color", "presto":"", "trident":"", "status":""}, 256 {"gecko":"", "webkit":"-webkit-max-logical-height", "presto":"", "trident":"", "status":""}, 257 {"gecko":"", "webkit":"-webkit-max-logical-width", "presto":"", "trident":"", "status":"ED"}, 258 {"gecko":"", "webkit":"-webkit-min-logical-height", "presto":"", "trident":"", "status":"ED"}, 259 {"gecko":"", "webkit":"-webkit-min-logical-width", "presto":"", "trident":"", "status":"ED"}, 260 {"gecko":"", "webkit":"", "presto":"-o-mini-fold", "trident":"", "status":""}, 261 {"gecko":"", "webkit":"-webkit-nbsp-mode", "presto":"", "trident":"", "status":"P"}, 262 {"gecko":"", "webkit":"", "presto":"-o-object-fit", "trident":"", "status":"ED"}, 263 {"gecko":"", "webkit":"", "presto":"-o-object-position", "trident":"", "status":"ED"}, 264 {"gecko":"opacity", "webkit":"-webkit-opacity", "presto":"opacity", "trident":"opacity", "status":"WD"}, 265 {"gecko":"", "webkit":"-webkit-opacity = opacity", "presto":"", "trident":"", "status":""}, 266 {"gecko":"-moz-outline-radius", "webkit":"", "presto":"", "trident":"", "status":"P"}, 267 {"gecko":"-moz-outline-radius-bottomleft", "webkit":"", "presto":"", "trident":"", "status":"P"}, 268 {"gecko":"-moz-outline-radius-bottomright", "webkit":"", "presto":"", "trident":"", "status":"P"}, 269 {"gecko":"-moz-outline-radius-topleft", "webkit":"", "presto":"", "trident":"", "status":"P"}, 270 {"gecko":"-moz-outline-radius-topright", "webkit":"", "presto":"", "trident":"", "status":"P"}, 271 {"gecko":"overflow-x", "webkit":"overflow-x", "presto":"overflow-x", "trident":"-ms-overflow-x", "status":"WD"}, 272 {"gecko":"overflow-y", "webkit":"overflow-y", "presto":"overflow-y", "trident":"-ms-overflow-y", "status":"WD"}, 273 {"gecko":"", "webkit":"-webkit-padding-after", "presto":"", "trident":"", "status":"ED"}, 274 {"gecko":"", "webkit":"-webkit-padding-before", "presto":"", "trident":"", "status":"ED"}, 275 {"gecko":"-moz-padding-end", "webkit":"-webkit-padding-end", "presto":"", "trident":"", "status":"ED"}, 276 {"gecko":"-moz-padding-start", "webkit":"-webkit-padding-start", "presto":"", "trident":"", "status":"ED"}, 277 {"gecko":"", "webkit":"-webkit-perspective", "presto":"", "trident":"", "status":"WD"}, 278 {"gecko":"", "webkit":"-webkit-perspective-origin", "presto":"", "trident":"", "status":"WD"}, 279 {"gecko":"", "webkit":"-webkit-perspective-origin-x", "presto":"", "trident":"", "status":""}, 280 {"gecko":"", "webkit":"-webkit-perspective-origin-y", "presto":"", "trident":"", "status":""}, 281 {"gecko":"", "webkit":"", "presto":"-xv-phonemes", "trident":"", "status":""}, 282 {"gecko":"", "webkit":"-webkit-rtl-ordering", "presto":"", "trident":"", "status":"P"}, 283 {"gecko":"-moz-script-level", "webkit":"", "presto":"", "trident":"", "status":""}, 284 {"gecko":"-moz-script-min-size", "webkit":"", "presto":"", "trident":"", "status":""}, 285 {"gecko":"-moz-script-size-multiplier", "webkit":"", "presto":"", "trident":"", "status":""}, 286 {"gecko":"", "webkit":"", "presto":"scrollbar-3dlight-color", "trident":"-ms-scrollbar-3dlight-color", "status":"P"}, 287 {"gecko":"", "webkit":"", "presto":"scrollbar-arrow-color", "trident":"-ms-scrollbar-arrow-color", "status":"P"}, 288 {"gecko":"", "webkit":"", "presto":"scrollbar-base-color", "trident":"-ms-scrollbar-base-color", "status":"P"}, 289 {"gecko":"", "webkit":"", "presto":"scrollbar-darkshadow-color", "trident":"-ms-scrollbar-darkshadow-color", "status":"P"}, 290 {"gecko":"", "webkit":"", "presto":"scrollbar-face-color", "trident":"-ms-scrollbar-face-color", "status":"P"}, 291 {"gecko":"", "webkit":"", "presto":"scrollbar-highlight-color", "trident":"-ms-scrollbar-highlight-color", "status":"P"}, 292 {"gecko":"", "webkit":"", "presto":"scrollbar-shadow-color", "trident":"-ms-scrollbar-shadow-color", "status":"P"}, 293 {"gecko":"", "webkit":"", "presto":"scrollbar-track-color", "trident":"-ms-scrollbar-track-color", "status":"P"}, 294 {"gecko":"-moz-stack-sizing", "webkit":"", "presto":"", "trident":"", "status":"P"}, 295 {"gecko":"", "webkit":"-webkit-svg-shadow", "presto":"", "trident":"", "status":""}, 296 {"gecko":"-moz-tab-size", "webkit":"", "presto":"-o-tab-size", "trident":"", "status":""}, 297 {"gecko":"", "webkit":"", "presto":"-o-table-baseline", "trident":"", "status":""}, 298 {"gecko":"", "webkit":"-webkit-tap-highlight-color", "presto":"", "trident":"", "status":"P"}, 299 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-text-align-last", "status":"WD"}, 300 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-text-autospace", "status":"WD"}, 301 {"gecko":"-moz-text-blink", "webkit":"", "presto":"", "trident":"", "status":""}, 302 {"gecko":"", "webkit":"-webkit-text-combine", "presto":"", "trident":"", "status":""}, 303 {"gecko":"", "webkit":"-epub-text-combine = -webkit-text-combine", "presto":"", "trident":"", "status":""}, 304 {"gecko":"-moz-text-decoration-color", "webkit":"", "presto":"", "trident":"", "status":""}, 305 {"gecko":"-moz-text-decoration-line", "webkit":"", "presto":"", "trident":"", "status":""}, 306 {"gecko":"-moz-text-decoration-style", "webkit":"", "presto":"", "trident":"", "status":""}, 307 {"gecko":"", "webkit":"-webkit-text-decorations-in-effect", "presto":"", "trident":"", "status":""}, 308 {"gecko":"", "webkit":"-webkit-text-emphasis", "presto":"", "trident":"", "status":""}, 309 {"gecko":"", "webkit":"-epub-text-emphasis = -webkit-text-emphasis", "presto":"", "trident":"", "status":""}, 310 {"gecko":"", "webkit":"-webkit-text-emphasis-color", "presto":"", "trident":"", "status":""}, 311 {"gecko":"", "webkit":"-epub-text-emphasis-color = -webkit-text-emphasis-color", "presto":"", "trident":"", "status":""}, 312 {"gecko":"", "webkit":"-webkit-text-emphasis-position", "presto":"", "trident":"", "status":""}, 313 {"gecko":"", "webkit":"-webkit-text-emphasis-style", "presto":"", "trident":"", "status":""}, 314 {"gecko":"", "webkit":"-epub-text-emphasis-style = -webkit-text-emphasis-style", "presto":"", "trident":"", "status":""}, 315 {"gecko":"", "webkit":"-webkit-text-fill-color", "presto":"", "trident":"", "status":"P"}, 316 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-text-justify", "status":"WD"}, 317 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-text-kashida-space", "status":"P"}, 318 {"gecko":"", "webkit":"-webkit-text-orientation", "presto":"", "trident":"", "status":""}, 319 {"gecko":"", "webkit":"-epub-text-orientation = -webkit-text-orientation", "presto":"", "trident":"", "status":""}, 320 {"gecko":"", "webkit":"text-overflow", "presto":"text-overflow", "trident":"-ms-text-overflow", "status":"WD"}, 321 {"gecko":"", "webkit":"-webkit-text-security", "presto":"", "trident":"", "status":"P"}, 322 {"gecko":"", "webkit":"-webkit-text-size-adjust", "presto":"", "trident":"-ms-text-size-adjust", "status":""}, 323 {"gecko":"", "webkit":"-webkit-text-stroke", "presto":"", "trident":"", "status":"P"}, 324 {"gecko":"", "webkit":"-webkit-text-stroke-color", "presto":"", "trident":"", "status":"P"}, 325 {"gecko":"", "webkit":"-webkit-text-stroke-width", "presto":"", "trident":"", "status":"P"}, 326 {"gecko":"", "webkit":"-epub-text-transform = text-transform", "presto":"", "trident":"", "status":""}, 327 {"gecko":"", "webkit":"", "presto":"", "trident":"-ms-text-underline-position", "status":"P"}, 328 {"gecko":"", "webkit":"-webkit-touch-callout", "presto":"", "trident":"", "status":"P"}, 329 {"gecko":"-moz-transform", "webkit":"-webkit-transform", "presto":"-o-transform", "trident":"-ms-transform", "status":"WD"}, 330 {"gecko":"-moz-transform-origin", "webkit":"-webkit-transform-origin", "presto":"-o-transform-origin", "trident":"-ms-transform-origin", "status":"WD"}, 331 {"gecko":"", "webkit":"-webkit-transform-origin-x", "presto":"", "trident":"", "status":"P"}, 332 {"gecko":"", "webkit":"-webkit-transform-origin-y", "presto":"", "trident":"", "status":"P"}, 333 {"gecko":"", "webkit":"-webkit-transform-origin-z", "presto":"", "trident":"", "status":"P"}, 334 {"gecko":"", "webkit":"-webkit-transform-style", "presto":"", "trident":"", "status":"WD"}, 335 {"gecko":"-moz-transition", "webkit":"-webkit-transition", "presto":"-o-transition", "trident":"", "status":"WD"}, 336 {"gecko":"-moz-transition-delay", "webkit":"-webkit-transition-delay", "presto":"-o-transition-delay", "trident":"", "status":"WD"}, 337 {"gecko":"-moz-transition-duration", "webkit":"-webkit-transition-duration", "presto":"-o-transition-duration", "trident":"", "status":"WD"}, 338 {"gecko":"-moz-transition-property", "webkit":"-webkit-transition-property", "presto":"-o-transition-property", "trident":"", "status":"WD"}, 339 {"gecko":"-moz-transition-timing-function", "webkit":"-webkit-transition-timing-function", "presto":"-o-transition-timing-function", "trident":"", "status":"WD"}, 340 {"gecko":"", "webkit":"-webkit-user-drag", "presto":"", "trident":"", "status":"P"}, 341 {"gecko":"-moz-user-focus", "webkit":"", "presto":"", "trident":"", "status":"P"}, 342 {"gecko":"-moz-user-input", "webkit":"", "presto":"", "trident":"", "status":"P"}, 343 {"gecko":"-moz-user-modify", "webkit":"-webkit-user-modify", "presto":"", "trident":"", "status":"P"}, 344 {"gecko":"-moz-user-select", "webkit":"-webkit-user-select", "presto":"", "trident":"", "status":"P"}, 345 {"gecko":"", "webkit":"", "presto":"-xv-voice-balance", "trident":"", "status":""}, 346 {"gecko":"", "webkit":"", "presto":"-xv-voice-duration", "trident":"", "status":""}, 347 {"gecko":"", "webkit":"", "presto":"-xv-voice-pitch", "trident":"", "status":""}, 348 {"gecko":"", "webkit":"", "presto":"-xv-voice-pitch-range", "trident":"", "status":""}, 349 {"gecko":"", "webkit":"", "presto":"-xv-voice-rate", "trident":"", "status":""}, 350 {"gecko":"", "webkit":"", "presto":"-xv-voice-stress", "trident":"", "status":""}, 351 {"gecko":"", "webkit":"", "presto":"-xv-voice-volume", "trident":"", "status":""}, 352 {"gecko":"-moz-window-shadow", "webkit":"", "presto":"", "trident":"", "status":"P"}, 353 {"gecko":"", "webkit":"word-break", "presto":"", "trident":"-ms-word-break", "status":"WD"}, 354 {"gecko":"", "webkit":"-epub-word-break = word-break", "presto":"", "trident":"", "status":""}, 355 {"gecko":"word-wrap", "webkit":"word-wrap", "presto":"word-wrap", "trident":"-ms-word-wrap", "status":"WD"}, 356 {"gecko":"", "webkit":"-webkit-writing-mode", "presto":"writing-mode", "trident":"-ms-writing-mode", "status":"ED"}, 357 {"gecko":"", "webkit":"-epub-writing-mode = -webkit-writing-mode", "presto":"", "trident":"", "status":""}, 358 {"gecko":"", "webkit":"zoom", "presto":"", "trident":"-ms-zoom", "status":""} 359 ]}; 360 361 var kCSS_PREFIXED_VALUE = [ 362 {"gecko":"-moz-box", "webkit":"-moz-box", "presto":"", "trident":"", "generic":"box"} 363 ]; 364 365 var CssInspector = { 366 367 mVENDOR_PREFIXES:null, 368 369 kEXPORTS_FOR_GECKO:true, 370 kEXPORTS_FOR_WEBKIT:true, 371 kEXPORTS_FOR_PRESTO:true, 372 kEXPORTS_FOR_TRIDENT:true, 373 374 cleanPrefixes:function () { 375 this.mVENDOR_PREFIXES = null; 376 }, 377 378 prefixesForProperty:function (aProperty) { 379 if (!this.mVENDOR_PREFIXES) { 380 381 this.mVENDOR_PREFIXES = {}; 382 for (var i = 0; i < kCSS_VENDOR_PREFIXES.properties.length; i++) { 383 var p = kCSS_VENDOR_PREFIXES.properties[i]; 384 if (p.gecko && (p.webkit || p.presto || p.trident)) { 385 var o = {}; 386 if (this.kEXPORTS_FOR_GECKO) { 387 o[p.gecko] = true; 388 } 389 if (this.kEXPORTS_FOR_WEBKIT && p.webkit) { 390 o[p.webkit] = true; 391 } 392 if (this.kEXPORTS_FOR_PRESTO && p.presto) { 393 o[p.presto] = true; 394 } 395 if (this.kEXPORTS_FOR_TRIDENT && p.trident) { 396 o[p.trident] = true; 397 } 398 this.mVENDOR_PREFIXES[p.gecko] = []; 399 for (var j in o) { 400 this.mVENDOR_PREFIXES[p.gecko].push(j) 401 } 402 } 403 } 404 } 405 if (aProperty in this.mVENDOR_PREFIXES) { 406 return this.mVENDOR_PREFIXES[aProperty].sort(); 407 } 408 return null; 409 }, 410 411 parseColorStop:function (parser, token) { 412 var color = parser.parseColor(token); 413 var position = ""; 414 if (!color) { 415 return null; 416 } 417 token = parser.getToken(true, true); 418 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")) { 419 position = token.value; 420 token = parser.getToken(true, true); 421 } 422 return { color:color, position:position } 423 }, 424 425 parseGradient:function (parser, token) { 426 var isRadial = false; 427 var gradient = { isRepeating:false }; 428 if (token.isNotNull()) { 429 if (token.isFunction("-moz-linear-gradient(") || token.isFunction("-moz-radial-gradient(") || token.isFunction("-moz-repeating-linear-gradient(") || token.isFunction("-moz-repeating-radial-gradient(")) { 430 if (token.isFunction("-moz-radial-gradient(") || token.isFunction("-moz-repeating-radial-gradient(")) { 431 gradient.isRadial = true; 432 } 433 if (token.isFunction("-moz-repeating-linear-gradient(") || token.isFunction("-moz-repeating-radial-gradient(")) { 434 gradient.isRepeating = true; 435 } 436 437 438 token = parser.getToken(true, true); 439 var haveGradientLine = false; 440 var foundHorizPosition = false; 441 var haveAngle = false; 442 443 if (token.isAngle()) { 444 gradient.angle = token.value; 445 haveGradientLine = true; 446 haveAngle = true; 447 token = parser.getToken(true, true); 448 } 449 450 if (token.isLength() || token.isIdent("top") || token.isIdent("center") || token.isIdent("bottom") || token.isIdent("left") || token.isIdent("right")) { 451 haveGradientLine = true; 452 if (token.isLength() || token.isIdent("left") || token.isIdent("right")) { 453 foundHorizPosition = true; 454 } 455 gradient.position = token.value; 456 token = parser.getToken(true, true); 457 } 458 459 if (haveGradientLine) { 460 if (!haveAngle && token.isAngle()) { // we have an angle here 461 gradient.angle = token.value; 462 haveAngle = true; 463 token = parser.getToken(true, true); 464 } 465 466 else if (token.isLength() || (foundHorizPosition && (token.isIdent("top") || token.isIdent("center") || token.isIdent("bottom"))) || (!foundHorizPosition && (token.isLength() || token.isIdent("top") || token.isIdent("center") || token.isIdent("bottom") || token.isIdent("left") || token.isIdent("right")))) { 467 gradient.position = ("position" in gradient) ? gradient.position + " " : ""; 468 gradient.position += token.value; 469 token = parser.getToken(true, true); 470 } 471 472 if (!haveAngle && token.isAngle()) { // we have an angle here 473 gradient.angle = token.value; 474 haveAngle = true; 475 token = parser.getToken(true, true); 476 } 477 478 // we must find a comma here 479 if (!token.isSymbol(",")) { 480 return null; 481 } 482 token = parser.getToken(true, true); 483 } 484 485 // ok... Let's deal with the rest now 486 if (gradient.isRadial) { 487 if (token.isIdent("circle") || token.isIdent("ellipse")) { 488 gradient.shape = token.value; 489 token = parser.getToken(true, true); 490 } 491 if (token.isIdent("closest-side") || token.isIdent("closest-corner") || token.isIdent("farthest-side") || token.isIdent("farthest-corner") || token.isIdent("contain") || token.isIdent("cover")) { 492 gradient.size = token.value; 493 token = parser.getToken(true, true); 494 } 495 if (!("shape" in gradient) && (token.isIdent("circle") || token.isIdent("ellipse"))) { 496 // we can still have the second value... 497 gradient.shape = token.value; 498 token = parser.getToken(true, true); 499 } 500 if ((("shape" in gradient) || ("size" in gradient)) && !token.isSymbol(",")) { 501 return null; 502 } else if (("shape" in gradient) || ("size" in gradient)) { 503 token = parser.getToken(true, true); 504 } 505 } 506 507 // now color stops... 508 var stop1 = this.parseColorStop(parser, token); 509 if (!stop1) { 510 return null; 511 } 512 token = parser.currentToken(); 513 if (!token.isSymbol(",")) { 514 return null; 515 } 516 token = parser.getToken(true, true); 517 var stop2 = this.parseColorStop(parser, token); 518 if (!stop2) { 519 return null; 520 } 521 token = parser.currentToken(); 522 if (token.isSymbol(",")) { 523 token = parser.getToken(true, true); 524 } 525 // ok we have at least two color stops 526 gradient.stops = [stop1, stop2]; 527 while (!token.isSymbol(")")) { 528 var colorstop = this.parseColorStop(parser, token); 529 if (!colorstop) { 530 return null; 531 } 532 token = parser.currentToken(); 533 if (!token.isSymbol(")") && !token.isSymbol(",")) { 534 return null; 535 } 536 if (token.isSymbol(",")) { 537 token = parser.getToken(true, true); 538 } 539 gradient.stops.push(colorstop); 540 } 541 return gradient; 542 } 543 } 544 return null; 545 }, 546 547 parseBoxShadows:function (aString) { 548 var parser = new CSSParser(); 549 parser._init(); 550 parser.mPreserveWS = false; 551 parser.mPreserveComments = false; 552 parser.mPreservedTokens = []; 553 parser.mScanner.init(aString); 554 555 var shadows = []; 556 var token = parser.getToken(true, true); 557 var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px", spreadRadius = "0px"; 558 var inset = false; 559 while (token.isNotNull()) { 560 if (token.isIdent("none")) { 561 shadows.push({ none:true }); 562 token = parser.getToken(true, true); 563 } else { 564 if (token.isIdent('inset')) { 565 inset = true; 566 token = parser.getToken(true, true); 567 } 568 569 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")) { 570 var offsetX = token.value; 571 token = parser.getToken(true, true); 572 } else { 573 return []; 574 } 575 576 if (!inset && token.isIdent('inset')) { 577 inset = true; 578 token = parser.getToken(true, true); 579 } 580 581 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")) { 582 var offsetX = token.value; 583 token = parser.getToken(true, true); 584 } else { 585 return []; 586 } 587 588 if (!inset && token.isIdent('inset')) { 589 inset = true; 590 token = parser.getToken(true, true); 591 } 592 593 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")) { 594 var blurRadius = token.value; 595 token = parser.getToken(true, true); 596 } 597 598 if (!inset && token.isIdent('inset')) { 599 inset = true; 600 token = parser.getToken(true, true); 601 } 602 603 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")) { 604 var spreadRadius = token.value; 605 token = parser.getToken(true, true); 606 } 607 608 if (!inset && token.isIdent('inset')) { 609 inset = true; 610 token = parser.getToken(true, true); 611 } 612 613 if (token.isFunction("rgb(") || token.isFunction("rgba(") || token.isFunction("hsl(") || token.isFunction("hsla(") || token.isSymbol("#") || token.isIdent()) { 614 var color = parser.parseColor(token); 615 token = parser.getToken(true, true); 616 } 617 618 if (!inset && token.isIdent('inset')) { 619 inset = true; 620 token = parser.getToken(true, true); 621 } 622 623 shadows.push({ none:false, 624 color:color, 625 offsetX:offsetX, offsetY:offsetY, 626 blurRadius:blurRadius, 627 spreadRadius:spreadRadius }); 628 629 if (token.isSymbol(",")) { 630 inset = false; 631 color = ""; 632 blurRadius = "0px"; 633 spreadRadius = "0px" 634 offsetX = "0px"; 635 offsetY = "0px"; 636 token = parser.getToken(true, true); 637 } else if (!token.isNotNull()) { 638 return shadows; 639 } else { 640 return []; 641 } 642 } 643 } 644 return shadows; 645 }, 646 647 parseTextShadows:function (aString) { 648 var parser = new CSSParser(); 649 parser._init(); 650 parser.mPreserveWS = false; 651 parser.mPreserveComments = false; 652 parser.mPreservedTokens = []; 653 parser.mScanner.init(aString); 654 655 var shadows = []; 656 var token = parser.getToken(true, true); 657 var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px"; 658 while (token.isNotNull()) { 659 if (token.isIdent("none")) { 660 shadows.push({ none:true }); 661 token = parser.getToken(true, true); 662 } else { 663 if (token.isFunction("rgb(") || token.isFunction("rgba(") || token.isFunction("hsl(") || token.isFunction("hsla(") || token.isSymbol("#") || token.isIdent()) { 664 var color = parser.parseColor(token); 665 token = parser.getToken(true, true); 666 } 667 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")) { 668 var offsetX = token.value; 669 token = parser.getToken(true, true); 670 } else { 671 return []; 672 } 673 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")) { 674 var offsetY = token.value; 675 token = parser.getToken(true, true); 676 } else { 677 return []; 678 } 679 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")) { 680 var blurRadius = token.value; 681 token = parser.getToken(true, true); 682 } 683 if (!color && (token.isFunction("rgb(") || token.isFunction("rgba(") || token.isFunction("hsl(") || token.isFunction("hsla(") || token.isSymbol("#") || token.isIdent())) { 684 var color = parser.parseColor(token); 685 token = parser.getToken(true, true); 686 } 687 688 shadows.push({ none:false, 689 color:color, 690 offsetX:offsetX, offsetY:offsetY, 691 blurRadius:blurRadius }); 692 693 if (token.isSymbol(",")) { 694 color = ""; 695 blurRadius = "0px"; 696 offsetX = "0px"; 697 offsetY = "0px"; 698 token = parser.getToken(true, true); 699 } else if (!token.isNotNull()) { 700 return shadows; 701 } else { 702 return []; 703 } 704 } 705 } 706 return shadows; 707 }, 708 709 parseBackgroundImages:function (aString) { 710 var parser = new CSSParser(); 711 parser._init(); 712 parser.mPreserveWS = false; 713 parser.mPreserveComments = false; 714 parser.mPreservedTokens = []; 715 parser.mScanner.init(aString); 716 717 var backgrounds = []; 718 var token = parser.getToken(true, true); 719 while (token.isNotNull()) { 720 /*if (token.isFunction("rgb(") || 721 token.isFunction("rgba(") || 722 token.isFunction("hsl(") || 723 token.isFunction("hsla(") || 724 token.isSymbol("#") || 725 token.isIdent()) { 726 var color = parser.parseColor(token); 727 backgrounds.push( { type: "color", value: color }); 728 token = parser.getToken(true, true); 729 } 730 else */ 731 if (token.isFunction("url(")) { 732 token = parser.getToken(true, true); 733 var urlContent = parser.parseURL(token); 734 backgrounds.push({ type:"image", value:"url(" + urlContent }); 735 token = parser.getToken(true, true); 736 } else if (token.isFunction("-moz-linear-gradient(") || token.isFunction("-moz-radial-gradient(") || token.isFunction("-moz-repeating-linear-gradient(") || token.isFunction("-moz-repeating-radial-gradient(")) { 737 var gradient = this.parseGradient(parser, token); 738 backgrounds.push({ type:gradient.isRadial ? "radial-gradient" : "linear-gradient", value:gradient }); 739 token = parser.getToken(true, true); 740 } else { 741 return null; 742 } 743 if (token.isSymbol(",")) { 744 token = parser.getToken(true, true); 745 if (!token.isNotNull()) { 746 return null; 747 } 748 } 749 } 750 return backgrounds; 751 }, 752 753 serializeGradient:function (gradient) { 754 var s = gradient.isRadial ? (gradient.isRepeating ? "-moz-repeating-radial-gradient(" : "-moz-radial-gradient(" ) : (gradient.isRepeating ? "-moz-repeating-linear-gradient(" : "-moz-linear-gradient(" ); 755 if (gradient.angle || gradient.position) { 756 s += (gradient.angle ? gradient.angle + " " : "") + (gradient.position ? gradient.position : "") + ", "; 757 } 758 if (gradient.isRadial && (gradient.shape || gradient.size)) { 759 s += (gradient.shape ? gradient.shape : "") + " " + (gradient.size ? gradient.size : "") + ", "; 760 } 761 for (var i = 0; i < gradient.stops.length; i++) { 762 var colorstop = gradient.stops[i]; 763 s += colorstop.color + (colorstop.position ? " " + colorstop.position : ""); 764 if (i != gradient.stops.length - 1) { 765 s += ", "; 766 } 767 } 768 s += ")"; 769 return s; 770 }, 771 772 parseBorderImage:function (aString) { 773 var parser = new CSSParser(); 774 parser._init(); 775 parser.mPreserveWS = false; 776 parser.mPreserveComments = false; 777 parser.mPreservedTokens = []; 778 parser.mScanner.init(aString); 779 780 var borderImage = {url:"", offsets:[], widths:[], sizes:[]}; 781 var token = parser.getToken(true, true); 782 if (token.isFunction("url(")) { 783 token = parser.getToken(true, true); 784 var urlContent = parser.parseURL(token); 785 if (urlContent) { 786 borderImage.url = urlContent.substr(0, urlContent.length - 1).trim(); 787 if ((borderImage.url[0] == '"' && borderImage.url[borderImage.url.length - 1] == '"') || (borderImage.url[0] == "'" && borderImage.url[borderImage.url.length - 1] == "'")) { 788 borderImage.url = borderImage.url.substr(1, borderImage.url.length - 2); 789 } 790 } else { 791 return null; 792 } 793 } else { 794 return null; 795 } 796 797 token = parser.getToken(true, true); 798 if (token.isNumber() || token.isPercentage()) { 799 borderImage.offsets.push(token.value); 800 } else { 801 return null; 802 } 803 var i; 804 for (i = 0; i < 3; i++) { 805 token = parser.getToken(true, true); 806 if (token.isNumber() || token.isPercentage()) { 807 borderImage.offsets.push(token.value); 808 } else { 809 break; 810 } 811 } 812 if (i == 3) { 813 token = parser.getToken(true, true); 814 } 815 816 if (token.isSymbol("/")) { 817 token = parser.getToken(true, true); 818 if (token.isDimension() || token.isNumber("0") || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES)) { 819 borderImage.widths.push(token.value); 820 } else { 821 return null; 822 } 823 824 for (var i = 0; i < 3; i++) { 825 token = parser.getToken(true, true); 826 if (token.isDimension() || token.isNumber("0") || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES)) { 827 borderImage.widths.push(token.value); 828 } else { 829 break; 830 } 831 } 832 if (i == 3) { 833 token = parser.getToken(true, true); 834 } 835 } 836 837 for (var i = 0; i < 2; i++) { 838 if (token.isIdent("stretch") || token.isIdent("repeat") || token.isIdent("round")) { 839 borderImage.sizes.push(token.value); 840 } else if (!token.isNotNull()) { 841 return borderImage; 842 } else { 843 return null; 844 } 845 token = parser.getToken(true, true); 846 } 847 if (!token.isNotNull()) { 848 return borderImage; 849 } 850 851 return null; 852 }, 853 854 parseMediaQuery:function (aString) { 855 var kCONSTRAINTS = { 856 "width":true, 857 "min-width":true, 858 "max-width":true, 859 "height":true, 860 "min-height":true, 861 "max-height":true, 862 "device-width":true, 863 "min-device-width":true, 864 "max-device-width":true, 865 "device-height":true, 866 "min-device-height":true, 867 "max-device-height":true, 868 "orientation":true, 869 "aspect-ratio":true, 870 "min-aspect-ratio":true, 871 "max-aspect-ratio":true, 872 "device-aspect-ratio":true, 873 "min-device-aspect-ratio":true, 874 "max-device-aspect-ratio":true, 875 "color":true, 876 "min-color":true, 877 "max-color":true, 878 "color-index":true, 879 "min-color-index":true, 880 "max-color-index":true, 881 "monochrome":true, 882 "min-monochrome":true, 883 "max-monochrome":true, 884 "resolution":true, 885 "min-resolution":true, 886 "max-resolution":true, 887 "scan":true, 888 "grid":true 889 }; 890 var parser = new CSSParser(); 891 parser._init(); 892 parser.mPreserveWS = false; 893 parser.mPreserveComments = false; 894 parser.mPreservedTokens = []; 895 parser.mScanner.init(aString); 896 897 var m = {amplifier:"", medium:"", constraints:[]}; 898 var token = parser.getToken(true, true); 899 900 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")) { 901 m.medium = token.value; 902 token = parser.getToken(true, true); 903 } else if (token.isIdent("not") || token.isIdent("only")) { 904 m.amplifier = token.value; 905 token = parser.getToken(true, true); 906 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")) { 907 m.medium = token.value; 908 token = parser.getToken(true, true); 909 } else { 910 return null; 911 } 912 } 913 914 if (m.medium) { 915 if (!token.isNotNull()) { 916 return m; 917 } 918 if (token.isIdent("and")) { 919 token = parser.getToken(true, true); 920 } else { 921 return null; 922 } 923 } 924 925 while (token.isSymbol("(")) { 926 token = parser.getToken(true, true); 927 if (token.isIdent() && (token.value in kCONSTRAINTS)) { 928 var constraint = token.value; 929 token = parser.getToken(true, true); 930 if (token.isSymbol(":")) { 931 token = parser.getToken(true, true); 932 var values = []; 933 while (!token.isSymbol(")")) { 934 values.push(token.value); 935 token = parser.getToken(true, true); 936 } 937 if (token.isSymbol(")")) { 938 m.constraints.push({constraint:constraint, value:values}); 939 token = parser.getToken(true, true); 940 if (token.isNotNull()) { 941 if (token.isIdent("and")) { 942 token = parser.getToken(true, true); 943 } else { 944 return null; 945 } 946 } else { 947 return m; 948 } 949 } else { 950 return null; 951 } 952 } else if (token.isSymbol(")")) { 953 m.constraints.push({constraint:constraint, value:null}); 954 token = parser.getToken(true, true); 955 if (token.isNotNull()) { 956 if (token.isIdent("and")) { 957 token = parser.getToken(true, true); 958 } else { 959 return null; 960 } 961 } else { 962 return m; 963 } 964 } else { 965 return null; 966 } 967 } else { 968 return null; 969 } 970 } 971 return m; 972 } 973 974 }; 975 976 977 /************************************************************/ 978 /************************** JSCSSP **************************/ 979 /************************************************************/ 980 981 var CSS_ESCAPE = '\\'; 982 983 var IS_HEX_DIGIT = 1; 984 var START_IDENT = 2; 985 var IS_IDENT = 4; 986 var IS_WHITESPACE = 8; 987 988 var W = IS_WHITESPACE; 989 var I = IS_IDENT; 990 var S = START_IDENT; 991 var SI = IS_IDENT | START_IDENT; 992 var XI = IS_IDENT | IS_HEX_DIGIT; 993 var XSI = IS_IDENT | START_IDENT | IS_HEX_DIGIT; 994 995 function CSSScanner(aString) { 996 this.init(aString); 997 } 998 999 CSSScanner.prototype = { 1000 1001 kLexTable:[ 1002 // TAB LF FF CR 1003 0, 0, 0, 0, 0, 0, 0, 0, 0, W, W, 0, W, W, 0, 0, // 1004 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // SPC ! " # $ % & ' ( ) * + , - . / 1005 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 : ; < = > ? 1006 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 1007 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 [ \ ] ^ _ 1008 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 1009 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 { | } ~ 1010 SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, 0, 0, 0, 0, 0, // 1011 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1012 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ® ¯ 1013 0, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, // ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ 1014 SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, // À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï 1015 SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, // Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß 1016 SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, // à á â ã ä å æ ç è é ê ë ì í î ï 1017 SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, // ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ 1018 SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI 1019 ], 1020 1021 kHexValues:{ 1022 "0":0, "1":1, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, 1023 "a":10, "b":11, "c":12, "d":13, "e":14, "f":15 1024 }, 1025 1026 mString:"", 1027 mPos:0, 1028 mPreservedPos:[], 1029 1030 init:function (aString) { 1031 this.mString = aString; 1032 this.mPos = 0; 1033 this.mPreservedPos = []; 1034 }, 1035 1036 getCurrentPos:function () { 1037 return this.mPos; 1038 }, 1039 1040 getAlreadyScanned:function () { 1041 return this.mString.substr(0, this.mPos); 1042 }, 1043 1044 preserveState:function () { 1045 this.mPreservedPos.push(this.mPos); 1046 }, 1047 1048 restoreState:function () { 1049 if (this.mPreservedPos.length) { 1050 this.mPos = this.mPreservedPos.pop(); 1051 } 1052 }, 1053 1054 forgetState:function () { 1055 if (this.mPreservedPos.length) { 1056 this.mPreservedPos.pop(); 1057 } 1058 }, 1059 1060 read:function () { 1061 if (this.mPos < this.mString.length) { 1062 return this.mString.charAt(this.mPos++); 1063 } 1064 return -1; 1065 }, 1066 1067 peek:function () { 1068 if (this.mPos < this.mString.length) { 1069 return this.mString.charAt(this.mPos); 1070 } 1071 return -1; 1072 }, 1073 1074 isHexDigit:function (c) { 1075 var code = c.charCodeAt(0); 1076 return (code < 256 && (this.kLexTable[code] & IS_HEX_DIGIT) != 0); 1077 }, 1078 1079 isIdentStart:function (c) { 1080 var code = c.charCodeAt(0); 1081 return (code >= 256 || (this.kLexTable[code] & START_IDENT) != 0); 1082 }, 1083 1084 startsWithIdent:function (aFirstChar, aSecondChar) { 1085 var code = aFirstChar.charCodeAt(0); 1086 return this.isIdentStart(aFirstChar) || (aFirstChar == "-" && this.isIdentStart(aSecondChar)); 1087 }, 1088 1089 isIdent:function (c) { 1090 var code = c.charCodeAt(0); 1091 return (code >= 256 || (this.kLexTable[code] & IS_IDENT) != 0); 1092 }, 1093 1094 pushback:function () { 1095 this.mPos--; 1096 }, 1097 1098 nextHexValue:function () { 1099 var c = this.read(); 1100 if (c == -1 || !this.isHexDigit(c)) { 1101 return new jscsspToken(jscsspToken.NULL_TYPE, null); 1102 } 1103 var s = c; 1104 c = this.read(); 1105 while (c != -1 && this.isHexDigit(c)) { 1106 s += c; 1107 c = this.read(); 1108 } 1109 if (c != -1) { 1110 this.pushback(); 1111 } 1112 return new jscsspToken(jscsspToken.HEX_TYPE, s); 1113 }, 1114 1115 gatherEscape:function () { 1116 var c = this.peek(); 1117 if (c == -1) { 1118 return ""; 1119 } 1120 if (this.isHexDigit(c)) { 1121 var code = 0; 1122 for (var i = 0; i < 6; i++) { 1123 c = this.read(); 1124 if (this.isHexDigit(c)) { 1125 code = code * 16 + this.kHexValues[c.toLowerCase()]; 1126 } else if (!this.isHexDigit(c) && !this.isWhiteSpace(c)) { 1127 this.pushback(); 1128 break; 1129 } else { 1130 break; 1131 } 1132 } 1133 if (i == 6) { 1134 c = this.peek(); 1135 if (this.isWhiteSpace(c)) { 1136 this.read(); 1137 } 1138 } 1139 return String.fromCharCode(code); 1140 } 1141 c = this.read(); 1142 if (c != "\n") { 1143 return c; 1144 } 1145 return ""; 1146 }, 1147 1148 gatherIdent:function (c) { 1149 var s = ""; 1150 if (c == CSS_ESCAPE) { 1151 s += this.gatherEscape(); 1152 } else { 1153 s += c; 1154 } 1155 c = this.read(); 1156 while (c != -1 && (this.isIdent(c) || c == CSS_ESCAPE)) { 1157 if (c == CSS_ESCAPE) { 1158 s += this.gatherEscape(); 1159 } else { 1160 s += c; 1161 } 1162 c = this.read(); 1163 } 1164 if (c != -1) { 1165 this.pushback(); 1166 } 1167 return s; 1168 }, 1169 1170 parseIdent:function (c) { 1171 var value = this.gatherIdent(c); 1172 var nextChar = this.peek(); 1173 if (nextChar == "(") { 1174 value += this.read(); 1175 return new jscsspToken(jscsspToken.FUNCTION_TYPE, value); 1176 } 1177 return new jscsspToken(jscsspToken.IDENT_TYPE, value); 1178 }, 1179 1180 isDigit:function (c) { 1181 return (c >= '0') && (c <= '9'); 1182 }, 1183 1184 parseComment:function (c) { 1185 var s = c; 1186 while ((c = this.read()) != -1) { 1187 s += c; 1188 if (c == "*") { 1189 c = this.read(); 1190 if (c == -1) { 1191 break; 1192 } 1193 if (c == "/") { 1194 s += c; 1195 break; 1196 } 1197 this.pushback(); 1198 } 1199 } 1200 return new jscsspToken(jscsspToken.COMMENT_TYPE, s); 1201 }, 1202 1203 parseNumber:function (c) { 1204 var s = c; 1205 var foundDot = false; 1206 while ((c = this.read()) != -1) { 1207 if (c == ".") { 1208 if (foundDot) { 1209 break; 1210 } else { 1211 s += c; 1212 foundDot = true; 1213 } 1214 } else if (this.isDigit(c)) { 1215 s += c; 1216 } else { 1217 break; 1218 } 1219 } 1220 1221 if (c != -1 && this.startsWithIdent(c, this.peek())) { // DIMENSION 1222 var unit = this.gatherIdent(c); 1223 s += unit; 1224 return new jscsspToken(jscsspToken.DIMENSION_TYPE, s, unit); 1225 } else if (c == "%") { 1226 s += "%"; 1227 return new jscsspToken(jscsspToken.PERCENTAGE_TYPE, s); 1228 } else if (c != -1) { 1229 this.pushback(); 1230 } 1231 return new jscsspToken(jscsspToken.NUMBER_TYPE, s); 1232 }, 1233 1234 parseString:function (aStop) { 1235 var s = aStop; 1236 var previousChar = aStop; 1237 var c; 1238 while ((c = this.read()) != -1) { 1239 if (c == aStop && previousChar != CSS_ESCAPE) { 1240 s += c; 1241 break; 1242 } else if (c == CSS_ESCAPE) { 1243 c = this.peek(); 1244 if (c == -1) { 1245 break; 1246 } else if (c == "\n" || c == "\r" || c == "\f") { 1247 d = c; 1248 c = this.read(); 1249 // special for Opera that preserves \r\n... 1250 if (d == "\r") { 1251 c = this.peek(); 1252 if (c == "\n") { 1253 c = this.read(); 1254 } 1255 } 1256 } else { 1257 s += this.gatherEscape(); 1258 c = this.peek(); 1259 } 1260 } else if (c == "\n" || c == "\r" || c == "\f") { 1261 break; 1262 } else { 1263 s += c; 1264 } 1265 1266 previousChar = c; 1267 } 1268 return new jscsspToken(jscsspToken.STRING_TYPE, s); 1269 }, 1270 1271 isWhiteSpace:function (c) { 1272 var code = c.charCodeAt(0); 1273 return code < 256 && (this.kLexTable[code] & IS_WHITESPACE) != 0; 1274 }, 1275 1276 eatWhiteSpace:function (c) { 1277 var s = c; 1278 while ((c = this.read()) != -1) { 1279 if (!this.isWhiteSpace(c)) { 1280 break; 1281 } 1282 s += c; 1283 } 1284 if (c != -1) { 1285 this.pushback(); 1286 } 1287 return s; 1288 }, 1289 1290 parseAtKeyword:function (c) { 1291 return new jscsspToken(jscsspToken.ATRULE_TYPE, this.gatherIdent(c)); 1292 }, 1293 1294 nextToken:function () { 1295 var c = this.read(); 1296 if (c == -1) { 1297 return new jscsspToken(jscsspToken.NULL_TYPE, null); 1298 } 1299 1300 if (this.startsWithIdent(c, this.peek())) { 1301 return this.parseIdent(c); 1302 } 1303 1304 if (c == '@') { 1305 var nextChar = this.read(); 1306 if (nextChar != -1) { 1307 var followingChar = this.peek(); 1308 this.pushback(); 1309 if (this.startsWithIdent(nextChar, followingChar)) { 1310 return this.parseAtKeyword(c); 1311 } 1312 } 1313 } 1314 1315 if (c == "." || c == "+" || c == "-") { 1316 var nextChar = this.peek(); 1317 if (this.isDigit(nextChar)) { 1318 return this.parseNumber(c); 1319 } else if (nextChar == "." && c != ".") { 1320 firstChar = this.read(); 1321 var secondChar = this.peek(); 1322 this.pushback(); 1323 if (this.isDigit(secondChar)) { 1324 return this.parseNumber(c); 1325 } 1326 } 1327 } 1328 if (this.isDigit(c)) { 1329 return this.parseNumber(c); 1330 } 1331 1332 if (c == "'" || c == '"') { 1333 return this.parseString(c); 1334 } 1335 1336 if (this.isWhiteSpace(c)) { 1337 var s = this.eatWhiteSpace(c); 1338 1339 return new jscsspToken(jscsspToken.WHITESPACE_TYPE, s); 1340 } 1341 1342 if (c == "|" || c == "~" || c == "^" || c == "$" || c == "*") { 1343 var nextChar = this.read(); 1344 if (nextChar == "=") { 1345 switch (c) { 1346 case "~" : 1347 return new jscsspToken(jscsspToken.INCLUDES_TYPE, "~="); 1348 case "|" : 1349 return new jscsspToken(jscsspToken.DASHMATCH_TYPE, "|="); 1350 case "^" : 1351 return new jscsspToken(jscsspToken.BEGINSMATCH_TYPE, "^="); 1352 case "$" : 1353 return new jscsspToken(jscsspToken.ENDSMATCH_TYPE, "$="); 1354 case "*" : 1355 return new jscsspToken(jscsspToken.CONTAINSMATCH_TYPE, "*="); 1356 default : 1357 break; 1358 } 1359 } else if (nextChar != -1) { 1360 this.pushback(); 1361 } 1362 } 1363 1364 if (c == "/" && this.peek() == "*") { 1365 return this.parseComment(c); 1366 } 1367 1368 return new jscsspToken(jscsspToken.SYMBOL_TYPE, c); 1369 } 1370 }; 1371 1372 function CSSParser(aString) { 1373 this.mToken = null; 1374 this.mLookAhead = null; 1375 this.mScanner = new CSSScanner(aString); 1376 1377 this.mPreserveWS = true; 1378 this.mPreserveComments = true; 1379 1380 this.mPreservedTokens = []; 1381 1382 this.mError = null; 1383 } 1384 1385 CSSParser.prototype = { 1386 1387 _init:function () { 1388 this.mToken = null; 1389 this.mLookAhead = null; 1390 }, 1391 1392 kINHERIT:"inherit", 1393 1394 kBORDER_WIDTH_NAMES:{ 1395 "thin":true, 1396 "medium":true, 1397 "thick":true 1398 }, 1399 1400 kBORDER_STYLE_NAMES:{ 1401 "none":true, 1402 "hidden":true, 1403 "dotted":true, 1404 "dashed":true, 1405 "solid":true, 1406 "double":true, 1407 "groove":true, 1408 "ridge":true, 1409 "inset":true, 1410 "outset":true 1411 }, 1412 1413 kCOLOR_NAMES:{ 1414 "transparent":true, 1415 1416 "black":true, 1417 "silver":true, 1418 "gray":true, 1419 "white":true, 1420 "maroon":true, 1421 "red":true, 1422 "purple":true, 1423 "fuchsia":true, 1424 "green":true, 1425 "lime":true, 1426 "olive":true, 1427 "yellow":true, 1428 "navy":true, 1429 "blue":true, 1430 "teal":true, 1431 "aqua":true, 1432 1433 "aliceblue":true, 1434 "antiquewhite":true, 1435 "aqua":true, 1436 "aquamarine":true, 1437 "azure":true, 1438 "beige":true, 1439 "bisque":true, 1440 "black":true, 1441 "blanchedalmond":true, 1442 "blue":true, 1443 "blueviolet":true, 1444 "brown":true, 1445 "burlywood":true, 1446 "cadetblue":true, 1447 "chartreuse":true, 1448 "chocolate":true, 1449 "coral":true, 1450 "cornflowerblue":true, 1451 "cornsilk":true, 1452 "crimson":true, 1453 "cyan":true, 1454 "darkblue":true, 1455 "darkcyan":true, 1456 "darkgoldenrod":true, 1457 "darkgray":true, 1458 "darkgreen":true, 1459 "darkgrey":true, 1460 "darkkhaki":true, 1461 "darkmagenta":true, 1462 "darkolivegreen":true, 1463 "darkorange":true, 1464 "darkorchid":true, 1465 "darkred":true, 1466 "darksalmon":true, 1467 "darkseagreen":true, 1468 "darkslateblue":true, 1469 "darkslategray":true, 1470 "darkslategrey":true, 1471 "darkturquoise":true, 1472 "darkviolet":true, 1473 "deeppink":true, 1474 "deepskyblue":true, 1475 "dimgray":true, 1476 "dimgrey":true, 1477 "dodgerblue":true, 1478 "firebrick":true, 1479 "floralwhite":true, 1480 "forestgreen":true, 1481 "fuchsia":true, 1482 "gainsboro":true, 1483 "ghostwhite":true, 1484 "gold":true, 1485 "goldenrod":true, 1486 "gray":true, 1487 "green":true, 1488 "greenyellow":true, 1489 "grey":true, 1490 "honeydew":true, 1491 "hotpink":true, 1492 "indianred":true, 1493 "indigo":true, 1494 "ivory":true, 1495 "khaki":true, 1496 "lavender":true, 1497 "lavenderblush":true, 1498 "lawngreen":true, 1499 "lemonchiffon":true, 1500 "lightblue":true, 1501 "lightcoral":true, 1502 "lightcyan":true, 1503 "lightgoldenrodyellow":true, 1504 "lightgray":true, 1505 "lightgreen":true, 1506 "lightgrey":true, 1507 "lightpink":true, 1508 "lightsalmon":true, 1509 "lightseagreen":true, 1510 "lightskyblue":true, 1511 "lightslategray":true, 1512 "lightslategrey":true, 1513 "lightsteelblue":true, 1514 "lightyellow":true, 1515 "lime":true, 1516 "limegreen":true, 1517 "linen":true, 1518 "magenta":true, 1519 "maroon":true, 1520 "mediumaquamarine":true, 1521 "mediumblue":true, 1522 "mediumorchid":true, 1523 "mediumpurple":true, 1524 "mediumseagreen":true, 1525 "mediumslateblue":true, 1526 "mediumspringgreen":true, 1527 "mediumturquoise":true, 1528 "mediumvioletred":true, 1529 "midnightblue":true, 1530 "mintcream":true, 1531 "mistyrose":true, 1532 "moccasin":true, 1533 "navajowhite":true, 1534 "navy":true, 1535 "oldlace":true, 1536 "olive":true, 1537 "olivedrab":true, 1538 "orange":true, 1539 "orangered":true, 1540 "orchid":true, 1541 "palegoldenrod":true, 1542 "palegreen":true, 1543 "paleturquoise":true, 1544 "palevioletred":true, 1545 "papayawhip":true, 1546 "peachpuff":true, 1547 "peru":true, 1548 "pink":true, 1549 "plum":true, 1550 "powderblue":true, 1551 "purple":true, 1552 "red":true, 1553 "rosybrown":true, 1554 "royalblue":true, 1555 "saddlebrown":true, 1556 "salmon":true, 1557 "sandybrown":true, 1558 "seagreen":true, 1559 "seashell":true, 1560 "sienna":true, 1561 "silver":true, 1562 "skyblue":true, 1563 "slateblue":true, 1564 "slategray":true, 1565 "slategrey":true, 1566 "snow":true, 1567 "springgreen":true, 1568 "steelblue":true, 1569 "tan":true, 1570 "teal":true, 1571 "thistle":true, 1572 "tomato":true, 1573 "turquoise":true, 1574 "violet":true, 1575 "wheat":true, 1576 "white":true, 1577 "whitesmoke":true, 1578 "yellow":true, 1579 "yellowgreen":true, 1580 1581 "activeborder":true, 1582 "activecaption":true, 1583 "appworkspace":true, 1584 "background":true, 1585 "buttonface":true, 1586 "buttonhighlight":true, 1587 "buttonshadow":true, 1588 "buttontext":true, 1589 "captiontext":true, 1590 "graytext":true, 1591 "highlight":true, 1592 "highlighttext":true, 1593 "inactiveborder":true, 1594 "inactivecaption":true, 1595 "inactivecaptiontext":true, 1596 "infobackground":true, 1597 "infotext":true, 1598 "menu":true, 1599 "menutext":true, 1600 "scrollbar":true, 1601 "threeddarkshadow":true, 1602 "threedface":true, 1603 "threedhighlight":true, 1604 "threedlightshadow":true, 1605 "threedshadow":true, 1606 "window":true, 1607 "windowframe":true, 1608 "windowtext":true 1609 }, 1610 1611 kLIST_STYLE_TYPE_NAMES:{ 1612 "decimal":true, 1613 "decimal-leading-zero":true, 1614 "lower-roman":true, 1615 "upper-roman":true, 1616 "georgian":true, 1617 "armenian":true, 1618 "lower-latin":true, 1619 "lower-alpha":true, 1620 "upper-latin":true, 1621 "upper-alpha":true, 1622 "lower-greek":true, 1623 1624 "disc":true, 1625 "circle":true, 1626 "square":true, 1627 "none":true, 1628 1629 /* CSS 3 */ 1630 "box":true, 1631 "check":true, 1632 "diamond":true, 1633 "hyphen":true, 1634 1635 "lower-armenian":true, 1636 "cjk-ideographic":true, 1637 "ethiopic-numeric":true, 1638 "hebrew":true, 1639 "japanese-formal":true, 1640 "japanese-informal":true, 1641 "simp-chinese-formal":true, 1642 "simp-chinese-informal":true, 1643 "syriac":true, 1644 "tamil":true, 1645 "trad-chinese-formal":true, 1646 "trad-chinese-informal":true, 1647 "upper-armenian":true, 1648 "arabic-indic":true, 1649 "binary":true, 1650 "bengali":true, 1651 "cambodian":true, 1652 "khmer":true, 1653 "devanagari":true, 1654 "gujarati":true, 1655 "gurmukhi":true, 1656 "kannada":true, 1657 "lower-hexadecimal":true, 1658 "lao":true, 1659 "malayalam":true, 1660 "mongolian":true, 1661 "myanmar":true, 1662 "octal":true, 1663 "oriya":true, 1664 "persian":true, 1665 "urdu":true, 1666 "telugu":true, 1667 "tibetan":true, 1668 "upper-hexadecimal":true, 1669 "afar":true, 1670 "ethiopic-halehame-aa-et":true, 1671 "ethiopic-halehame-am-et":true, 1672 "amharic-abegede":true, 1673 "ehiopic-abegede-am-et":true, 1674 "cjk-earthly-branch":true, 1675 "cjk-heavenly-stem":true, 1676 "ethiopic":true, 1677 "ethiopic-abegede":true, 1678 "ethiopic-abegede-gez":true, 1679 "hangul-consonant":true, 1680 "hangul":true, 1681 "hiragana-iroha":true, 1682 "hiragana":true, 1683 "katakana-iroha":true, 1684 "katakana":true, 1685 "lower-norwegian":true, 1686 "oromo":true, 1687 "ethiopic-halehame-om-et":true, 1688 "sidama":true, 1689 "ethiopic-halehame-sid-et":true, 1690 "somali":true, 1691 "ethiopic-halehame-so-et":true, 1692 "tigre":true, 1693 "ethiopic-halehame-tig":true, 1694 "tigrinya-er-abegede":true, 1695 "ethiopic-abegede-ti-er":true, 1696 "tigrinya-et":true, 1697 "ethiopic-halehame-ti-et":true, 1698 "upper-greek":true, 1699 "asterisks":true, 1700 "footnotes":true, 1701 "circled-decimal":true, 1702 "circled-lower-latin":true, 1703 "circled-upper-latin":true, 1704 "dotted-decimal":true, 1705 "double-circled-decimal":true, 1706 "filled-circled-decimal":true, 1707 "parenthesised-decimal":true, 1708 "parenthesised-lower-latin":true 1709 }, 1710 1711 reportError:function (aMsg) { 1712 this.mError = aMsg; 1713 }, 1714 1715 consumeError:function () { 1716 var e = this.mError; 1717 this.mError = null; 1718 return e; 1719 }, 1720 1721 currentToken:function () { 1722 return this.mToken; 1723 }, 1724 1725 getHexValue:function () { 1726 this.mToken = this.mScanner.nextHexValue(); 1727 return this.mToken; 1728 }, 1729 1730 getToken:function (aSkipWS, aSkipComment) { 1731 if (this.mLookAhead) { 1732 this.mToken = this.mLookAhead; 1733 this.mLookAhead = null; 1734 return this.mToken; 1735 } 1736 1737 this.mToken = this.mScanner.nextToken(); 1738 while (this.mToken && ((aSkipWS && this.mToken.isWhiteSpace()) || (aSkipComment && this.mToken.isComment()))) { 1739 this.mToken = this.mScanner.nextToken(); 1740 } 1741 return this.mToken; 1742 }, 1743 1744 lookAhead:function (aSkipWS, aSkipComment) { 1745 var preservedToken = this.mToken; 1746 this.mScanner.preserveState(); 1747 var token = this.getToken(aSkipWS, aSkipComment); 1748 this.mScanner.restoreState(); 1749 this.mToken = preservedToken; 1750 1751 return token; 1752 }, 1753 1754 ungetToken:function () { 1755 this.mLookAhead = this.mToken; 1756 }, 1757 1758 addUnknownAtRule:function (aSheet, aString) { 1759 var currentLine = CountLF(this.mScanner.getAlreadyScanned()); 1760 var blocks = []; 1761 var token = this.getToken(false, false); 1762 while (token.isNotNull()) { 1763 aString += token.value; 1764 if (token.isSymbol(";") && !blocks.length) { 1765 break; 1766 } else if (token.isSymbol("{") || token.isSymbol("(") || token.isSymbol("[") || token.type == "function") { 1767 blocks.push(token.isFunction() ? "(" : token.value); 1768 } else if (token.isSymbol("}") || token.isSymbol(")") || token.isSymbol("]")) { 1769 if (blocks.length) { 1770 var ontop = blocks[blocks.length - 1]; 1771 if ((token.isSymbol("}") && ontop == "{") || (token.isSymbol(")") && ontop == "(") || (token.isSymbol("]") && ontop == "[")) { 1772 blocks.pop(); 1773 if (!blocks.length && token.isSymbol("}")) { 1774 break; 1775 } 1776 } 1777 } 1778 } 1779 token = this.getToken(false, false); 1780 } 1781 1782 this.addUnknownRule(aSheet, aString, currentLine); 1783 }, 1784 1785 addUnknownRule:function (aSheet, aString, aCurrentLine) { 1786 var errorMsg = this.consumeError(); 1787 var rule = new jscsspErrorRule(errorMsg); 1788 rule.currentLine = aCurrentLine; 1789 rule.parsedCssText = aString; 1790 rule.parentStyleSheet = aSheet; 1791 aSheet.cssRules.push(rule); 1792 }, 1793 1794 addWhitespace:function (aSheet, aString) { 1795 var rule = new jscsspWhitespace(); 1796 rule.parsedCssText = aString; 1797 rule.parentStyleSheet = aSheet; 1798 aSheet.cssRules.push(rule); 1799 }, 1800 1801 addComment:function (aSheet, aString) { 1802 var rule = new jscsspComment(); 1803 rule.parsedCssText = aString; 1804 rule.parentStyleSheet = aSheet; 1805 aSheet.cssRules.push(rule); 1806 }, 1807 1808 parseCharsetRule:function (aToken, aSheet) { 1809 var s = aToken.value; 1810 var token = this.getToken(false, false); 1811 s += token.value; 1812 if (token.isWhiteSpace(" ")) { 1813 token = this.getToken(false, false); 1814 s += token.value; 1815 if (token.isString()) { 1816 var encoding = token.value; 1817 token = this.getToken(false, false); 1818 s += token.value; 1819 if (token.isSymbol(";")) { 1820 var rule = new jscsspCharsetRule(); 1821 rule.encoding = encoding; 1822 rule.parsedCssText = s; 1823 rule.parentStyleSheet = aSheet; 1824 aSheet.cssRules.push(rule); 1825 return true; 1826 } else { 1827 this.reportError(kCHARSET_RULE_MISSING_SEMICOLON); 1828 } 1829 } else { 1830 this.reportError(kCHARSET_RULE_CHARSET_IS_STRING); 1831 } 1832 } else { 1833 this.reportError(kCHARSET_RULE_MISSING_WS); 1834 } 1835 1836 this.addUnknownAtRule(aSheet, s); 1837 return false; 1838 }, 1839 1840 parseImportRule:function (aToken, aSheet) { 1841 var currentLine = CountLF(this.mScanner.getAlreadyScanned()); 1842 var s = aToken.value; 1843 this.preserveState(); 1844 var token = this.getToken(true, true); 1845 var media = []; 1846 var href = ""; 1847 if (token.isString()) { 1848 href = token.value; 1849 s += " " + href; 1850 } else if (token.isFunction("url(")) { 1851 token = this.getToken(true, true); 1852 var urlContent = this.parseURL(token); 1853 if (urlContent) { 1854 href = "url(" + urlContent; 1855 s += " " + href; 1856 } 1857 } else { 1858 this.reportError(kIMPORT_RULE_MISSING_URL); 1859 } 1860 1861 if (href) { 1862 token = this.getToken(true, true); 1863 while (token.isIdent()) { 1864 s += " " + token.value; 1865 media.push(token.value); 1866 token = this.getToken(true, true); 1867 if (!token) { 1868 break; 1869 } 1870 if (token.isSymbol(",")) { 1871 s += ","; 1872 } else if (token.isSymbol(";")) { 1873 break; 1874 } else { 1875 break; 1876 } 1877 token = this.getToken(true, true); 1878 } 1879 1880 if (!media.length) { 1881 media.push("all"); 1882 } 1883 1884 if (token.isSymbol(";")) { 1885 s += ";" 1886 this.forgetState(); 1887 var rule = new jscsspImportRule(); 1888 rule.currentLine = currentLine; 1889 rule.parsedCssText = s; 1890 rule.href = href; 1891 rule.media = media; 1892 rule.parentStyleSheet = aSheet; 1893 aSheet.cssRules.push(rule); 1894 return true; 1895 } 1896 } 1897 1898 this.restoreState(); 1899 this.addUnknownAtRule(aSheet, "@import"); 1900 return false; 1901 }, 1902 1903 parseVariablesRule:function (token, aSheet) { 1904 var currentLine = CountLF(this.mScanner.getAlreadyScanned()); 1905 var s = token.value; 1906 var declarations = []; 1907 var valid = false; 1908 this.preserveState(); 1909 token = this.getToken(true, true); 1910 var media = []; 1911 var foundMedia = false; 1912 while (token.isNotNull()) { 1913 if (token.isIdent()) { 1914 foundMedia = true; 1915 s += " " + token.value; 1916 media.push(token.value); 1917 token = this.getToken(true, true); 1918 if (token.isSymbol(",")) { 1919 s += ","; 1920 } else { 1921 if (token.isSymbol("{")) { 1922 this.ungetToken(); 1923 } else { 1924 // error... 1925 token.type = jscsspToken.NULL_TYPE; 1926 break; 1927 } 1928 } 1929 } else if (token.isSymbol("{")) { 1930 break; 1931 } else if (foundMedia) { 1932 token.type = jscsspToken.NULL_TYPE; 1933 // not a media list 1934 break; 1935 } 1936 token = this.getToken(true, true); 1937 } 1938 1939 if (token.isSymbol("{")) { 1940 s += " {"; 1941 token = this.getToken(true, true); 1942 while (true) { 1943 if (!token.isNotNull()) { 1944 valid = true; 1945 break; 1946 } 1947 if (token.isSymbol("}")) { 1948 s += "}"; 1949 valid = true; 1950 break; 1951 } else { 1952 var d = this.parseDeclaration(token, declarations, true, false, aSheet); 1953 s += ((d && declarations.length) ? " " : "") + d; 1954 } 1955 token = this.getToken(true, false); 1956 } 1957 } 1958 if (valid) { 1959 this.forgetState(); 1960 var rule = new jscsspVariablesRule(); 1961 rule.currentLine = currentLine; 1962 rule.parsedCssText = s; 1963 rule.declarations = declarations; 1964 rule.media = media; 1965 rule.parentStyleSheet = aSheet; 1966 aSheet.cssRules.push(rule) 1967 return true; 1968 } 1969 this.restoreState(); 1970 return false; 1971 }, 1972 1973 parseNamespaceRule:function (aToken, aSheet) { 1974 var currentLine = CountLF(this.mScanner.getAlreadyScanned()); 1975 var s = aToken.value; 1976 var valid = false; 1977 this.preserveState(); 1978 var token = this.getToken(true, true); 1979 if (token.isNotNull()) { 1980 var prefix = ""; 1981 var url = ""; 1982 if (token.isIdent()) { 1983 prefix = token.value; 1984 s += " " + prefix; 1985 token = this.getToken(true, true); 1986 } 1987 if (token) { 1988 var foundURL = false; 1989 if (token.isString()) { 1990 foundURL = true; 1991 url = token.value; 1992 s += " " + url; 1993 } else if (token.isFunction("url(")) { 1994 // get a url here... 1995 token = this.getToken(true, true); 1996 var urlContent = this.parseURL(token); 1997 if (urlContent) { 1998 url += "url(" + urlContent; 1999 foundURL = true; 2000 s += " " + urlContent; 2001 } 2002 } 2003 } 2004 if (foundURL) { 2005 token = this.getToken(true, true); 2006 if (token.isSymbol(";")) { 2007 s += ";"; 2008 this.forgetState(); 2009 var rule = new jscsspNamespaceRule(); 2010 rule.currentLine = currentLine; 2011 rule.parsedCssText = s; 2012 rule.prefix = prefix; 2013 rule.url = url; 2014 rule.parentStyleSheet = aSheet; 2015 aSheet.cssRules.push(rule); 2016 return true; 2017 } 2018 } 2019 2020 } 2021 this.restoreState(); 2022 this.addUnknownAtRule(aSheet, "@namespace"); 2023 return false; 2024 }, 2025 2026 parseFontFaceRule:function (aToken, aSheet) { 2027 var currentLine = CountLF(this.mScanner.getAlreadyScanned()); 2028 var s = aToken.value; 2029 var valid = false; 2030 var descriptors = []; 2031 this.preserveState(); 2032 var token = this.getToken(true, true); 2033 if (token.isNotNull()) { 2034 // expecting block start 2035 if (token.isSymbol("{")) { 2036 s += " " + token.value; 2037 var token = this.getToken(true, false); 2038 while (true) { 2039 if (token.isSymbol("}")) { 2040 s += "}"; 2041 valid = true; 2042 break; 2043 } else { 2044 var d = this.parseDeclaration(token, descriptors, false, false, aSheet); 2045 s += ((d && descriptors.length) ? " " : "") + d; 2046 } 2047 token = this.getToken(true, false); 2048 } 2049 } 2050 } 2051 if (valid) { 2052 this.forgetState(); 2053 var rule = new jscsspFontFaceRule(); 2054 rule.currentLine = currentLine; 2055 rule.parsedCssText = s; 2056 rule.descriptors = descriptors; 2057 rule.parentStyleSheet = aSheet; 2058 aSheet.cssRules.push(rule) 2059 return true; 2060 } 2061 this.restoreState(); 2062 return false; 2063 }, 2064 2065 parsePageRule:function (aToken, aSheet) { 2066 var currentLine = CountLF(this.mScanner.getAlreadyScanned()); 2067 var s = aToken.value; 2068 var valid = false; 2069 var declarations = []; 2070 this.preserveState(); 2071 var token = this.getToken(true, true); 2072 var pageSelector = ""; 2073 if (token.isSymbol(":") || token.isIdent()) { 2074 if (token.isSymbol(":")) { 2075 pageSelector = ":"; 2076 token = this.getToken(false, false); 2077 } 2078 if (token.isIdent()) { 2079 pageSelector += token.value; 2080 s += " " + pageSelector; 2081 token = this.getToken(true, true); 2082 } 2083 } 2084 if (token.isNotNull()) { 2085 // expecting block start 2086 if (token.isSymbol("{")) { 2087 s += " " + token.value; 2088 var token = this.getToken(true, false); 2089 while (true) { 2090 if (token.isSymbol("}")) { 2091 s += "}"; 2092 valid = true; 2093 break; 2094 } else { 2095 var d = this.parseDeclaration(token, declarations, true, true, aSheet); 2096 s += ((d && declarations.length) ? " " : "") + d; 2097 } 2098 token = this.getToken(true, false); 2099 } 2100 } 2101 } 2102 if (valid) { 2103 this.forgetState(); 2104 var rule = new jscsspPageRule(); 2105 rule.currentLine = currentLine; 2106 rule.parsedCssText = s; 2107 rule.pageSelector = pageSelector; 2108 rule.declarations = declarations; 2109 rule.parentStyleSheet = aSheet; 2110 aSheet.cssRules.push(rule) 2111 return true; 2112 } 2113 this.restoreState(); 2114 return false; 2115 }, 2116 2117 parseDefaultPropertyValue:function (token, aDecl, aAcceptPriority, descriptor, aSheet) { 2118 var valueText = ""; 2119 var blocks = []; 2120 var foundPriority = false; 2121 var values = []; 2122 while (token.isNotNull()) { 2123 2124 if ((token.isSymbol(";") || token.isSymbol("}") || token.isSymbol("!")) && !blocks.length) { 2125 if (token.isSymbol("}")) { 2126 this.ungetToken(); 2127 } 2128 break; 2129 } 2130 2131 if (token.isIdent(this.kINHERIT)) { 2132 if (values.length) { 2133 return ""; 2134 } else { 2135 valueText = this.kINHERIT; 2136 var value = new jscsspVariable(kJscsspINHERIT_VALUE, aSheet); 2137 values.push(value); 2138 token = this.getToken(true, true); 2139 break; 2140 } 2141 } else if (token.isSymbol("{") || token.isSymbol("(") || token.isSymbol("[")) { 2142 blocks.push(token.value); 2143 } else if (token.isSymbol("}") || token.isSymbol("]")) { 2144 if (blocks.length) { 2145 var ontop = blocks[blocks.length - 1]; 2146 if ((token.isSymbol("}") && ontop == "{") || (token.isSymbol(")") && ontop == "(") || (token.isSymbol("]") && ontop == "[")) { 2147 blocks.pop(); 2148 } 2149 } 2150 } 2151 // XXX must find a better way to store individual values 2152 // probably a |values: []| field holding dimensions, percentages 2153 // functions, idents, numbers and symbols, in that order. 2154 if (token.isFunction()) { 2155 if (token.isFunction("var(")) { 2156 token = this.getToken(true, true); 2157 if (token.isIdent()) { 2158 var name = token.value; 2159 token = this.getToken(true, true); 2160 if (token.isSymbol(")")) { 2161 var value = new jscsspVariable(kJscsspVARIABLE_VALUE, aSheet); 2162 valueText += "var(" + name + ")"; 2163 value.name = name; 2164 values.push(value); 2165 } else { 2166 return ""; 2167 } 2168 } else { 2169 return ""; 2170 } 2171 } else { 2172 var fn = token.value; 2173 token = this.getToken(false, true); 2174 var arg = this.parseFunctionArgument(token); 2175 if (arg) { 2176 valueText += fn + arg; 2177 var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); 2178 value.value = fn + arg; 2179 values.push(value); 2180 } else { 2181 return ""; 2182 } 2183 } 2184 } else if (token.isSymbol("#")) { 2185 var color = this.parseColor(token); 2186 if (color) { 2187 valueText += color; 2188 var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); 2189 value.value = color; 2190 values.push(value); 2191 } else { 2192 return ""; 2193 } 2194 } else if (!token.isWhiteSpace() && !token.isSymbol(",")) { 2195 var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); 2196 value.value = token.value; 2197 values.push(value); 2198 valueText += token.value; 2199 } else { 2200 valueText += token.value; 2201 } 2202 token = this.getToken(false, true); 2203 } 2204 if (values.length && valueText) { 2205 this.forgetState(); 2206 aDecl.push(this._createJscsspDeclarationFromValuesArray(descriptor, values, valueText)); 2207 return valueText; 2208 } 2209 return ""; 2210 }, 2211 2212 parseMarginOrPaddingShorthand:function (token, aDecl, aAcceptPriority, aProperty) { 2213 var top = null; 2214 var bottom = null; 2215 var left = null; 2216 var right = null; 2217 2218 var values = []; 2219 while (true) { 2220 2221 if (!token.isNotNull()) { 2222 break; 2223 } 2224 2225 if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { 2226 if (token.isSymbol("}")) { 2227 this.ungetToken(); 2228 } 2229 break; 2230 } 2231 2232 else if (!values.length && token.isIdent(this.kINHERIT)) { 2233 values.push(token.value); 2234 token = this.getToken(true, true); 2235 break; 2236 } 2237 2238 else if (token.isDimension() || token.isNumber("0") || token.isPercentage() || token.isIdent("auto")) { 2239 values.push(token.value); 2240 } else { 2241 return ""; 2242 } 2243 2244 token = this.getToken(true, true); 2245 } 2246 2247 var count = values.length; 2248 switch (count) { 2249 case 1: 2250 top = values[0]; 2251 bottom = top; 2252 left = top; 2253 right = top; 2254 break; 2255 case 2: 2256 top = values[0]; 2257 bottom = top; 2258 left = values[1]; 2259 right = left; 2260 break; 2261 case 3: 2262 top = values[0]; 2263 left = values[1]; 2264 right = left; 2265 bottom = values[2]; 2266 break; 2267 case 4: 2268 top = values[0]; 2269 right = values[1]; 2270 bottom = values[2]; 2271 left = values[3]; 2272 break; 2273 default: 2274 return ""; 2275 } 2276 this.forgetState(); 2277 aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-top", top)); 2278 aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-right", right)); 2279 aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-bottom", bottom)); 2280 aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-left", left)); 2281 return top + " " + right + " " + bottom + " " + left; 2282 }, 2283 2284 parseBorderColorShorthand:function (token, aDecl, aAcceptPriority) { 2285 var top = null; 2286 var bottom = null; 2287 var left = null; 2288 var right = null; 2289 2290 var values = []; 2291 while (true) { 2292 2293 if (!token.isNotNull()) { 2294 break; 2295 } 2296 2297 if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { 2298 if (token.isSymbol("}")) { 2299 this.ungetToken(); 2300 } 2301 break; 2302 } 2303 2304 else if (!values.length && token.isIdent(this.kINHERIT)) { 2305 values.push(token.value); 2306 token = this.getToken(true, true); 2307 break; 2308 } 2309 2310 else { 2311 var color = this.parseColor(token); 2312 if (color) { 2313 values.push(color); 2314 } else { 2315 return ""; 2316 } 2317 } 2318 2319 token = this.getToken(true, true); 2320 } 2321 2322 var count = values.length; 2323 switch (count) { 2324 case 1: 2325 top = values[0]; 2326 bottom = top; 2327 left = top; 2328 right = top; 2329 break; 2330 case 2: 2331 top = values[0]; 2332 bottom = top; 2333 left = values[1]; 2334 right = left; 2335 break; 2336 case 3: 2337 top = values[0]; 2338 left = values[1]; 2339 right = left; 2340 bottom = values[2]; 2341 break; 2342 case 4: 2343 top = values[0]; 2344 right = values[1]; 2345 bottom = values[2]; 2346 left = values[3]; 2347 break; 2348 default: 2349 return ""; 2350 } 2351 this.forgetState(); 2352 aDecl.push(this._createJscsspDeclarationFromValue("border-top-color", top)); 2353 aDecl.push(this._createJscsspDeclarationFromValue("border-right-color", right)); 2354 aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-color", bottom)); 2355 aDecl.push(this._createJscsspDeclarationFromValue("border-left-color", left)); 2356 return top + " " + right + " " + bottom + " " + left; 2357 }, 2358 2359 parseCueShorthand:function (token, declarations, aAcceptPriority) { 2360 var before = ""; 2361 var after = ""; 2362 2363 var values = []; 2364 var values = []; 2365 while (true) { 2366 2367 if (!token.isNotNull()) { 2368 break; 2369 } 2370 2371 if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { 2372 if (token.isSymbol("}")) { 2373 this.ungetToken(); 2374 } 2375 break; 2376 } 2377 2378 else if (!values.length && token.isIdent(this.kINHERIT)) { 2379 values.push(token.value); 2380 } 2381 2382 else if (token.isIdent("none")) { 2383 values.push(token.value); 2384 } 2385 2386 else if (token.isFunction("url(")) { 2387 var token = this.getToken(true, true); 2388 var urlContent = this.parseURL(token); 2389 if (urlContent) { 2390 values.push("url(" + urlContent); 2391 } else { 2392 return ""; 2393 } 2394 } else { 2395 return ""; 2396 } 2397 2398 token = this.getToken(true, true); 2399 } 2400 2401 var count = values.length; 2402 switch (count) { 2403 case 1: 2404 before = values[0]; 2405 after = before; 2406 break; 2407 case 2: 2408 before = values[0]; 2409 after = values[1]; 2410 break; 2411 default: 2412 return ""; 2413 } 2414 this.forgetState(); 2415 aDecl.push(this._createJscsspDeclarationFromValue("cue-before", before)); 2416 aDecl.push(this._createJscsspDeclarationFromValue("cue-after", after)); 2417 return before + " " + after; 2418 }, 2419 2420 parsePauseShorthand:function (token, declarations, aAcceptPriority) { 2421 var before = ""; 2422 var after = ""; 2423 2424 var values = []; 2425 var values = []; 2426 while (true) { 2427 2428 if (!token.isNotNull()) { 2429 break; 2430 } 2431 2432 if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { 2433 if (token.isSymbol("}")) { 2434 this.ungetToken(); 2435 } 2436 break; 2437 } 2438 2439 else if (!values.length && token.isIdent(this.kINHERIT)) { 2440 values.push(token.value); 2441 } 2442 2443 else if (token.isDimensionOfUnit("ms") || token.isDimensionOfUnit("s") || token.isPercentage() || token.isNumber("0")) { 2444 values.push(token.value); 2445 } else { 2446 return ""; 2447 } 2448 2449 token = this.getToken(true, true); 2450 } 2451 2452 var count = values.length; 2453 switch (count) { 2454 case 1: 2455 before = values[0]; 2456 after = before; 2457 break; 2458 case 2: 2459 before = values[0]; 2460 after = values[1]; 2461 break; 2462 default: 2463 return ""; 2464 } 2465 this.forgetState(); 2466 aDecl.push(this._createJscsspDeclarationFromValue("pause-before", before)); 2467 aDecl.push(this._createJscsspDeclarationFromValue("pause-after", after)); 2468 return before + " " + after; 2469 }, 2470 2471 parseBorderWidthShorthand:function (token, aDecl, aAcceptPriority) { 2472 var top = null; 2473 var bottom = null; 2474 var left = null; 2475 var right = null; 2476 2477 var values = []; 2478 while (true) { 2479 2480 if (!token.isNotNull()) { 2481 break; 2482 } 2483 2484 if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { 2485 if (token.isSymbol("}")) { 2486 this.ungetToken(); 2487 } 2488 break; 2489 } 2490 2491 else if (!values.length && token.isIdent(this.kINHERIT)) { 2492 values.push(token.value); 2493 } 2494 2495 else if (token.isDimension() || token.isNumber("0") || (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES)) { 2496 values.push(token.value); 2497 } else { 2498 return ""; 2499 } 2500 2501 token = this.getToken(true, true); 2502 } 2503 2504 var count = values.length; 2505 switch (count) { 2506 case 1: 2507 top = values[0]; 2508 bottom = top; 2509 left = top; 2510 right = top; 2511 break; 2512 case 2: 2513 top = values[0]; 2514 bottom = top; 2515 left = values[1]; 2516 right = left; 2517 break; 2518 case 3: 2519 top = values[0]; 2520 left = values[1]; 2521 right = left; 2522 bottom = values[2]; 2523 break; 2524 case 4: 2525 top = values[0]; 2526 right = values[1]; 2527 bottom = values[2]; 2528 left = values[3]; 2529 break; 2530 default: 2531 return ""; 2532 } 2533 this.forgetState(); 2534 aDecl.push(this._createJscsspDeclarationFromValue("border-top-width", top)); 2535 aDecl.push(this._createJscsspDeclarationFromValue("border-right-width", right)); 2536 aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-width", bottom)); 2537 aDecl.push(this._createJscsspDeclarationFromValue("border-left-width", left)); 2538 return top + " " + right + " " + bottom + " " + left; 2539 }, 2540 2541 parseBorderStyleShorthand:function (token, aDecl, aAcceptPriority) { 2542 var top = null; 2543 var bottom = null; 2544 var left = null; 2545 var right = null; 2546 2547 var values = []; 2548 while (true) { 2549 2550 if (!token.isNotNull()) { 2551 break; 2552 } 2553 2554 if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { 2555 if (token.isSymbol("}")) { 2556 this.ungetToken(); 2557 } 2558 break; 2559 } 2560 2561 else if (!values.length && token.isIdent(this.kINHERIT)) { 2562 values.push(token.value); 2563 } 2564 2565 else if (token.isIdent() && token.value in this.kBORDER_STYLE_NAMES) { 2566 values.push(token.value); 2567 } else { 2568 return ""; 2569 } 2570 2571 token = this.getToken(true, true); 2572 } 2573 2574 var count = values.length; 2575 switch (count) { 2576 case 1: 2577 top = values[0]; 2578 bottom = top; 2579 left = top; 2580 right = top; 2581 break; 2582 case 2: 2583 top = values[0]; 2584 bottom = top; 2585 left = values[1]; 2586 right = left; 2587 break; 2588 case 3: 2589 top = values[0]; 2590 left = values[1]; 2591 right = left; 2592 bottom = values[2]; 2593 break; 2594 case 4: 2595 top = values[0]; 2596 right = values[1]; 2597 bottom = values[2]; 2598 left = values[3]; 2599 break; 2600 default: 2601 return ""; 2602 } 2603 this.forgetState(); 2604 aDecl.push(this._createJscsspDeclarationFromValue("border-top-style", top)); 2605 aDecl.push(this._createJscsspDeclarationFromValue("border-right-style", right)); 2606 aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-style", bottom)); 2607 aDecl.push(this._createJscsspDeclarationFromValue("border-left-style", left)); 2608 return top + " " + right + " " + bottom + " " + left; 2609 }, 2610 2611 parseBorderEdgeOrOutlineShorthand:function (token, aDecl, aAcceptPriority, aProperty) { 2612 var bWidth = null; 2613 var bStyle = null; 2614 var bColor = null; 2615 2616 while (true) { 2617 if (!token.isNotNull()) { 2618 break; 2619 } 2620 2621 if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { 2622 if (token.isSymbol("}")) { 2623 this.ungetToken(); 2624 } 2625 break; 2626 } 2627 2628 else if (!bWidth && !bStyle && !bColor && token.isIdent(this.kINHERIT)) { 2629 bWidth = this.kINHERIT; 2630 bStyle = this.kINHERIT; 2631 bColor = this.kINHERIT; 2632 } 2633 2634 else if (!bWidth && (token.isDimension() || (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES) || token.isNumber("0"))) { 2635 bWidth = token.value; 2636 } 2637 2638 else if (!bStyle && (token.isIdent() && token.value in this.kBORDER_STYLE_NAMES)) { 2639 bStyle = token.value; 2640 } 2641 2642 else { 2643 var color = (aProperty == "outline" && token.isIdent("invert")) ? "invert" : this.parseColor(token); 2644 if (!bColor && color) { 2645 bColor = color; 2646 } else { 2647 return ""; 2648 } 2649 } 2650 token = this.getToken(true, true); 2651 } 2652 2653 // create the declarations 2654 this.forgetState(); 2655 bWidth = bWidth ? bWidth : "medium"; 2656 bStyle = bStyle ? bStyle : "none"; 2657 bColor = bColor ? bColor : "-moz-initial"; 2658 2659 function addPropertyToDecl(aSelf, aDecl, property, w, s, c) { 2660 aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-width", w)); 2661 aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-style", s)); 2662 aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-color", c)); 2663 } 2664 2665 if (aProperty == "border") { 2666 addPropertyToDecl(this, aDecl, "border-top", bWidth, bStyle, bColor); 2667 addPropertyToDecl(this, aDecl, "border-right", bWidth, bStyle, bColor); 2668 addPropertyToDecl(this, aDecl, "border-bottom", bWidth, bStyle, bColor); 2669 addPropertyToDecl(this, aDecl, "border-left", bWidth, bStyle, bColor); 2670 } else { 2671 addPropertyToDecl(this, aDecl, aProperty, bWidth, bStyle, bColor); 2672 } 2673 return bWidth + " " + bStyle + " " + bColor; 2674 }, 2675 2676 parseBackgroundShorthand:function (token, aDecl, aAcceptPriority) { 2677 var kHPos = {"left":true, "right":true }; 2678 var kVPos = {"top":true, "bottom":true }; 2679 var kPos = {"left":true, "right":true, "top":true, "bottom":true, "center":true}; 2680 2681 var bgColor = null; 2682 var bgRepeat = null; 2683 var bgAttachment = null; 2684 var bgImage = null; 2685 var bgPosition = null; 2686 2687 while (true) { 2688 2689 if (!token.isNotNull()) { 2690 break; 2691 } 2692 2693 if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { 2694 if (token.isSymbol("}")) { 2695 this.ungetToken(); 2696 } 2697 break; 2698 } 2699 2700 else if (!bgColor && !bgRepeat && !bgAttachment && !bgImage && !bgPosition && token.isIdent(this.kINHERIT)) { 2701 bgColor = this.kINHERIT; 2702 bgRepeat = this.kINHERIT; 2703 bgAttachment = this.kINHERIT; 2704 bgImage = this.kINHERIT; 2705 bgPosition = this.kINHERIT; 2706 } 2707 2708 else { 2709 if (!bgAttachment && (token.isIdent("scroll") || token.isIdent("fixed"))) { 2710 bgAttachment = token.value; 2711 } 2712 2713 else if (!bgPosition && ((token.isIdent() && token.value in kPos) || token.isDimension() || token.isNumber("0") || token.isPercentage())) { 2714 bgPosition = token.value; 2715 token = this.getToken(true, true); 2716 if (token.isDimension() || token.isNumber("0") || token.isPercentage()) { 2717 bgPosition += " " + token.value; 2718 } else if (token.isIdent() && token.value in kPos) { 2719 if ((bgPosition in kHPos && token.value in kHPos) || (bgPosition in kVPos && token.value in kVPos)) { 2720 return ""; 2721 } 2722 bgPosition += " " + token.value; 2723 } else { 2724 this.ungetToken(); 2725 bgPosition += " center"; 2726 } 2727 } 2728 2729 else if (!bgRepeat && (token.isIdent("repeat") || token.isIdent("repeat-x") || token.isIdent("repeat-y") || token.isIdent("no-repeat"))) { 2730 bgRepeat = token.value; 2731 } 2732 2733 else if (!bgImage && (token.isFunction("url(") || token.isIdent("none"))) { 2734 bgImage = token.value; 2735 if (token.isFunction("url(")) { 2736 token = this.getToken(true, true); 2737 var url = this.parseURL(token); // TODO 2738 if (url) { 2739 bgImage += url; 2740 } else { 2741 return ""; 2742 } 2743 } 2744 } 2745 2746 else if (!bgImage && (token.isFunction("-moz-linear-gradient(") || token.isFunction("-moz-radial-gradient(") || token.isFunction("-moz-repeating-linear-gradient(") || token.isFunction("-moz-repeating-radial-gradient("))) { 2747 var gradient = CssInspector.parseGradient(this, token); 2748 if (gradient) { 2749 bgImage = CssInspector.serializeGradient(gradient); 2750 } else { 2751 return ""; 2752 } 2753 } 2754 2755 else { 2756 var color = this.parseColor(token); 2757 if (!bgColor && color) { 2758 bgColor = color; 2759 } else { 2760 return ""; 2761 } 2762 } 2763 2764 } 2765 2766 token = this.getToken(true, true); 2767 } 2768 2769 // create the declarations 2770 this.forgetState(); 2771 bgColor = bgColor ? bgColor : "transparent"; 2772 bgImage = bgImage ? bgImage : "none"; 2773 bgRepeat = bgRepeat ? bgRepeat : "repeat"; 2774 bgAttachment = bgAttachment ? bgAttachment : "scroll"; 2775 bgPosition = bgPosition ? bgPosition : "top left"; 2776 2777 aDecl.push(this._createJscsspDeclarationFromValue("background-color", bgColor)); 2778 aDecl.push(this._createJscsspDeclarationFromValue("background-image", bgImage)); 2779 aDecl.push(this._createJscsspDeclarationFromValue("background-repeat", bgRepeat)); 2780 aDecl.push(this._createJscsspDeclarationFromValue("background-attachment", bgAttachment)); 2781 aDecl.push(this._createJscsspDeclarationFromValue("background-position", bgPosition)); 2782 return bgColor + " " + bgImage + " " + bgRepeat + " " + bgAttachment + " " + bgPosition; 2783 }, 2784 2785 parseListStyleShorthand:function (token, aDecl, aAcceptPriority) { 2786 var kPosition = { "inside":true, "outside":true }; 2787 2788 var lType = null; 2789 var lPosition = null; 2790 var lImage = null; 2791 2792 while (true) { 2793 2794 if (!token.isNotNull()) { 2795 break; 2796 } 2797 2798 if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { 2799 if (token.isSymbol("}")) { 2800 this.ungetToken(); 2801 } 2802 break; 2803 } 2804 2805 else if (!lType && !lPosition && !lImage && token.isIdent(this.kINHERIT)) { 2806 lType = this.kINHERIT; 2807 lPosition = this.kINHERIT; 2808 lImage = this.kINHERIT; 2809 } 2810 2811 else if (!lType && (token.isIdent() && token.value in this.kLIST_STYLE_TYPE_NAMES)) { 2812 lType = token.value; 2813 } 2814 2815 else if (!lPosition && (token.isIdent() && token.value in kPosition)) { 2816 lPosition = token.value; 2817 } 2818 2819 else if (!lImage && token.isFunction("url")) { 2820 token = this.getToken(true, true); 2821 var urlContent = this.parseURL(token); 2822 if (urlContent) { 2823 lImage = "url(" + urlContent; 2824 } else { 2825 return ""; 2826 } 2827 } else if (!token.isIdent("none")) { 2828 return ""; 2829 } 2830 2831 token = this.getToken(true, true); 2832 } 2833 2834 // create the declarations 2835 this.forgetState(); 2836 lType = lType ? lType : "none"; 2837 lImage = lImage ? lImage : "none"; 2838 lPosition = lPosition ? lPosition : "outside"; 2839 2840 aDecl.push(this._createJscsspDeclarationFromValue("list-style-type", lType)); 2841 aDecl.push(this._createJscsspDeclarationFromValue("list-style-position", lPosition)); 2842 aDecl.push(this._createJscsspDeclarationFromValue("list-style-image", lImage)); 2843 return lType + " " + lPosition + " " + lImage; 2844 }, 2845 2846 parseFontShorthand:function (token, aDecl, aAcceptPriority) { 2847 var kStyle = {"italic":true, "oblique":true }; 2848 var kVariant = {"small-caps":true }; 2849 var kWeight = { "bold":true, "bolder":true, "lighter":true, 2850 "100":true, "200":true, "300":true, "400":true, 2851 "500":true, "600":true, "700":true, "800":true, 2852 "900":true }; 2853 var kSize = { "xx-small":true, "x-small":true, "small":true, "medium":true, 2854 "large":true, "x-large":true, "xx-large":true, 2855 "larger":true, "smaller":true }; 2856 var kValues = { "caption":true, "icon":true, "menu":true, "message-box":true, "small-caption":true, "status-bar":true }; 2857 var kFamily = { "serif":true, "sans-serif":true, "cursive":true, "fantasy":true, "monospace":true }; 2858 2859 var fStyle = null; 2860 var fVariant = null; 2861 var fWeight = null; 2862 var fSize = null; 2863 var fLineHeight = null; 2864 var fFamily = ""; 2865 var fSystem = null; 2866 var fFamilyValues = []; 2867 2868 var normalCount = 0; 2869 while (true) { 2870 2871 if (!token.isNotNull()) { 2872 break; 2873 } 2874 2875 if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { 2876 if (token.isSymbol("}")) { 2877 this.ungetToken(); 2878 } 2879 break; 2880 } 2881 2882 else if (!fStyle && !fVariant && !fWeight && !fSize && !fLineHeight && !fFamily && !fSystem && token.isIdent(this.kINHERIT)) { 2883 fStyle = this.kINHERIT; 2884 fVariant = this.kINHERIT; 2885 fWeight = this.kINHERIT; 2886 fSize = this.kINHERIT; 2887 fLineHeight = this.kINHERIT; 2888 fFamily = this.kINHERIT; 2889 fSystem = this.kINHERIT; 2890 } 2891 2892 else { 2893 if (!fSystem && (token.isIdent() && token.value in kValues)) { 2894 fSystem = token.value; 2895 break; 2896 } 2897 2898 else { 2899 if (!fStyle && token.isIdent() && (token.value in kStyle)) { 2900 fStyle = token.value; 2901 } 2902 2903 else if (!fVariant && token.isIdent() && (token.value in kVariant)) { 2904 fVariant = token.value; 2905 } 2906 2907 else if (!fWeight && (token.isIdent() || token.isNumber()) && (token.value in kWeight)) { 2908 fWeight = token.value; 2909 } 2910 2911 else if (!fSize && ((token.isIdent() && (token.value in kSize)) || token.isDimension() || token.isPercentage())) { 2912 fSize = token.value; 2913 var token = this.getToken(false, false); 2914 if (token.isSymbol("/")) { 2915 token = this.getToken(false, false); 2916 if (!fLineHeight && (token.isDimension() || token.isNumber() || token.isPercentage())) { 2917 fLineHeight = token.value; 2918 } else { 2919 return ""; 2920 } 2921 } else { 2922 this.ungetToken(); 2923 } 2924 } 2925 2926 else if (token.isIdent("normal")) { 2927 normalCount++; 2928 if (normalCount > 3) { 2929 return ""; 2930 } 2931 } 2932 2933 else if (!fFamily && // *MUST* be last to be tested here 2934 (token.isString() || token.isIdent())) { 2935 var lastWasComma = false; 2936 while (true) { 2937 if (!token.isNotNull()) { 2938 break; 2939 } else if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { 2940 this.ungetToken(); 2941 break; 2942 } else if (token.isIdent() && token.value in kFamily) { 2943 var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null); 2944 value.value = token.value; 2945 fFamilyValues.push(value); 2946 fFamily += token.value; 2947 break; 2948 } else if (token.isString() || token.isIdent()) { 2949 var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null); 2950 value.value = token.value; 2951 fFamilyValues.push(value); 2952 fFamily += token.value; 2953 lastWasComma = false; 2954 } else if (!lastWasComma && token.isSymbol(",")) { 2955 fFamily += ", "; 2956 lastWasComma = true; 2957 } else { 2958 return ""; 2959 } 2960 token = this.getToken(true, true); 2961 } 2962 } 2963 2964 else { 2965 return ""; 2966 } 2967 } 2968 2969 } 2970 2971 token = this.getToken(true, true); 2972 } 2973 2974 // create the declarations 2975 this.forgetState(); 2976 if (fSystem) { 2977 aDecl.push(this._createJscsspDeclarationFromValue("font", fSystem)); 2978 return fSystem; 2979 } 2980 fStyle = fStyle ? fStyle : "normal"; 2981 fVariant = fVariant ? fVariant : "normal"; 2982 fWeight = fWeight ? fWeight : "normal"; 2983 fSize = fSize ? fSize : "medium"; 2984 fLineHeight = fLineHeight ? fLineHeight : "normal"; 2985 fFamily = fFamily ? fFamily : "-moz-initial"; 2986 2987 aDecl.push(this._createJscsspDeclarationFromValue("font-style", fStyle)); 2988 aDecl.push(this._createJscsspDeclarationFromValue("font-variant", fVariant)); 2989 aDecl.push(this._createJscsspDeclarationFromValue("font-weight", fWeight)); 2990 aDecl.push(this._createJscsspDeclarationFromValue("font-size", fSize)); 2991 aDecl.push(this._createJscsspDeclarationFromValue("line-height", fLineHeight)); 2992 aDecl.push(this._createJscsspDeclarationFromValuesArray("font-family", fFamilyValues, fFamily)); 2993 return fStyle + " " + fVariant + " " + fWeight + " " + fSize + "/" + fLineHeight + " " + fFamily; 2994 }, 2995 2996 _createJscsspDeclaration:function (property, value) { 2997 var decl = new jscsspDeclaration(); 2998 decl.property = property; 2999 decl.value = this.trim11(value); 3000 decl.parsedCssText = property + ": " + value + ";"; 3001 return decl; 3002 }, 3003 3004 _createJscsspDeclarationFromValue:function (property, valueText) { 3005 var decl = new jscsspDeclaration(); 3006 decl.property = property; 3007 var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null); 3008 value.value = valueText; 3009 decl.values = [value]; 3010 decl.valueText = valueText; 3011 decl.parsedCssText = property + ": " + valueText + ";"; 3012 return decl; 3013 }, 3014 3015 _createJscsspDeclarationFromValuesArray:function (property, values, valueText) { 3016 var decl = new jscsspDeclaration(); 3017 decl.property = property; 3018 decl.values = values; 3019 decl.valueText = valueText; 3020 decl.parsedCssText = property + ": " + valueText + ";"; 3021 return decl; 3022 }, 3023 3024 parseURL:function (token) { 3025 var value = ""; 3026 if (token.isString()) { 3027 value += token.value; 3028 token = this.getToken(true, true); 3029 } else { 3030 while (true) { 3031 if (!token.isNotNull()) { 3032 this.reportError(kURL_EOF); 3033 return ""; 3034 } 3035 if (token.isWhiteSpace()) { 3036 nextToken = this.lookAhead(true, true); 3037 // if next token is not a closing parenthesis, that's an error 3038 if (!nextToken.isSymbol(")")) { 3039 this.reportError(kURL_WS_INSIDE); 3040 token = this.currentToken(); 3041 break; 3042 } 3043 } 3044 if (token.isSymbol(")")) { 3045 break; 3046 } 3047 value += token.value; 3048 token = this.getToken(false, false); 3049 } 3050 } 3051 3052 if (token.isSymbol(")")) { 3053 return value + ")"; 3054 } 3055 return ""; 3056 }, 3057 3058 parseFunctionArgument:function (token) { 3059 var value = ""; 3060 if (token.isString()) { 3061 value += token.value; 3062 token = this.getToken(true, true); 3063 } else { 3064 var parenthesis = 1; 3065 while (true) { 3066 if (!token.isNotNull()) { 3067 return ""; 3068 } 3069 if (token.isFunction() || token.isSymbol("(")) { 3070 parenthesis++; 3071 } 3072 if (token.isSymbol(")")) { 3073 parenthesis--; 3074 if (!parenthesis) { 3075 break; 3076 } 3077 } 3078 value += token.value; 3079 token = this.getToken(false, false); 3080 } 3081 } 3082 3083 if (token.isSymbol(")")) { 3084 return value + ")"; 3085 } 3086 return ""; 3087 }, 3088 3089 parseColor:function (token) { 3090 var color = ""; 3091 if (token.isFunction("rgb(") || token.isFunction("rgba(")) { 3092 color = token.value; 3093 var isRgba = token.isFunction("rgba(") 3094 token = this.getToken(true, true); 3095 if (!token.isNumber() && !token.isPercentage()) { 3096 return ""; 3097 } 3098 color += token.value; 3099 token = this.getToken(true, true); 3100 if (!token.isSymbol(",")) { 3101 return ""; 3102 } 3103 color += ", "; 3104 3105 token = this.getToken(true, true); 3106 if (!token.isNumber() && !token.isPercentage()) { 3107 return ""; 3108 } 3109 color += token.value; 3110 token = this.getToken(true, true); 3111 if (!token.isSymbol(",")) { 3112 return ""; 3113 } 3114 color += ", "; 3115 3116 token = this.getToken(true, true); 3117 if (!token.isNumber() && !token.isPercentage()) { 3118 return ""; 3119 } 3120 color += token.value; 3121 3122 if (isRgba) { 3123 token = this.getToken(true, true); 3124 if (!token.isSymbol(",")) { 3125 return ""; 3126 } 3127 color += ", "; 3128 3129 token = this.getToken(true, true); 3130 if (!token.isNumber()) { 3131 return ""; 3132 } 3133 color += token.value; 3134 } 3135 3136 token = this.getToken(true, true); 3137 if (!token.isSymbol(")")) { 3138 return ""; 3139 } 3140 color += token.value; 3141 } 3142 3143 else if (token.isFunction("hsl(") || token.isFunction("hsla(")) { 3144 color = token.value; 3145 var isHsla = token.isFunction("hsla(") 3146 token = this.getToken(true, true); 3147 if (!token.isNumber()) { 3148 return ""; 3149 } 3150 color += token.value; 3151 token = this.getToken(true, true); 3152 if (!token.isSymbol(",")) { 3153 return ""; 3154 } 3155 color += ", "; 3156 3157 token = this.getToken(true, true); 3158 if (!token.isPercentage()) { 3159 return ""; 3160 } 3161 color += token.value; 3162 token = this.getToken(true, true); 3163 if (!token.isSymbol(",")) { 3164 return ""; 3165 } 3166 color += ", "; 3167 3168 token = this.getToken(true, true); 3169 if (!token.isPercentage()) { 3170 return ""; 3171 } 3172 color += token.value; 3173 3174 if (isHsla) { 3175 token = this.getToken(true, true); 3176 if (!token.isSymbol(",")) { 3177 return ""; 3178 } 3179 color += ", "; 3180 3181 token = this.getToken(true, true); 3182 if (!token.isNumber()) { 3183 return ""; 3184 } 3185 color += token.value; 3186 } 3187 3188 token = this.getToken(true, true); 3189 if (!token.isSymbol(")")) { 3190 return ""; 3191 } 3192 color += token.value; 3193 } 3194 3195 else if (token.isIdent() && (token.value in this.kCOLOR_NAMES)) { 3196 color = token.value; 3197 } 3198 3199 else if (token.isSymbol("#")) { 3200 token = this.getHexValue(); 3201 if (!token.isHex()) { 3202 return ""; 3203 } 3204 var length = token.value.length; 3205 if (length != 3 && length != 6) { 3206 return ""; 3207 } 3208 if (token.value.match(/[a-fA-F0-9]/g).length != length) { 3209 return ""; 3210 } 3211 color = "#" + token.value; 3212 } 3213 return color; 3214 }, 3215 3216 parseDeclaration:function (aToken, aDecl, aAcceptPriority, aExpandShorthands, aSheet) { 3217 this.preserveState(); 3218 var blocks = []; 3219 if (aToken.isIdent()) { 3220 var descriptor = aToken.value.toLowerCase(); 3221 var token = this.getToken(true, true); 3222 if (token.isSymbol(":")) { 3223 var token = this.getToken(true, true); 3224 3225 var value = ""; 3226 var declarations = []; 3227 if (aExpandShorthands) { 3228 switch (descriptor) { 3229 case "background": 3230 value = this.parseBackgroundShorthand(token, declarations, aAcceptPriority); 3231 break; 3232 case "margin": 3233 case "padding": 3234 value = this.parseMarginOrPaddingShorthand(token, declarations, aAcceptPriority, descriptor); 3235 break; 3236 case "border-color": 3237 value = this.parseBorderColorShorthand(token, declarations, aAcceptPriority); 3238 break; 3239 case "border-style": 3240 value = this.parseBorderStyleShorthand(token, declarations, aAcceptPriority); 3241 break; 3242 case "border-width": 3243 value = this.parseBorderWidthShorthand(token, declarations, aAcceptPriority); 3244 break; 3245 case "border-top": 3246 case "border-right": 3247 case "border-bottom": 3248 case "border-left": 3249 case "border": 3250 case "outline": 3251 value = this.parseBorderEdgeOrOutlineShorthand(token, declarations, aAcceptPriority, descriptor); 3252 break; 3253 case "cue": 3254 value = this.parseCueShorthand(token, declarations, aAcceptPriority); 3255 break; 3256 case "pause": 3257 value = this.parsePauseShorthand(token, declarations, aAcceptPriority); 3258 break; 3259 case "font": 3260 value = this.parseFontShorthand(token, declarations, aAcceptPriority); 3261 break; 3262 case "list-style": 3263 value = this.parseListStyleShorthand(token, declarations, aAcceptPriority); 3264 break; 3265 default: 3266 value = this.parseDefaultPropertyValue(token, declarations, aAcceptPriority, descriptor, aSheet); 3267 break; 3268 } 3269 } else { 3270 value = this.parseDefaultPropertyValue(token, declarations, aAcceptPriority, descriptor, aSheet); 3271 } 3272 token = this.currentToken(); 3273 if (value) // no error above 3274 { 3275 var priority = false; 3276 if (token.isSymbol("!")) { 3277 token = this.getToken(true, true); 3278 if (token.isIdent("important")) { 3279 priority = true; 3280 token = this.getToken(true, true); 3281 if (token.isSymbol(";") || token.isSymbol("}")) { 3282 if (token.isSymbol("}")) { 3283 this.ungetToken(); 3284 } 3285 } else { 3286 return ""; 3287 } 3288 } else { 3289 return ""; 3290 } 3291 } else if (token.isNotNull() && !token.isSymbol(";") && !token.isSymbol("}")) { 3292 return ""; 3293 } 3294 for (var i = 0; i < declarations.length; i++) { 3295 declarations[i].priority = priority; 3296 aDecl.push(declarations[i]); 3297 } 3298 return descriptor + ": " + value + ";"; 3299 } 3300 } 3301 } else if (aToken.isComment()) { 3302 if (this.mPreserveComments) { 3303 this.forgetState(); 3304 var comment = new jscsspComment(); 3305 comment.parsedCssText = aToken.value; 3306 aDecl.push(comment); 3307 } 3308 return aToken.value; 3309 } 3310 3311 // we have an error here, let's skip it 3312 this.restoreState(); 3313 var s = aToken.value; 3314 blocks = []; 3315 var token = this.getToken(false, false); 3316 while (token.isNotNull()) { 3317 s += token.value; 3318 if ((token.isSymbol(";") || token.isSymbol("}")) && !blocks.length) { 3319 if (token.isSymbol("}")) { 3320 this.ungetToken(); 3321 } 3322 break; 3323 } else if (token.isSymbol("{") || token.isSymbol("(") || token.isSymbol("[") || token.isFunction()) { 3324 blocks.push(token.isFunction() ? "(" : token.value); 3325 } else if (token.isSymbol("}") || token.isSymbol(")") || token.isSymbol("]")) { 3326 if (blocks.length) { 3327 var ontop = blocks[blocks.length - 1]; 3328 if ((token.isSymbol("}") && ontop == "{") || (token.isSymbol(")") && ontop == "(") || (token.isSymbol("]") && ontop == "[")) { 3329 blocks.pop(); 3330 } 3331 } 3332 } 3333 token = this.getToken(false, false); 3334 } 3335 return ""; 3336 }, 3337 3338 parseMediaRule:function (aToken, aSheet) { 3339 var currentLine = CountLF(this.mScanner.getAlreadyScanned()); 3340 var s = aToken.value; 3341 var valid = false; 3342 var mediaRule = new jscsspMediaRule(); 3343 mediaRule.currentLine = currentLine; 3344 this.preserveState(); 3345 var token = this.getToken(true, true); 3346 var foundMedia = false; 3347 while (token.isNotNull()) { 3348 if (token.isIdent()) { 3349 foundMedia = true; 3350 s += " " + token.value; 3351 mediaRule.media.push(token.value); 3352 token = this.getToken(true, true); 3353 if (token.isSymbol(",")) { 3354 s += ","; 3355 } else { 3356 if (token.isSymbol("{")) { 3357 this.ungetToken(); 3358 } else { 3359 // error... 3360 token.type = jscsspToken.NULL_TYPE; 3361 break; 3362 } 3363 } 3364 } else if (token.isSymbol("{")) { 3365 break; 3366 } else if (foundMedia) { 3367 token.type = jscsspToken.NULL_TYPE; 3368 // not a media list 3369 break; 3370 } 3371 token = this.getToken(true, true); 3372 } 3373 if (token.isSymbol("{") && mediaRule.media.length) { 3374 // ok let's parse style rules now... 3375 s += " { "; 3376 token = this.getToken(true, false); 3377 while (token.isNotNull()) { 3378 if (token.isComment() && this.mPreserveComments) { 3379 s += " " + token.value; 3380 var comment = new jscsspComment(); 3381 comment.parsedCssText = token.value; 3382 mediaRule.cssRules.push(comment); 3383 } else if (token.isSymbol("}")) { 3384 valid = true; 3385 break; 3386 } else { 3387 var r = this.parseStyleRule(token, mediaRule, true); 3388 if (r) { 3389 s += r; 3390 } 3391 } 3392 token = this.getToken(true, false); 3393 } 3394 } 3395 if (valid) { 3396 this.forgetState(); 3397 mediaRule.parsedCssText = s; 3398 aSheet.cssRules.push(mediaRule); 3399 return true; 3400 } 3401 this.restoreState(); 3402 return false; 3403 }, 3404 3405 trim11:function (str) { 3406 str = str.replace(/^\s+/, ''); 3407 for (var i = str.length - 1; i >= 0; i--) { 3408 if (/\S/.test(str.charAt(i))) { // XXX charat 3409 str = str.substring(0, i + 1); 3410 break; 3411 } 3412 } 3413 return str; 3414 }, 3415 3416 parseStyleRule:function (aToken, aOwner, aIsInsideMediaRule) { 3417 var currentLine = CountLF(this.mScanner.getAlreadyScanned()); 3418 this.preserveState(); 3419 // first let's see if we have a selector here... 3420 var selector = this.parseSelector(aToken, false); 3421 var valid = false; 3422 var declarations = []; 3423 if (selector) { 3424 selector = this.trim11(selector.selector); 3425 var s = selector; 3426 var token = this.getToken(true, true); 3427 if (token.isSymbol("{")) { 3428 s += " { "; 3429 var token = this.getToken(true, false); 3430 while (true) { 3431 if (!token.isNotNull()) { 3432 valid = true; 3433 break; 3434 } 3435 if (token.isSymbol("}")) { 3436 s += "}"; 3437 valid = true; 3438 break; 3439 } else { 3440 var d = this.parseDeclaration(token, declarations, true, true, aOwner); 3441 s += ((d && declarations.length) ? " " : "") + d; 3442 } 3443 token = this.getToken(true, false); 3444 } 3445 } 3446 } else { 3447 // selector is invalid so the whole rule is invalid with it 3448 } 3449 3450 if (valid) { 3451 var rule = new jscsspStyleRule(); 3452 rule.currentLine = currentLine; 3453 rule.parsedCssText = s; 3454 rule.declarations = declarations; 3455 rule.mSelectorText = selector; 3456 if (aIsInsideMediaRule) { 3457 rule.parentRule = aOwner; 3458 } else { 3459 rule.parentStyleSheet = aOwner; 3460 } 3461 aOwner.cssRules.push(rule); 3462 return s; 3463 } 3464 this.restoreState(); 3465 s = this.currentToken().value; 3466 this.addUnknownAtRule(aOwner, s); 3467 return ""; 3468 }, 3469 3470 parseSelector:function (aToken, aParseSelectorOnly) { 3471 var s = ""; 3472 var specificity = {a:0, b:0, c:0, d:0}; // CSS 2.1 section 6.4.3 3473 var isFirstInChain = true; 3474 var token = aToken; 3475 var valid = false; 3476 var combinatorFound = false; 3477 while (true) { 3478 if (!token.isNotNull()) { 3479 if (aParseSelectorOnly) { 3480 return {selector:s, specificity:specificity }; 3481 } 3482 return ""; 3483 } 3484 3485 if (!aParseSelectorOnly && token.isSymbol("{")) { 3486 // end of selector 3487 valid = !combinatorFound; 3488 // don't unget if invalid since addUnknownRule is going to restore state anyway 3489 if (valid) { 3490 this.ungetToken(); 3491 } 3492 break; 3493 } 3494 3495 if (token.isSymbol(",")) { // group of selectors 3496 s += token.value; 3497 isFirstInChain = true; 3498 combinatorFound = false; 3499 token = this.getToken(false, true); 3500 continue; 3501 } 3502 // now combinators and grouping... 3503 else if (!combinatorFound && (token.isWhiteSpace() || token.isSymbol(">") || token.isSymbol("+") || token.isSymbol("~"))) { 3504 if (token.isWhiteSpace()) { 3505 s += " "; 3506 var nextToken = this.lookAhead(true, true); 3507 if (!nextToken.isNotNull()) { 3508 if (aParseSelectorOnly) { 3509 return {selector:s, specificity:specificity }; 3510 } 3511 return ""; 3512 } 3513 if (nextToken.isSymbol(">") || nextToken.isSymbol("+") || nextToken.isSymbol("~")) { 3514 token = this.getToken(true, true); 3515 s += token.value + " "; 3516 combinatorFound = true; 3517 } 3518 } else { 3519 s += token.value; 3520 combinatorFound = true; 3521 } 3522 isFirstInChain = true; 3523 token = this.getToken(true, true); 3524 continue; 3525 } else { 3526 var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, true); 3527 if (!simpleSelector) { 3528 break; 3529 } // error 3530 s += simpleSelector.selector; 3531 specificity.b += simpleSelector.specificity.b; 3532 specificity.c += simpleSelector.specificity.c; 3533 specificity.d += simpleSelector.specificity.d; 3534 isFirstInChain = false; 3535 combinatorFound = false; 3536 } 3537 3538 token = this.getToken(false, true); 3539 } 3540 3541 if (valid) { 3542 return {selector:s, specificity:specificity }; 3543 } 3544 return ""; 3545 }, 3546 3547 isPseudoElement:function (aIdent) { 3548 switch (aIdent) { 3549 case "first-letter": 3550 case "first-line": 3551 case "before": 3552 case "after": 3553 case "marker": 3554 return true; 3555 break; 3556 default: 3557 return false; 3558 break; 3559 } 3560 }, 3561 3562 parseSimpleSelector:function (token, isFirstInChain, canNegate) { 3563 var s = ""; 3564 var specificity = {a:0, b:0, c:0, d:0}; // CSS 2.1 section 6.4.3 3565 3566 if (isFirstInChain && (token.isSymbol("*") || token.isSymbol("|") || token.isIdent())) { 3567 // type or universal selector 3568 if (token.isSymbol("*") || token.isIdent()) { 3569 // we don't know yet if it's a prefix or a universal 3570 // selector 3571 s += token.value; 3572 var isIdent = token.isIdent(); 3573 token = this.getToken(false, true); 3574 if (token.isSymbol("|")) { 3575 // it's a prefix 3576 s += token.value; 3577 token = this.getToken(false, true); 3578 if (token.isIdent() || token.isSymbol("*")) { 3579 // ok we now have a type element or universal 3580 // selector 3581 s += token.value; 3582 if (token.isIdent()) { 3583 specificity.d++; 3584 } 3585 } else 3586 // oops that's an error... 3587 { 3588 return null; 3589 } 3590 } else { 3591 this.ungetToken(); 3592 if (isIdent) { 3593 specificity.d++; 3594 } 3595 } 3596 } else if (token.isSymbol("|")) { 3597 s += token.value; 3598 token = this.getToken(false, true); 3599 if (token.isIdent() || token.isSymbol("*")) { 3600 s += token.value; 3601 if (token.isIdent()) { 3602 specificity.d++; 3603 } 3604 } else 3605 // oops that's an error 3606 { 3607 return null; 3608 } 3609 } 3610 } 3611 3612 else if (token.isSymbol(".") || token.isSymbol("#")) { 3613 var isClass = token.isSymbol("."); 3614 s += token.value; 3615 token = this.getToken(false, true); 3616 if (token.isIdent()) { 3617 s += token.value; 3618 if (isClass) { 3619 specificity.c++; 3620 } else { 3621 specificity.b++; 3622 } 3623 } else { 3624 return null; 3625 } 3626 } 3627 3628 else if (token.isSymbol(":")) { 3629 s += token.value; 3630 token = this.getToken(false, true); 3631 if (token.isSymbol(":")) { 3632 s += token.value; 3633 token = this.getToken(false, true); 3634 } 3635 if (token.isIdent()) { 3636 s += token.value; 3637 if (this.isPseudoElement(token.value)) { 3638 specificity.d++; 3639 } else { 3640 specificity.c++; 3641 } 3642 } else if (token.isFunction()) { 3643 s += token.value; 3644 if (token.isFunction(":not(")) { 3645 if (!canNegate) { 3646 return null; 3647 } 3648 token = this.getToken(true, true); 3649 var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, false); 3650 if (!simpleSelector) { 3651 return null; 3652 } else { 3653 s += simpleSelector.selector; 3654 token = this.getToken(true, true); 3655 if (token.isSymbol(")")) { 3656 s += ")"; 3657 } else { 3658 return null; 3659 } 3660 } 3661 specificity.c++; 3662 } else { 3663 while (true) { 3664 token = this.getToken(false, true); 3665 if (token.isSymbol(")")) { 3666 s += ")"; 3667 break; 3668 } else { 3669 s += token.value; 3670 } 3671 } 3672 specificity.c++; 3673 } 3674 } else { 3675 return null; 3676 } 3677 3678 } else if (token.isSymbol("[")) { 3679 s += "["; 3680 token = this.getToken(true, true); 3681 if (token.isIdent() || token.isSymbol("*")) { 3682 s += token.value; 3683 var nextToken = this.getToken(true, true); 3684 if (token.isSymbol("|")) { 3685 s += "|"; 3686 token = this.getToken(true, true); 3687 if (token.isIdent()) { 3688 s += token.value; 3689 } else { 3690 return null; 3691 } 3692 } else { 3693 this.ungetToken(); 3694 } 3695 } else if (token.isSymbol("|")) { 3696 s += "|"; 3697 token = this.getToken(true, true); 3698 if (token.isIdent()) { 3699 s += token.value; 3700 } else { 3701 return null; 3702 } 3703 } else { 3704 return null; 3705 } 3706 3707 // nothing, =, *=, $=, ^=, |= 3708 token = this.getToken(true, true); 3709 if (token.isIncludes() || token.isDashmatch() || token.isBeginsmatch() || token.isEndsmatch() || token.isContainsmatch() || token.isSymbol("=")) { 3710 s += token.value; 3711 token = this.getToken(true, true); 3712 if (token.isString() || token.isIdent()) { 3713 s += token.value; 3714 token = this.getToken(true, true); 3715 } else { 3716 return null; 3717 } 3718 3719 if (token.isSymbol("]")) { 3720 s += token.value; 3721 specificity.c++; 3722 } else { 3723 return null; 3724 } 3725 } else if (token.isSymbol("]")) { 3726 s += token.value; 3727 specificity.c++; 3728 } else { 3729 return null; 3730 } 3731 3732 } else if (token.isWhiteSpace()) { 3733 var t = this.lookAhead(true, true); 3734 if (t.isSymbol('{')) { 3735 return "" 3736 } 3737 } 3738 if (s) { 3739 return {selector:s, specificity:specificity }; 3740 } 3741 return null; 3742 }, 3743 3744 preserveState:function () { 3745 this.mPreservedTokens.push(this.currentToken()); 3746 this.mScanner.preserveState(); 3747 }, 3748 3749 restoreState:function () { 3750 if (this.mPreservedTokens.length) { 3751 this.mScanner.restoreState(); 3752 this.mToken = this.mPreservedTokens.pop(); 3753 } 3754 }, 3755 3756 forgetState:function () { 3757 if (this.mPreservedTokens.length) { 3758 this.mScanner.forgetState(); 3759 this.mPreservedTokens.pop(); 3760 } 3761 }, 3762 3763 parse:function (aString, aTryToPreserveWhitespaces, aTryToPreserveComments) { 3764 if (!aString) { 3765 return null; 3766 } // early way out if we can 3767 3768 this.mPreserveWS = aTryToPreserveWhitespaces; 3769 this.mPreserveComments = aTryToPreserveComments; 3770 this.mPreservedTokens = []; 3771 this.mScanner.init(aString); 3772 var sheet = new jscsspStylesheet(); 3773 3774 // @charset can only appear at first char of the stylesheet 3775 var token = this.getToken(false, false); 3776 if (!token.isNotNull()) { 3777 return; 3778 } 3779 if (token.isAtRule("@charset")) { 3780 this.parseCharsetRule(token, sheet); 3781 token = this.getToken(false, false); 3782 } 3783 3784 var foundStyleRules = false; 3785 var foundImportRules = false; 3786 var foundNameSpaceRules = false; 3787 while (true) { 3788 if (!token.isNotNull()) { 3789 break; 3790 } 3791 if (token.isWhiteSpace()) { 3792 if (aTryToPreserveWhitespaces) { 3793 this.addWhitespace(sheet, token.value); 3794 } 3795 } 3796 3797 else if (token.isComment()) { 3798 if (this.mPreserveComments) { 3799 this.addComment(sheet, token.value); 3800 } 3801 } 3802 3803 else if (token.isAtRule()) { 3804 if (token.isAtRule("@variables")) { 3805 if (!foundImportRules && !foundStyleRules) { 3806 this.parseVariablesRule(token, sheet); 3807 } else { 3808 this.reportError(kVARIABLES_RULE_POSITION); 3809 this.addUnknownAtRule(sheet, token.value); 3810 } 3811 } else if (token.isAtRule("@import")) { 3812 // @import rules MUST occur before all style and namespace 3813 // rules 3814 if (!foundStyleRules && !foundNameSpaceRules) { 3815 foundImportRules = this.parseImportRule(token, sheet); 3816 } else { 3817 this.reportError(kIMPORT_RULE_POSITION); 3818 this.addUnknownAtRule(sheet, token.value); 3819 } 3820 } else if (token.isAtRule("@namespace")) { 3821 // @namespace rules MUST occur before all style rule and 3822 // after all @import rules 3823 if (!foundStyleRules) { 3824 foundNameSpaceRules = this.parseNamespaceRule(token, sheet); 3825 } else { 3826 this.reportError(kNAMESPACE_RULE_POSITION); 3827 this.addUnknownAtRule(sheet, token.value); 3828 } 3829 } else if (token.isAtRule("@font-face")) { 3830 if (this.parseFontFaceRule(token, sheet)) { 3831 foundStyleRules = true; 3832 } else { 3833 this.addUnknownAtRule(sheet, token.value); 3834 } 3835 } else if (token.isAtRule("@page")) { 3836 if (this.parsePageRule(token, sheet)) { 3837 foundStyleRules = true; 3838 } else { 3839 this.addUnknownAtRule(sheet, token.value); 3840 } 3841 } else if (token.isAtRule("@media")) { 3842 if (this.parseMediaRule(token, sheet)) { 3843 foundStyleRules = true; 3844 } else { 3845 this.addUnknownAtRule(sheet, token.value); 3846 } 3847 } else if (token.isAtRule("@charset")) { 3848 this.reportError(kCHARSET_RULE_CHARSET_SOF); 3849 this.addUnknownAtRule(sheet, token.value); 3850 } else { 3851 this.reportError(kUNKNOWN_AT_RULE); 3852 this.addUnknownAtRule(sheet, token.value); 3853 } 3854 } 3855 3856 else // plain style rules 3857 { 3858 var ruleText = this.parseStyleRule(token, sheet, false); 3859 if (ruleText) { 3860 foundStyleRules = true; 3861 } 3862 } 3863 token = this.getToken(false); 3864 } 3865 3866 return sheet; 3867 } 3868 3869 }; 3870 3871 3872 function jscsspToken(aType, aValue, aUnit) { 3873 this.type = aType; 3874 this.value = aValue; 3875 this.unit = aUnit; 3876 } 3877 3878 jscsspToken.NULL_TYPE = 0; 3879 3880 jscsspToken.WHITESPACE_TYPE = 1; 3881 jscsspToken.STRING_TYPE = 2; 3882 jscsspToken.COMMENT_TYPE = 3; 3883 jscsspToken.NUMBER_TYPE = 4; 3884 jscsspToken.IDENT_TYPE = 5; 3885 jscsspToken.FUNCTION_TYPE = 6; 3886 jscsspToken.ATRULE_TYPE = 7; 3887 jscsspToken.INCLUDES_TYPE = 8; 3888 jscsspToken.DASHMATCH_TYPE = 9; 3889 jscsspToken.BEGINSMATCH_TYPE = 10; 3890 jscsspToken.ENDSMATCH_TYPE = 11; 3891 jscsspToken.CONTAINSMATCH_TYPE = 12; 3892 jscsspToken.SYMBOL_TYPE = 13; 3893 jscsspToken.DIMENSION_TYPE = 14; 3894 jscsspToken.PERCENTAGE_TYPE = 15; 3895 jscsspToken.HEX_TYPE = 16; 3896 3897 jscsspToken.prototype = { 3898 3899 isNotNull:function () { 3900 return this.type; 3901 }, 3902 3903 _isOfType:function (aType, aValue) { 3904 return (this.type == aType && (!aValue || this.value.toLowerCase() == aValue)); 3905 }, 3906 3907 isWhiteSpace:function (w) { 3908 return this._isOfType(jscsspToken.WHITESPACE_TYPE, w); 3909 }, 3910 3911 isString:function () { 3912 return this._isOfType(jscsspToken.STRING_TYPE); 3913 }, 3914 3915 isComment:function () { 3916 return this._isOfType(jscsspToken.COMMENT_TYPE); 3917 }, 3918 3919 isNumber:function (n) { 3920 return this._isOfType(jscsspToken.NUMBER_TYPE, n); 3921 }, 3922 3923 isSymbol:function (c) { 3924 return this._isOfType(jscsspToken.SYMBOL_TYPE, c); 3925 }, 3926 3927 isIdent:function (i) { 3928 return this._isOfType(jscsspToken.IDENT_TYPE, i); 3929 }, 3930 3931 isFunction:function (f) { 3932 return this._isOfType(jscsspToken.FUNCTION_TYPE, f); 3933 }, 3934 3935 isAtRule:function (a) { 3936 return this._isOfType(jscsspToken.ATRULE_TYPE, a); 3937 }, 3938 3939 isIncludes:function () { 3940 return this._isOfType(jscsspToken.INCLUDES_TYPE); 3941 }, 3942 3943 isDashmatch:function () { 3944 return this._isOfType(jscsspToken.DASHMATCH_TYPE); 3945 }, 3946 3947 isBeginsmatch:function () { 3948 return this._isOfType(jscsspToken.BEGINSMATCH_TYPE); 3949 }, 3950 3951 isEndsmatch:function () { 3952 return this._isOfType(jscsspToken.ENDSMATCH_TYPE); 3953 }, 3954 3955 isContainsmatch:function () { 3956 return this._isOfType(jscsspToken.CONTAINSMATCH_TYPE); 3957 }, 3958 3959 isSymbol:function (c) { 3960 return this._isOfType(jscsspToken.SYMBOL_TYPE, c); 3961 }, 3962 3963 isDimension:function () { 3964 return this._isOfType(jscsspToken.DIMENSION_TYPE); 3965 }, 3966 3967 isPercentage:function () { 3968 return this._isOfType(jscsspToken.PERCENTAGE_TYPE); 3969 }, 3970 3971 isHex:function () { 3972 return this._isOfType(jscsspToken.HEX_TYPE); 3973 }, 3974 3975 isDimensionOfUnit:function (aUnit) { 3976 return (this.isDimension() && this.unit == aUnit); 3977 }, 3978 3979 isLength:function () { 3980 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")); 3981 }, 3982 3983 isAngle:function () { 3984 return (this.isDimensionOfUnit("deg") || this.isDimensionOfUnit("rad") || this.isDimensionOfUnit("grad")); 3985 } 3986 } 3987 3988 var kJscsspUNKNOWN_RULE = 0; 3989 var kJscsspSTYLE_RULE = 1 3990 var kJscsspCHARSET_RULE = 2; 3991 var kJscsspIMPORT_RULE = 3; 3992 var kJscsspMEDIA_RULE = 4; 3993 var kJscsspFONT_FACE_RULE = 5; 3994 var kJscsspPAGE_RULE = 6; 3995 var kJscsspVARIABLES_RULE = 7; 3996 3997 var kJscsspNAMESPACE_RULE = 100; 3998 var kJscsspCOMMENT = 101; 3999 var kJscsspWHITE_SPACE = 102; 4000 4001 var kJscsspSTYLE_DECLARATION = 1000; 4002 4003 var gTABS = ""; 4004 4005 function jscsspStylesheet() { 4006 this.cssRules = []; 4007 this.variables = {}; 4008 } 4009 4010 jscsspStylesheet.prototype = { 4011 insertRule:function (aRule, aIndex) { 4012 try { 4013 this.cssRules.splice(aIndex, 1, aRule); 4014 } catch (e) { 4015 } 4016 }, 4017 4018 deleteRule:function (aIndex) { 4019 try { 4020 this.cssRules.splice(aIndex); 4021 } catch (e) { 4022 } 4023 }, 4024 4025 cssText:function () { 4026 var rv = ""; 4027 for (var i = 0; i < this.cssRules.length; i++) { 4028 rv += this.cssRules[i].cssText() + "\n"; 4029 } 4030 return rv; 4031 }, 4032 4033 resolveVariables:function (aMedium) { 4034 4035 function ItemFoundInArray(aArray, aItem) { 4036 for (var i = 0; i < aArray.length; i++) { 4037 if (aItem == aArray[i]) { 4038 return true; 4039 } 4040 } 4041 return false; 4042 } 4043 4044 for (var i = 0; i < this.cssRules.length; i++) { 4045 var rule = this.cssRules[i]; 4046 if (rule.type == kJscsspSTYLE_RULE || rule.type == kJscsspIMPORT_RULE) { 4047 break; 4048 } else if (rule.type == kJscsspVARIABLES_RULE && (!rule.media.length || ItemFoundInArray(rule.media, aMedium))) { 4049 4050 for (var j = 0; j < rule.declarations.length; j++) { 4051 var valueText = ""; 4052 for (var k = 0; k < rule.declarations[j].values.length; k++) { 4053 valueText += (k ? " " : "") + rule.declarations[j].values[k].value; 4054 } 4055 this.variables[rule.declarations[j].property] = valueText; 4056 } 4057 } 4058 } 4059 } 4060 }; 4061 4062 /* kJscsspCHARSET_RULE */ 4063 4064 function jscsspCharsetRule() { 4065 this.type = kJscsspCHARSET_RULE; 4066 this.encoding = null; 4067 this.parsedCssText = null; 4068 this.parentStyleSheet = null; 4069 this.parentRule = null; 4070 } 4071 4072 jscsspCharsetRule.prototype = { 4073 4074 cssText:function () { 4075 return "@charset " + this.encoding + ";"; 4076 }, 4077 4078 setCssText:function (val) { 4079 var sheet = {cssRules:[]}; 4080 var parser = new CSSParser(val); 4081 var token = parser.getToken(false, false); 4082 if (token.isAtRule("@charset")) { 4083 if (parser.parseCharsetRule(token, sheet)) { 4084 var newRule = sheet.cssRules[0]; 4085 this.encoding = newRule.encoding; 4086 this.parsedCssText = newRule.parsedCssText; 4087 return; 4088 } 4089 } 4090 throw DOMException.SYNTAX_ERR; 4091 } 4092 }; 4093 4094 /* kJscsspUNKNOWN_RULE */ 4095 4096 function jscsspErrorRule(aErrorMsg) { 4097 this.error = aErrorMsg ? aErrorMsg : "INVALID"; 4098 this.type = kJscsspUNKNOWN_RULE; 4099 this.parsedCssText = null; 4100 this.parentStyleSheet = null; 4101 this.parentRule = null; 4102 } 4103 4104 jscsspErrorRule.prototype = { 4105 cssText:function () { 4106 return this.parsedCssText; 4107 } 4108 }; 4109 4110 /* kJscsspCOMMENT */ 4111 4112 function jscsspComment() { 4113 this.type = kJscsspCOMMENT; 4114 this.parsedCssText = null; 4115 this.parentStyleSheet = null; 4116 this.parentRule = null; 4117 } 4118 4119 jscsspComment.prototype = { 4120 cssText:function () { 4121 return this.parsedCssText; 4122 }, 4123 4124 setCssText:function (val) { 4125 var parser = new CSSParser(val); 4126 var token = parser.getToken(true, false); 4127 if (token.isComment()) { 4128 this.parsedCssText = token.value; 4129 } else { 4130 throw DOMException.SYNTAX_ERR; 4131 } 4132 } 4133 }; 4134 4135 /* kJscsspWHITE_SPACE */ 4136 4137 function jscsspWhitespace() { 4138 this.type = kJscsspWHITE_SPACE; 4139 this.parsedCssText = null; 4140 this.parentStyleSheet = null; 4141 this.parentRule = null; 4142 } 4143 4144 jscsspWhitespace.prototype = { 4145 cssText:function () { 4146 return this.parsedCssText; 4147 } 4148 }; 4149 4150 /* kJscsspIMPORT_RULE */ 4151 4152 function jscsspImportRule() { 4153 this.type = kJscsspIMPORT_RULE; 4154 this.parsedCssText = null; 4155 this.href = null; 4156 this.media = []; 4157 this.parentStyleSheet = null; 4158 this.parentRule = null; 4159 } 4160 4161 jscsspImportRule.prototype = { 4162 cssText:function () { 4163 var mediaString = this.media.join(", "); 4164 return "@import " + this.href + ((mediaString && mediaString != "all") ? mediaString + " " : "") + ";"; 4165 }, 4166 4167 setCssText:function (val) { 4168 var sheet = {cssRules:[]}; 4169 var parser = new CSSParser(val); 4170 var token = parser.getToken(true, true); 4171 if (token.isAtRule("@import")) { 4172 if (parser.parseImportRule(token, sheet)) { 4173 var newRule = sheet.cssRules[0]; 4174 this.href = newRule.href; 4175 this.media = newRule.media; 4176 this.parsedCssText = newRule.parsedCssText; 4177 return; 4178 } 4179 } 4180 throw DOMException.SYNTAX_ERR; 4181 } 4182 }; 4183 4184 /* kJscsspNAMESPACE_RULE */ 4185 4186 function jscsspNamespaceRule() { 4187 this.type = kJscsspNAMESPACE_RULE; 4188 this.parsedCssText = null; 4189 this.prefix = null; 4190 this.url = null; 4191 this.parentStyleSheet = null; 4192 this.parentRule = null; 4193 } 4194 4195 jscsspNamespaceRule.prototype = { 4196 cssText:function () { 4197 return "@namespace " + (this.prefix ? this.prefix + " " : "") + this.url + ";"; 4198 }, 4199 4200 setCssText:function (val) { 4201 var sheet = {cssRules:[]}; 4202 var parser = new CSSParser(val); 4203 var token = parser.getToken(true, true); 4204 if (token.isAtRule("@namespace")) { 4205 if (parser.parseNamespaceRule(token, sheet)) { 4206 var newRule = sheet.cssRules[0]; 4207 this.url = newRule.url; 4208 this.prefix = newRule.prefix; 4209 this.parsedCssText = newRule.parsedCssText; 4210 return; 4211 } 4212 } 4213 throw DOMException.SYNTAX_ERR; 4214 } 4215 }; 4216 4217 /* kJscsspSTYLE_DECLARATION */ 4218 4219 function jscsspDeclaration() { 4220 this.type = kJscsspSTYLE_DECLARATION; 4221 this.property = null; 4222 this.values = []; 4223 this.valueText = null; 4224 this.priority = null; 4225 this.parsedCssText = null; 4226 this.parentStyleSheet = null; 4227 this.parentRule = null; 4228 } 4229 4230 jscsspDeclaration.prototype = { 4231 kCOMMA_SEPARATED:{ 4232 "cursor":true, 4233 "font-family":true, 4234 "voice-family":true, 4235 "background-image":true 4236 }, 4237 4238 kUNMODIFIED_COMMA_SEPARATED_PROPERTIES:{ 4239 "text-shadow":true, 4240 "box-shadow":true, 4241 "-moz-transition":true, 4242 "-moz-transition-property":true, 4243 "-moz-transition-duration":true, 4244 "-moz-transition-timing-function":true, 4245 "-moz-transition-delay":true 4246 }, 4247 4248 cssText:function () { 4249 var prefixes = CssInspector.prefixesForProperty(this.property); 4250 4251 if (this.property in this.kUNMODIFIED_COMMA_SEPARATED_PROPERTIES) { 4252 if (prefixes) { 4253 var rv = ""; 4254 for (var propertyIndex = 0; propertyIndex < prefixes.length; propertyIndex++) { 4255 var property = prefixes[propertyIndex]; 4256 rv += (propertyIndex ? gTABS : "") + property + ": "; 4257 rv += this.valueText + (this.priority ? " !important" : "") + ";"; 4258 rv += ((prefixes.length > 1 && propertyIndex != prefixes.length - 1) ? "\n" : ""); 4259 } 4260 return rv; 4261 } 4262 return this.property + ": " + this.valueText + (this.priority ? " !important" : "") + ";" 4263 } 4264 4265 if (prefixes) { 4266 var rv = ""; 4267 for (var propertyIndex = 0; propertyIndex < prefixes.length; propertyIndex++) { 4268 var property = prefixes[propertyIndex]; 4269 rv += (propertyIndex ? gTABS : "") + property + ": "; 4270 var separator = (property in this.kCOMMA_SEPARATED) ? ", " : " "; 4271 for (var i = 0; i < this.values.length; i++) { 4272 if (this.values[i].cssText() != null) { 4273 rv += (i ? separator : "") + this.values[i].cssText(); 4274 } else { 4275 return null; 4276 } 4277 } 4278 rv += (this.priority ? " !important" : "") + ";" + ((prefixes.length > 1 && propertyIndex != prefixes.length - 1) ? "\n" : ""); 4279 } 4280 return rv; 4281 } 4282 4283 var rv = this.property + ": "; 4284 var separator = (this.property in this.kCOMMA_SEPARATED) ? ", " : " "; 4285 var extras = {"webkit":false, "presto":false, "trident":false, "generic":false } 4286 for (var i = 0; i < this.values.length; i++) { 4287 var v = this.values[i].cssText(); 4288 if (v != null) { 4289 var paren = v.indexOf("("); 4290 var kwd = v; 4291 if (paren != -1) { 4292 kwd = v.substr(0, paren); 4293 } 4294 if (kwd in kCSS_VENDOR_VALUES) { 4295 for (var j in kCSS_VENDOR_VALUES[kwd]) { 4296 extras[j] = extras[j] || (kCSS_VENDOR_VALUES[kwd][j] != ""); 4297 } 4298 } 4299 rv += (i ? separator : "") + v; 4300 } else { 4301 return null; 4302 } 4303 } 4304 rv += (this.priority ? " !important" : "") + ";"; 4305 4306 for (var j in extras) { 4307 if (extras[j]) { 4308 var str = "\n" + gTABS + this.property + ": "; 4309 for (var i = 0; i < this.values.length; i++) { 4310 var v = this.values[i].cssText(); 4311 if (v != null) { 4312 var paren = v.indexOf("("); 4313 var kwd = v; 4314 if (paren != -1) { 4315 kwd = v.substr(0, paren); 4316 } 4317 if (kwd in kCSS_VENDOR_VALUES) { 4318 functor = kCSS_VENDOR_VALUES[kwd][j]; 4319 if (functor) { 4320 v = (typeof functor == "string") ? functor : functor(v, j); 4321 if (!v) { 4322 str = null; 4323 break; 4324 } 4325 } 4326 } 4327 str += (i ? separator : "") + v; 4328 } else { 4329 return null; 4330 } 4331 } 4332 if (str) { 4333 rv += str + ";" 4334 } else { 4335 rv += "\n" + gTABS + "/* Impossible to translate property " + this.property + " for " + j + " */"; 4336 } 4337 } 4338 } 4339 return rv; 4340 }, 4341 4342 setCssText:function (val) { 4343 var declarations = []; 4344 var parser = new CSSParser(val); 4345 var token = parser.getToken(true, true); 4346 if (parser.parseDeclaration(token, declarations, true, true, null) && declarations.length && declarations[0].type == kJscsspSTYLE_DECLARATION) { 4347 var newDecl = declarations.cssRules[0]; 4348 this.property = newDecl.property; 4349 this.value = newDecl.value; 4350 this.priority = newDecl.priority; 4351 this.parsedCssText = newRule.parsedCssText; 4352 return; 4353 } 4354 throw DOMException.SYNTAX_ERR; 4355 } 4356 }; 4357 4358 /* kJscsspFONT_FACE_RULE */ 4359 4360 function jscsspFontFaceRule() { 4361 this.type = kJscsspFONT_FACE_RULE; 4362 this.parsedCssText = null; 4363 this.descriptors = []; 4364 this.parentStyleSheet = null; 4365 this.parentRule = null; 4366 } 4367 4368 jscsspFontFaceRule.prototype = { 4369 cssText:function () { 4370 var rv = gTABS + "@font-face {\n"; 4371 var preservedGTABS = gTABS; 4372 gTABS += " "; 4373 for (var i = 0; i < this.descriptors.length; i++) { 4374 rv += gTABS + this.descriptors[i].cssText() + "\n"; 4375 } 4376 gTABS = preservedGTABS; 4377 return rv + gTABS + "}"; 4378 }, 4379 4380 setCssText:function (val) { 4381 var sheet = {cssRules:[]}; 4382 var parser = new CSSParser(val); 4383 var token = parser.getToken(true, true); 4384 if (token.isAtRule("@font-face")) { 4385 if (parser.parseFontFaceRule(token, sheet)) { 4386 var newRule = sheet.cssRules[0]; 4387 this.descriptors = newRule.descriptors; 4388 this.parsedCssText = newRule.parsedCssText; 4389 return; 4390 } 4391 } 4392 throw DOMException.SYNTAX_ERR; 4393 } 4394 }; 4395 4396 /* kJscsspMEDIA_RULE */ 4397 4398 function jscsspMediaRule() { 4399 this.type = kJscsspMEDIA_RULE; 4400 this.parsedCssText = null; 4401 this.cssRules = []; 4402 this.media = []; 4403 this.parentStyleSheet = null; 4404 this.parentRule = null; 4405 } 4406 4407 jscsspMediaRule.prototype = { 4408 cssText:function () { 4409 var rv = gTABS + "@media " + this.media.join(", ") + " {\n"; 4410 var preservedGTABS = gTABS; 4411 gTABS += " "; 4412 for (var i = 0; i < this.cssRules.length; i++) { 4413 rv += gTABS + this.cssRules[i].cssText() + "\n"; 4414 } 4415 gTABS = preservedGTABS; 4416 return rv + gTABS + "}"; 4417 }, 4418 4419 setCssText:function (val) { 4420 var sheet = {cssRules:[]}; 4421 var parser = new CSSParser(val); 4422 var token = parser.getToken(true, true); 4423 if (token.isAtRule("@media")) { 4424 if (parser.parseMediaRule(token, sheet)) { 4425 var newRule = sheet.cssRules[0]; 4426 this.cssRules = newRule.cssRules; 4427 this.media = newRule.media; 4428 this.parsedCssText = newRule.parsedCssText; 4429 return; 4430 } 4431 } 4432 throw DOMException.SYNTAX_ERR; 4433 } 4434 }; 4435 4436 /* kJscsspSTYLE_RULE */ 4437 4438 function jscsspStyleRule() { 4439 this.type = kJscsspSTYLE_RULE; 4440 this.parsedCssText = null; 4441 this.declarations = [] 4442 this.mSelectorText = null; 4443 this.parentStyleSheet = null; 4444 this.parentRule = null; 4445 } 4446 4447 jscsspStyleRule.prototype = { 4448 cssText:function () { 4449 var rv = this.mSelectorText + " {\n"; 4450 var preservedGTABS = gTABS; 4451 gTABS += " "; 4452 for (var i = 0; i < this.declarations.length; i++) { 4453 var declText = this.declarations[i].cssText(); 4454 if (declText) { 4455 rv += gTABS + this.declarations[i].cssText() + "\n"; 4456 } 4457 } 4458 gTABS = preservedGTABS; 4459 return rv + gTABS + "}"; 4460 }, 4461 4462 setCssText:function (val) { 4463 var sheet = {cssRules:[]}; 4464 var parser = new CSSParser(val); 4465 var token = parser.getToken(true, true); 4466 if (!token.isNotNull()) { 4467 if (parser.parseStyleRule(token, sheet, false)) { 4468 var newRule = sheet.cssRules[0]; 4469 this.mSelectorText = newRule.mSelectorText; 4470 this.declarations = newRule.declarations; 4471 this.parsedCssText = newRule.parsedCssText; 4472 return; 4473 } 4474 } 4475 throw DOMException.SYNTAX_ERR; 4476 }, 4477 4478 selectorText:function () { 4479 return this.mSelectorText; 4480 }, 4481 4482 setSelectorText:function (val) { 4483 var parser = new CSSParser(val); 4484 var token = parser.getToken(true, true); 4485 if (!token.isNotNull()) { 4486 var s = parser.parseSelector(token, true); 4487 if (s) { 4488 this.mSelectorText = s.selector; 4489 return; 4490 } 4491 } 4492 throw DOMException.SYNTAX_ERR; 4493 } 4494 }; 4495 4496 /* kJscsspPAGE_RULE */ 4497 4498 function jscsspPageRule() { 4499 this.type = kJscsspPAGE_RULE; 4500 this.parsedCssText = null; 4501 this.pageSelector = null; 4502 this.declarations = []; 4503 this.parentStyleSheet = null; 4504 this.parentRule = null; 4505 } 4506 4507 jscsspPageRule.prototype = { 4508 cssText:function () { 4509 var rv = gTABS + "@page " + (this.pageSelector ? this.pageSelector + " " : "") + "{\n"; 4510 var preservedGTABS = gTABS; 4511 gTABS += " "; 4512 for (var i = 0; i < this.declarations.length; i++) { 4513 rv += gTABS + this.declarations[i].cssText() + "\n"; 4514 } 4515 gTABS = preservedGTABS; 4516 return rv + gTABS + "}"; 4517 }, 4518 4519 setCssText:function (val) { 4520 var sheet = {cssRules:[]}; 4521 var parser = new CSSParser(val); 4522 var token = parser.getToken(true, true); 4523 if (token.isAtRule("@page")) { 4524 if (parser.parsePageRule(token, sheet)) { 4525 var newRule = sheet.cssRules[0]; 4526 this.pageSelector = newRule.pageSelector; 4527 this.declarations = newRule.declarations; 4528 this.parsedCssText = newRule.parsedCssText; 4529 return; 4530 } 4531 } 4532 throw DOMException.SYNTAX_ERR; 4533 } 4534 }; 4535 4536 /* kJscsspVARIABLES_RULE */ 4537 4538 function jscsspVariablesRule() { 4539 this.type = kJscsspVARIABLES_RULE; 4540 this.parsedCssText = null; 4541 this.declarations = []; 4542 this.parentStyleSheet = null; 4543 this.parentRule = null; 4544 this.media = null; 4545 } 4546 4547 jscsspVariablesRule.prototype = { 4548 cssText:function () { 4549 var rv = gTABS + "@variables " + (this.media.length ? this.media.join(", ") + " " : "") + "{\n"; 4550 var preservedGTABS = gTABS; 4551 gTABS += " "; 4552 for (var i = 0; i < this.declarations.length; i++) { 4553 rv += gTABS + this.declarations[i].cssText() + "\n"; 4554 } 4555 gTABS = preservedGTABS; 4556 return rv + gTABS + "}"; 4557 }, 4558 4559 setCssText:function (val) { 4560 var sheet = {cssRules:[]}; 4561 var parser = new CSSParser(val); 4562 var token = parser.getToken(true, true); 4563 if (token.isAtRule("@variables")) { 4564 if (parser.parseVariablesRule(token, sheet)) { 4565 var newRule = sheet.cssRules[0]; 4566 this.declarations = newRule.declarations; 4567 this.parsedCssText = newRule.parsedCssText; 4568 return; 4569 } 4570 } 4571 throw DOMException.SYNTAX_ERR; 4572 } 4573 }; 4574 4575 var kJscsspINHERIT_VALUE = 0; 4576 var kJscsspPRIMITIVE_VALUE = 1; 4577 var kJscsspVARIABLE_VALUE = 4; 4578 4579 function jscsspVariable(aType, aSheet) { 4580 this.value = ""; 4581 this.type = aType; 4582 this.name = null; 4583 this.parentRule = null; 4584 this.parentStyleSheet = aSheet; 4585 } 4586 4587 jscsspVariable.prototype = { 4588 cssText:function () { 4589 if (this.type == kJscsspVARIABLE_VALUE) { 4590 return this.resolveVariable(this.name, this.parentRule, this.parentStyleSheet); 4591 } else { 4592 return this.value; 4593 } 4594 }, 4595 4596 setCssText:function (val) { 4597 if (this.type == kJscsspVARIABLE_VALUE) { 4598 throw DOMException.SYNTAX_ERR; 4599 } else { 4600 this.value = val; 4601 } 4602 }, 4603 4604 resolveVariable:function (aName, aRule, aSheet) { 4605 if (aName.toLowerCase() in aSheet.variables) { 4606 return aSheet.variables[aName.toLowerCase()]; 4607 } 4608 return null; 4609 } 4610 }; 4611 4612 function ParseURL(buffer) { 4613 var result = { }; 4614 result.protocol = ""; 4615 result.user = ""; 4616 result.password = ""; 4617 result.host = ""; 4618 result.port = ""; 4619 result.path = ""; 4620 result.query = ""; 4621 4622 var section = "PROTOCOL"; 4623 var start = 0; 4624 var wasSlash = false; 4625 4626 while (start < buffer.length) { 4627 if (section == "PROTOCOL") { 4628 if (buffer.charAt(start) == ':') { 4629 section = "AFTER_PROTOCOL"; 4630 start++; 4631 } else if (buffer.charAt(start) == '/' && result.protocol.length() == 0) { 4632 section = PATH; 4633 } else { 4634 result.protocol += buffer.charAt(start++); 4635 } 4636 } else if (section == "AFTER_PROTOCOL") { 4637 if (buffer.charAt(start) == '/') { 4638 if (!wasSlash) { 4639 wasSlash = true; 4640 } else { 4641 wasSlash = false; 4642 section = "USER"; 4643 } 4644 start++; 4645 } else { 4646 throw new ParseException("Protocol shell be separated with 2 slashes"); 4647 } 4648 } else if (section == "USER") { 4649 if (buffer.charAt(start) == '/') { 4650 result.host = result.user; 4651 result.user = ""; 4652 section = "PATH"; 4653 } else if (buffer.charAt(start) == '?') { 4654 result.host = result.user; 4655 result.user = ""; 4656 section = "QUERY"; 4657 start++; 4658 } else if (buffer.charAt(start) == ':') { 4659 section = "PASSWORD"; 4660 start++; 4661 } else if (buffer.charAt(start) == '@') { 4662 section = "HOST"; 4663 start++; 4664 } else { 4665 result.user += buffer.charAt(start++); 4666 } 4667 } else if (section == "PASSWORD") { 4668 if (buffer.charAt(start) == '/') { 4669 result.host = result.user; 4670 result.port = result.password; 4671 result.user = ""; 4672 result.password = ""; 4673 section = "PATH"; 4674 } else if (buffer.charAt(start) == '?') { 4675 result.host = result.user; 4676 result.port = result.password; 4677 result.user = ""; 4678 result.password = ""; 4679 section = "QUERY"; 4680 start++; 4681 } else if (buffer.charAt(start) == '@') { 4682 section = "HOST"; 4683 start++; 4684 } else { 4685 result.password += buffer.charAt(start++); 4686 } 4687 } else if (section == "HOST") { 4688 if (buffer.charAt(start) == '/') { 4689 section = "PATH"; 4690 } else if (buffer.charAt(start) == ':') { 4691 section = "PORT"; 4692 start++; 4693 } else if (buffer.charAt(start) == '?') { 4694 section = "QUERY"; 4695 start++; 4696 } else { 4697 result.host += buffer.charAt(start++); 4698 } 4699 } else if (section == "PORT") { 4700 if (buffer.charAt(start) = '/') { 4701 section = "PATH"; 4702 } else if (buffer.charAt(start) == '?') { 4703 section = "QUERY"; 4704 start++; 4705 } else { 4706 result.port += buffer.charAt(start++); 4707 } 4708 } else if (section == "PATH") { 4709 if (buffer.charAt(start) == '?') { 4710 section = "QUERY"; 4711 start++; 4712 } else { 4713 result.path += buffer.charAt(start++); 4714 } 4715 } else if (section == "QUERY") { 4716 result.query += buffer.charAt(start++); 4717 } 4718 } 4719 4720 if (section == "PROTOCOL") { 4721 result.host = result.protocol; 4722 result.protocol = "http"; 4723 } else if (section == "AFTER_PROTOCOL") { 4724 throw new ParseException("Invalid url"); 4725 } else if (section == "USER") { 4726 result.host = result.user; 4727 result.user = ""; 4728 } else if (section == "PASSWORD") { 4729 result.host = result.user; 4730 result.port = result.password; 4731 result.user = ""; 4732 result.password = ""; 4733 } 4734 4735 return result; 4736 } 4737 4738 function ParseException(description) { 4739 this.description = description; 4740 } 4741 4742 function CountLF(s) { 4743 var nCR = s.match(/\n/g); 4744 return nCR ? nCR.length + 1 : 1; 4745 } 4746 4747 function FilterLinearGradientForOutput(aValue, aEngine) { 4748 if (aEngine == "generic") { 4749 return aValue.substr(5); 4750 } 4751 4752 if (aEngine == "webkit") { 4753 return aValue.replace(/\-moz\-/g, "-webkit-") 4754 } 4755 4756 if (aEngine != "webkit20110101") { 4757 return ""; 4758 } 4759 4760 var g = CssInspector.parseBackgroundImages(aValue)[0]; 4761 4762 var cancelled = false; 4763 var str = "-webkit-gradient(linear, "; 4764 var position = ("position" in g.value) ? g.value.position.toLowerCase() : ""; 4765 var angle = ("angle" in g.value) ? g.value.angle.toLowerCase() : ""; 4766 // normalize angle 4767 if (angle) { 4768 var match = angle.match(/^([0-9\-\.\\+]+)([a-z]*)/); 4769 var angle = parseFloat(match[1]); 4770 var unit = match[2]; 4771 switch (unit) { 4772 case "grad": 4773 angle = angle * 90 / 100; 4774 break; 4775 case "rad": 4776 angle = angle * 180 / Math.PI; 4777 break; 4778 default: 4779 break; 4780 } 4781 while (angle < 0) { 4782 angle += 360; 4783 } 4784 while (angle >= 360) { 4785 angle -= 360; 4786 } 4787 } 4788 // get startpoint w/o keywords 4789 var startpoint = []; 4790 var endpoint = []; 4791 if (position != "") { 4792 if (position == "center") { 4793 position = "center center"; 4794 } 4795 startpoint = position.split(" "); 4796 if (angle == "" && angle != 0) { 4797 // no angle, then we just turn the point 180 degrees around center 4798 switch (startpoint[0]) { 4799 case "left": 4800 endpoint.push("right"); 4801 break; 4802 case "center": 4803 endpoint.push("center"); 4804 break; 4805 case "right": 4806 endpoint.push("left"); 4807 break; 4808 default: 4809 { 4810 var match = startpoint[0].match(/^([0-9\-\.\\+]+)([a-z]*)/); 4811 var v = parseFloat(match[0]); 4812 var unit = match[1]; 4813 if (unit == "%") { 4814 endpoint.push((100 - v) + "%"); 4815 } else { 4816 cancelled = true; 4817 } 4818 } 4819 break; 4820 } 4821 if (!cancelled) { 4822 switch (startpoint[1]) { 4823 case "top": 4824 endpoint.push("bottom"); 4825 break; 4826 case "center": 4827 endpoint.push("center"); 4828 break; 4829 case "bottom": 4830 endpoint.push("top"); 4831 break; 4832 default: 4833 { 4834 var match = startpoint[1].match(/^([0-9\-\.\\+]+)([a-z]*)/); 4835 var v = parseFloat(match[0]); 4836 var unit = match[1]; 4837 if (unit == "%") { 4838 endpoint.push((100 - v) + "%"); 4839 } else { 4840 cancelled = true; 4841 } 4842 } 4843 break; 4844 } 4845 } 4846 } else { 4847 switch (angle) { 4848 case 0: 4849 endpoint.push("right"); 4850 endpoint.push(startpoint[1]); 4851 break; 4852 case 90: 4853 endpoint.push(startpoint[0]); 4854 endpoint.push("top"); 4855 break; 4856 case 180: 4857 endpoint.push("left"); 4858 endpoint.push(startpoint[1]); 4859 break; 4860 case 270: 4861 endpoint.push(startpoint[0]); 4862 endpoint.push("bottom"); 4863 break; 4864 default: 4865 cancelled = true; 4866 break; 4867 } 4868 } 4869 } else { 4870 // no position defined, we accept only vertical and horizontal 4871 if (angle == "") { 4872 angle = 270; 4873 } 4874 switch (angle) { 4875 case 0: 4876 startpoint = ["left", "center"]; 4877 endpoint = ["right", "center"]; 4878 break; 4879 case 90: 4880 startpoint = ["center", "bottom"]; 4881 endpoint = ["center", "top"]; 4882 break; 4883 case 180: 4884 startpoint = ["right", "center"]; 4885 endpoint = ["left", "center"]; 4886 break; 4887 case 270: 4888 startpoint = ["center", "top"]; 4889 endpoint = ["center", "bottom"]; 4890 break; 4891 default: 4892 cancelled = true; 4893 break; 4894 } 4895 } 4896 4897 if (cancelled) { 4898 return ""; 4899 } 4900 4901 str += startpoint.join(" ") + ", " + endpoint.join(" "); 4902 if (!g.value.stops[0].position) { 4903 g.value.stops[0].position = "0%"; 4904 } 4905 if (!g.value.stops[g.value.stops.length - 1].position) { 4906 g.value.stops[g.value.stops.length - 1].position = "100%"; 4907 } 4908 var current = 0; 4909 for (var i = 0; i < g.value.stops.length && !cancelled; i++) { 4910 var s = g.value.stops[i]; 4911 if (s.position) { 4912 if (s.position.indexOf("%") == -1) { 4913 cancelled = true; 4914 break; 4915 } 4916 } else { 4917 var j = i + 1; 4918 while (j < g.value.stops.length && !g.value.stops[j].position) { 4919 j++; 4920 } 4921 var inc = parseFloat(g.value.stops[j].position) - current; 4922 for (var k = i; k < j; k++) { 4923 g.value.stops[k].position = (current + inc * (k - i + 1) / (j - i + 1)) + "%"; 4924 } 4925 } 4926 current = parseFloat(s.position); 4927 str += ", color-stop(" + (parseFloat(current) / 100) + ", " + s.color + ")"; 4928 } 4929 4930 if (cancelled) { 4931 return ""; 4932 } 4933 return str + ")"; 4934 } 4935 4936 function FilterRadialGradientForOutput(aValue, aEngine) { 4937 if (aEngine == "generic") { 4938 return aValue.substr(5); 4939 } 4940 4941 else if (aEngine == "webkit") { 4942 return aValue.replace(/\-moz\-/g, "-webkit-") 4943 } 4944 4945 else if (aEngine != "webkit20110101") { 4946 return ""; 4947 } 4948 4949 var g = CssInspector.parseBackgroundImages(aValue)[0]; 4950 4951 var shape = ("shape" in g.value) ? g.value.shape : ""; 4952 var size = ("size" in g.value) ? g.value.size : ""; 4953 if (shape != "circle" || (size != "farthest-corner" && size != "cover")) { 4954 return ""; 4955 } 4956 4957 if (g.value.stops.length < 2 || !("position" in g.value.stops[0]) || !g.value.stops[g.value.stops.length - 1].position || !("position" in g.value.stops[0]) || !g.value.stops[g.value.stops.length - 1].position) { 4958 return ""; 4959 } 4960 4961 for (var i = 0; i < g.value.stops.length; i++) { 4962 var s = g.value.stops[i]; 4963 if (("position" in s) && s.position && s.position.indexOf("px") == -1) { 4964 return ""; 4965 } 4966 } 4967 4968 var str = "-webkit-gradient(radial, "; 4969 var position = ("position" in g.value) ? g.value.position : "center center"; 4970 str += position + ", " + parseFloat(g.value.stops[0].position) + ", "; 4971 str += position + ", " + parseFloat(g.value.stops[g.value.stops.length - 1].position); 4972 4973 // at this point we're sure to deal with pixels 4974 var current = parseFloat(g.value.stops[0].position); 4975 for (var i = 0; i < g.value.stops.length; i++) { 4976 var s = g.value.stops[i]; 4977 if (!("position" in s) || !s.position) { 4978 var j = i + 1; 4979 while (j < g.value.stops.length && !g.value.stops[j].position) { 4980 j++; 4981 } 4982 var inc = parseFloat(g.value.stops[j].position) - current; 4983 for (var k = i; k < j; k++) { 4984 g.value.stops[k].position = (current + inc * (k - i + 1) / (j - i + 1)) + "px"; 4985 } 4986 } 4987 current = parseFloat(s.position); 4988 var c = (current - parseFloat(g.value.stops[0].position)) / (parseFloat(g.value.stops[g.value.stops.length - 1].position) - parseFloat(g.value.stops[0].position)); 4989 str += ", color-stop(" + c + ", " + s.color + ")"; 4990 } 4991 str += ")" 4992 return str; 4993 } 4994 4995 function FilterRepeatingGradientForOutput(aValue, aEngine) { 4996 if (aEngine == "generic") { 4997 return aValue.substr(5); 4998 } 4999 5000 else if (aEngine == "webkit") { 5001 return aValue.replace(/\-moz\-/g, "-webkit-") 5002 } 5003 5004 return ""; 5005 } 5006 5007 /**#nocode-*/ 5008 5009 /** 5010 * Creates a style declaration 5011 * 5012 * @param {string} property property name 5013 * @param {string} valueText property value 5014 * 5015 * @class CSS Property declaration 5016 * @name StyleDeclaration 5017 */ 5018 function StyleDeclaration(property, valueText) { 5019 this.property = property; 5020 this.valueText = valueText; 5021 } 5022 5023 StyleDeclaration.prototype = { 5024 /** 5025 * Property name 5026 * @type string 5027 */ 5028 property:"", 5029 /** 5030 * Property value 5031 * @type string 5032 */ 5033 valueText:"", 5034 }; 5035 5036 var cssParser, logger, CssParserInstance; 5037 5038 logger = wef.logger("wef.cssParser"); 5039 5040 /** 5041 * Creates a CSS parser 5042 * 5043 * @class CSS parser 5044 */ 5045 cssParser = function () { 5046 return new cssParser.prototype.init(); 5047 }; 5048 5049 cssParser.prototype = { 5050 /** 5051 * Version number*/ 5052 version:"0.2.0", 5053 /** 5054 * Stores callback functions. Looks like register events 5055 */ 5056 callbacks:{ 5057 /** 5058 * todo 5059 */ 5060 parserStar:undefined, 5061 parserStop:undefined, 5062 cssRuleFound:undefined, 5063 propertyFound:undefined, 5064 error:undefined 5065 }, 5066 constructor:cssParser, 5067 /** 5068 * @ignore 5069 */ 5070 init:function () { 5071 this.callbacks = { 5072 parserStar:undefined, 5073 parserStop:undefined, 5074 cssRuleFound:undefined, 5075 propertyFound:undefined, 5076 error:undefined 5077 }; 5078 return this; 5079 } 5080 }; 5081 5082 /** 5083 * Extension point 5084 */ 5085 cssParser.fn = cssParser.prototype; 5086 5087 cssParser.prototype.init.prototype = cssParser.prototype; 5088 5089 wef.extend(cssParser.prototype.init.prototype, 5090 /** 5091 * @lends cssParser# 5092 */ 5093 { 5094 /** 5095 * Reference to jscssp parser 5096 */ 5097 backend:undefined, 5098 5099 /** 5100 * Calls parserStar callback 5101 * @param {Function}callback "Parser starts" callback 5102 */ 5103 whenStart:function (callback) { 5104 if (wef.isFunction(callback)) { 5105 logger.debug("set parserStart callback"); 5106 this.callbacks.parserStar = callback; 5107 } 5108 return this; 5109 }, 5110 /** 5111 * Calls parserStop callback 5112 * @param {Function}callback "Parser stops" callback 5113 */ 5114 whenStop:function (callback) { 5115 if (wef.isFunction(callback)) { 5116 logger.debug("set parserStop callback"); 5117 this.callbacks.parserStop = callback; 5118 } 5119 return this; 5120 }, 5121 /** 5122 * Calls cssRuleFound callback 5123 * @param {Function}callback "Css rule found" callback 5124 */ 5125 whenCssRule:function (callback) { 5126 if (wef.isFunction(callback)) { 5127 logger.debug("set CssRuleFound callback"); 5128 this.callbacks.cssRuleFound = callback; 5129 } 5130 return this; 5131 }, 5132 /** 5133 * Calls propertyFound callback 5134 * @param {Function}callback "Property found" callback 5135 */ 5136 whenProperty:function (callback) { 5137 if (wef.isFunction(callback)) { 5138 logger.debug("set propertyFound callback"); 5139 this.callbacks.propertyFound = callback; 5140 } 5141 return this; 5142 }, 5143 /** 5144 * Calls error callback 5145 * @param {Function}callback "Error" callback 5146 */ 5147 whenError:function (callback) { 5148 if (wef.isFunction(callback)) { 5149 logger.debug("set error callback"); 5150 this.callbacks.error = callback; 5151 } 5152 return this; 5153 }, 5154 /** 5155 * Parses given text calling callbacks when registered actions happens 5156 * @param {string}data CSS code 5157 */ 5158 parse:function (data) { 5159 var sheet, property, context = this; 5160 try { 5161 if (!data || !wef.isString(data) || data === "") { 5162 var message = "InvalidArgumentException - data must be a non empty string"; 5163 logger.error(message); 5164 throw new Error(message); 5165 } 5166 if (context.callbacks.parserStar) { 5167 logger.debug("call parserStart callback"); 5168 context.callbacks.parserStar.call(context, 5169 /** 5170 * @namespace Parser start data format 5171 * @name StartCallbackData 5172 */ 5173 /** 5174 * @lends StartCallbackData# 5175 */ 5176 { 5177 /** 5178 * Start time in millisecons 5179 * @type Number 5180 */ 5181 time:new Date().getTime()}); 5182 } 5183 sheet = new CSSParser().parse(data, false, false); 5184 //start 5185 sheet.cssRules.forEach(function (cssRule) { 5186 logger.debug("cssRule:", cssRule); 5187 if (context.callbacks.cssRuleFound) { 5188 logger.debug("call cssRuleFound callback"); 5189 context.callbacks.cssRuleFound.call(context, cssRule); 5190 } 5191 //ErrorRule 5192 if (cssRule.type === 0) { 5193 var message = "ParserException - Error in line " + cssRule.currentLine + ": " + cssRule.parsedCssText; 5194 logger.error(message); 5195 throw new Error(message); 5196 } 5197 cssRule.declarations.forEach(function (declaration) { 5198 /** 5199 * @namespace CSS property found data format 5200 * @name CSSParserProperty 5201 */ 5202 property = 5203 /** 5204 * @lends CSSParserProperty# 5205 */ 5206 { 5207 /** 5208 * Property selector 5209 * @type string 5210 */ 5211 selectorText:cssRule.selectorText(), 5212 /** 5213 * Property declaration 5214 * @type StyleDeclaration 5215 */ 5216 declaration:new StyleDeclaration(declaration.property, declaration.valueText) 5217 }; 5218 logger.debug("property:", property); 5219 if (context.callbacks.propertyFound) { 5220 logger.debug("call propertyFound callback"); 5221 context.callbacks.propertyFound.call(context, property); 5222 } 5223 }); 5224 }); 5225 //done 5226 if (context.callbacks.parserStop) { 5227 logger.debug("call parserStop callback"); 5228 context.callbacks.parserStop.call(context, 5229 /** 5230 * @namespace Parser stop data format 5231 * @name StopCallbackData 5232 */ 5233 /** 5234 * @lends StopCallbackData# 5235 */ 5236 { 5237 /** 5238 * Stop time in millisecons 5239 * @type Number 5240 */ 5241 time:new Date().getTime()}); 5242 } 5243 } catch (e) { 5244 if (context.callbacks.error) { 5245 logger.error("call error callback:", e); 5246 context.callbacks.error.call(context, e.message); 5247 return this; 5248 } else { 5249 logger.error("unhandled error call wef.error:", e); 5250 wef.error(e.message); 5251 return null; 5252 } 5253 } 5254 return this; 5255 } 5256 }); 5257 5258 wef.cssParser = cssParser; 5259 5260 logger.info("cssParser plugged to wef.cssParser"); 5261 5262 })(window.wef);