diff --git a/public注释.md b/public注释.md new file mode 100644 index 0000000..06a5d3c --- /dev/null +++ b/public注释.md @@ -0,0 +1,3457 @@ +// 清除供应商前缀缓存的方法 +cleanPrefixes: function() +{ +// 将 mVENDOR_PREFIXES 属性置为 null,清除之前缓存的供应商前缀信息 +this.mVENDOR_PREFIXES = null; +}, + +// 根据属性获取对应的供应商前缀数组的方法 +prefixesForProperty: function(aProperty) +{ +// 检查 mVENDOR_PREFIXES 是否为 null,如果为 null 则进行初始化 +if (!this.mVENDOR_PREFIXES) { +// 初始化 mVENDOR_PREFIXES 为一个空对象 +this.mVENDOR_PREFIXES = {}; +// 遍历 kCSS_VENDOR_PREFIXES.properties 数组 +for (var i = 0; i < kCSS_VENDOR_PREFIXES.properties.length; i++) { +// 获取当前属性 +var p = kCSS_VENDOR_PREFIXES.properties[i]; +// 检查该属性是否有 gecko 前缀,并且有 webkit、presto 或 trident 前缀之一 +if (p.gecko && (p.webkit || p.presto || p.trident)) { +// 初始化一个空对象 o 用于存储不同前缀 +var o = {}; +// 如果 kEXPORTS_FOR_GECKO 为 true,则将 gecko 前缀添加到 o 中 +if (this.kEXPORTS_FOR_GECKO) o[p.gecko] = true; +// 如果 kEXPORTS_FOR_WEBKIT 为 true 且有 webkit 前缀,则将 webkit 前缀添加到 o 中 +if (this.kEXPORTS_FOR_WEBKIT && p.webkit) o[p.webkit] = true; +// 如果 kEXPORTS_FOR_PRESTO 为 true 且有 presto 前缀,则将 presto 前缀添加到 o 中 +if (this.kEXPORTS_FOR_PRESTO && p.presto) o[p.presto] = true; +// 如果 kEXPORTS_FOR_TRIDENT 为 true 且有 trident 前缀,则将 trident 前缀添加到 o 中 +if (this.kEXPORTS_FOR_TRIDENT && p.trident) o[p.trident] = true; +// 在 mVENDOR_PREFIXES 中为 gecko 前缀创建一个空数组 +this.mVENDOR_PREFIXES[p.gecko] = []; +// 遍历 o 对象,将其中的前缀添加到 mVENDOR_PREFIXES[p.gecko] 数组中 +for (var j in o) +this.mVENDOR_PREFIXES[p.gecko].push(j) +} +} +} +// 检查传入的属性是否存在于 mVENDOR_PREFIXES 中 +if (aProperty in this.mVENDOR_PREFIXES) +// 如果存在,则对该属性对应的前缀数组进行排序并返回 +return this.mVENDOR_PREFIXES[aProperty].sort(); +// 如果不存在,则返回 null +return null; +}, + +// 解析颜色停止点的方法 +parseColorStop: function(parser, token) +{ +// 调用 parser 的 parseColor 方法解析颜色 +var color = parser.parseColor(token); +// 初始化位置为空字符串 +var position = ""; +// 如果颜色解析失败,则返回 null +if (!color) +return null; +// 获取下一个标记 +token = parser.getToken(true, true); +// 检查标记是否为百分比或指定单位的尺寸 +if (token.isPercentage() || +token.isDimensionOfUnit("cm") || +token.isDimensionOfUnit("mm") || +token.isDimensionOfUnit("in") || +token.isDimensionOfUnit("pc") || +token.isDimensionOfUnit("px") || +token.isDimensionOfUnit("em") || +token.isDimensionOfUnit("ex") || +token.isDimensionOfUnit("pt")) { +// 如果是,则将标记的值赋给位置 +position = token.value; +// 获取下一个标记 +token = parser.getToken(true, true); +} +// 返回包含颜色和位置的对象 +return { color: color, position: position } +}, + +// 解析渐变的方法 +parseGradient: function (parser, token) +{ +// 初始化是否为径向渐变的标志为 false +var isRadial = false; +// 初始化渐变对象,设置是否重复为 false +var gradient = { isRepeating: false }; +// 检查标记是否不为空 +if (token.isNotNull()) { +// 检查标记是否为特定的渐变函数 +if (token.isFunction("-moz-linear-gradient(") || +token.isFunction("-moz-radial-gradient(") || +token.isFunction("-moz-repeating-linear-gradient(") || +token.isFunction("-moz-repeating-radial-gradient(")) { +// 如果是径向渐变函数,则将 isRadial 标志置为 true +if (token.isFunction("-moz-radial-gradient(") || +token.isFunction("-moz-repeating-radial-gradient(")) { +gradient.isRadial = true; +} +// 如果是重复渐变函数,则将 isRepeating 标志置为 true +if (token.isFunction("-moz-repeating-linear-gradient(") || +token.isFunction("-moz-repeating-radial-gradient(")) { +gradient.isRepeating = true; +} + + // 获取下一个标记 + token = parser.getToken(true, true); + // 初始化是否有渐变线的标志为 false + var haveGradientLine = false; + // 初始化是否找到水平位置的标志为 false + var foundHorizPosition = false; + // 初始化是否有角度的标志为 false + var haveAngle = false; + + // 检查标记是否为角度 + if (token.isAngle()) { + // 如果是,则将角度值赋给渐变对象的 angle 属性 + gradient.angle = token.value; + // 将 haveGradientLine 标志置为 true + haveGradientLine = true; + // 将 haveAngle 标志置为 true + haveAngle = true; + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 检查标记是否为长度或特定的标识符 + if (token.isLength() + || token.isIdent("top") + || token.isIdent("center") + || token.isIdent("bottom") + || token.isIdent("left") + || token.isIdent("right")) { + // 如果是,则将 haveGradientLine 标志置为 true + haveGradientLine = true; + // 检查标记是否为长度或水平位置标识符 + if (token.isLength() + || token.isIdent("left") + || token.isIdent("right")) { + // 如果是,则将 foundHorizPosition 标志置为 true + foundHorizPosition = true; + } + // 将标记的值赋给渐变对象的 position 属性 + gradient.position = token.value; + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 如果有渐变线 + if (haveGradientLine) { + // 如果没有角度且标记为角度 + if (!haveAngle && token.isAngle()) { + // 将角度值赋给渐变对象的 angle 属性 + gradient.angle = token.value; + // 将 haveAngle 标志置为 true + haveAngle = true; + // 获取下一个标记 + token = parser.getToken(true, true); + } + // 检查标记是否符合特定条件 + 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")))) { + // 如果符合条件,则更新渐变对象的 position 属性 + gradient.position = ("position" in gradient) ? gradient.position + " ": ""; + gradient.position += token.value; + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 如果没有角度且标记为角度 + if (!haveAngle && token.isAngle()) { + // 将角度值赋给渐变对象的 angle 属性 + gradient.angle = token.value; + // 将 haveAngle 标志置为 true + haveAngle = true; + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 检查标记是否为逗号 + if (!token.isSymbol(",")) + // 如果不是,则返回 null + return null; + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 如果是径向渐变 + if (gradient.isRadial) { + // 检查标记是否为圆形或椭圆形标识符 + if (token.isIdent("circle") || + token.isIdent("ellipse")) { + // 如果是,则将标识符的值赋给渐变对象的 shape 属性 + gradient.shape = token.value; + // 获取下一个标记 + token = parser.getToken(true, true); + } + // 检查标记是否为特定的尺寸标识符 + if (token.isIdent("closest-side") || + token.isIdent("closest-corner") || + token.isIdent("farthest-side") || + token.isIdent("farthest-corner") || + token.isIdent("contain") || + token.isIdent("cover")) { + // 如果是,则将标识符的值赋给渐变对象的 size 属性 + gradient.size = token.value; + // 获取下一个标记 + token = parser.getToken(true, true); + } + // 如果 shape 属性不存在且标记为圆形或椭圆形标识符 + if (!("shape" in gradient) && + (token.isIdent("circle") || + token.isIdent("ellipse"))) { + // 将标识符的值赋给渐变对象的 shape 属性 + gradient.shape = token.value; + // 获取下一个标记 + token = parser.getToken(true, true); + } + // 如果 shape 或 size 属性存在且标记不是逗号 + if ((("shape" in gradient) || ("size" in gradient)) && !token.isSymbol(",")) + // 返回 null + return null; + // 如果 shape 或 size 属性存在 + else if (("shape" in gradient) || ("size" in gradient)) + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 解析第一个颜色停止点 + var stop1 = this.parseColorStop(parser, token); + // 如果解析失败,则返回 null + if (!stop1) + return null; + // 获取当前标记 + token = parser.currentToken(); + // 检查标记是否为逗号 + if (!token.isSymbol(",")) + // 如果不是,则返回 null + return null; + // 获取下一个标记 + token = parser.getToken(true, true); + // 解析第二个颜色停止点 + var stop2 = this.parseColorStop(parser, token); + // 如果解析失败,则返回 null + if (!stop2) + return null; + // 获取当前标记 + token = parser.currentToken(); + // 如果标记为逗号 + if (token.isSymbol(",")) { + // 获取下一个标记 + token = parser.getToken(true, true); + } + // 将前两个颜色停止点添加到渐变对象的 stops 数组中 + gradient.stops = [stop1, stop2]; + // 循环解析剩余的颜色停止点,直到遇到右括号 + while (!token.isSymbol(")")) { + // 解析颜色停止点 + var colorstop = this.parseColorStop(parser, token); + // 如果解析失败,则返回 null + if (!colorstop) + return null; + // 获取当前标记 + token = parser.currentToken(); + // 检查标记是否为右括号或逗号 + if (!token.isSymbol(")") && !token.isSymbol(",")) + // 如果不是,则返回 null + return null; + // 如果标记为逗号 + if (token.isSymbol(",")) + // 获取下一个标记 + token = parser.getToken(true, true); + // 将颜色停止点添加到渐变对象的 stops 数组中 + gradient.stops.push(colorstop); + } + // 返回解析好的渐变对象 + return gradient; + } + } + // 如果解析失败,则返回 null + return null; +}, + +// 解析盒阴影的方法 +parseBoxShadows: function(aString) +{ +// 创建一个 CSSParser 实例 +var parser = new CSSParser(); +// 初始化解析器 +parser._init(); +// 设置解析器不保留空白字符 +parser.mPreserveWS = false; +// 设置解析器不保留注释 +parser.mPreserveComments = false; +// 初始化保留标记数组 +parser.mPreservedTokens = []; +// 初始化扫描器,传入要解析的字符串 +parser.mScanner.init(aString); + + // 初始化阴影数组 + var shadows = []; + // 获取第一个标记 + var token = parser.getToken(true, true); + // 初始化颜色、模糊半径、水平偏移、垂直偏移和扩展半径 + var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px", spreadRadius = "0px"; + // 初始化是否为内阴影的标志为 false + var inset = false; + // 循环处理标记,直到标记为空 + while (token.isNotNull()) { + // 检查标记是否为 "none" + if (token.isIdent("none")) { + // 如果是,则将一个包含 none 为 true 的对象添加到阴影数组中 + shadows.push( { none: true } ); + // 获取下一个标记 + token = parser.getToken(true, true); + } + else { + // 检查标记是否为 "inset" + if (token.isIdent('inset')) { + // 如果是,则将 inset 标志置为 true + inset = true; + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 检查标记是否为百分比或指定单位的尺寸 + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + // 如果是,则将标记的值赋给 offsetX + var offsetX = token.value; + // 获取下一个标记 + token = parser.getToken(true, true); + } + else + // 如果不是,则返回空数组 + return []; + + // 如果不是内阴影且标记为 "inset" + if (!inset && token.isIdent('inset')) { + // 将 inset 标志置为 true + inset = true; + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 检查标记是否为百分比或指定单位的尺寸 + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + // 如果是,则将标记的值赋给 offsetY + var offsetY = token.value; + // 获取下一个标记 + token = parser.getToken(true, true); + } + else + // 如果不是,则返回空数组 + return []; + + // 如果不是内阴影且标记为 "inset" + if (!inset && token.isIdent('inset')) { + // 将 inset 标志置为 true + inset = true; + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 检查标记是否为百分比或指定单位的尺寸 + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + // 如果是,则将标记的值赋给 blurRadius + var blurRadius = token.value; + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 如果不是内阴影且标记为 "inset" + if (!inset && token.isIdent('inset')) { + // 将 inset 标志置为 true + inset = true; + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 检查标记是否为颜色函数、符号或标识符 + if (token.isFunction("rgb(") || + token.isFunction("rgba(") || + token.isFunction("hsl(") || + token.isFunction("hsla(") || + token.isSymbol("#") || + token.isIdent()) { + // 如果是,则调用解析器的 parseColor 方法解析颜色 + var color = parser.parseColor(token); + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 如果不是内阴影且标记为 "inset" + if (!inset && token.isIdent('inset')) { + // 将 inset 标志置为 true + inset = true; + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 将解析好的阴影信息添加到阴影数组中 + shadows.push( { none: false, + color: color, + offsetX: offsetX, offsetY: offsetY, + blurRadius: blurRadius, + spreadRadius: spreadRadius } ); + + // 检查标记是否为逗号 + if (token.isSymbol(",")) { + // 如果是,则重置相关变量 + inset = false; + color = ""; + blurRadius = "0px"; + spreadRadius = "0px" + offsetX = "0px"; + offsetY = "0px"; + // 获取下一个标记 + token = parser.getToken(true, true); + } + else if (!token.isNotNull()) + // 如果标记为空,则返回阴影数组 + return shadows; + else + // 否则返回空数组 + return []; + } + } + // 返回阴影数组 + return shadows; +}, + +// 解析文本阴影的方法 +parseTextShadows: function(aString) +{ +// 创建一个 CSSParser 实例 +var parser = new CSSParser(); +// 初始化解析器 +parser._init(); +// 设置解析器不保留空白字符 +parser.mPreserveWS = false; +// 设置解析器不保留注释 +parser.mPreserveComments = false; +// 初始化保留标记数组 +parser.mPreservedTokens = []; +// 初始化扫描器,传入要解析的字符串 +parser.mScanner.init(aString); + + // 初始化阴影数组 + var shadows = []; + // 获取第一个标记 + var token = parser.getToken(true, true); + // 初始化颜色、模糊半径、水平偏移和垂直偏移 + var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px"; + // 循环处理标记,直到标记为空 + while (token.isNotNull()) { + // 检查标记是否为 "none" + if (token.isIdent("none")) { + // 如果是,则将一个包含 none 为 true 的对象添加到阴影数组中 + shadows.push( { none: true } ); + // 获取下一个标记 + token = parser.getToken(true, true); + } + else { + // 检查标记是否为颜色函数、符号或标识符 + if (token.isFunction("rgb(") || + token.isFunction("rgba(") || + token.isFunction("hsl(") || + token.isFunction("hsla(") || + token.isSymbol("#") || + token.isIdent()) { + // 如果是,则调用解析器的 parseColor 方法解析颜色 + var color = parser.parseColor(token); + // 获取下一个标记 + token = parser.getToken(true, true); + } + // 检查标记是否为百分比或指定单位的尺寸 + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + // 如果是,则将标记的值赋给 offsetX + var offsetX = token.value; + // 获取下一个标记 + token = parser.getToken(true, true); + } + else + // 如果不是,则返回空数组 + return []; + // 检查标记是否为百分比或指定单位的尺寸 + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + // 如果是,则将标记的值赋给 offsetY + var offsetY = token.value; + // 获取下一个标记 + token = parser.getToken(true, true); + } + else + // 如果不是,则返回空数组 + return []; + // 检查标记是否为百分比或指定单位的尺寸 + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + // 如果是,则将标记的值赋给 blurRadius + var blurRadius = token.value; + // 获取下一个标记 + token = parser.getToken(true, true); + } + // 如果颜色为空且标记为颜色函数、符号或标识符 + if (!color && + (token.isFunction("rgb(") || + token.isFunction("rgba(") || + token.isFunction("hsl(") || + token.isFunction("hsla(") || + token.isSymbol("#") || + token.isIdent())) { + // 调用解析器的 parseColor 方法解析颜色 + var color = parser.parseColor(token); + // 获取下一个标记 + token = parser.getToken(true, true); + } + + // 将解析好的阴影信息添加到阴影数组中 + shadows.push( { none: false, + color: color, + offsetX: offsetX, offsetY: offsetY, + blurRadius: blurRadius } ); + + // 检查标记是否为逗号 + if (token.isSymbol(",")) { + // 如果是,则重置相关变量 + color = ""; + blurRadius = "0px"; + offsetX = "0px"; + offsetY = "0px"; + // 获取下一个标记 + token = parser.getToken(true, true); + } + else if (!token.isNotNull()) + // 如果标记为空,则返回阴影数组 + return shadows; + else + // 否则返回空数组 + return []; + } + } + // 返回阴影数组 + return shadows; +}, + +// 解析背景图像的方法 +parseBackgroundImages: function(aString) +{ +// 创建一个 CSSParser 实例 +var parser = new CSSParser(); +// 初始化解析器 +parser._init(); +// 设置解析器不保留空白字符 +parser.mPreserveWS = false; +// 设置解析器不保留注释 +parser.mPreserveComments = false; +// 初始化保留标记数组 +parser.mPreservedTokens = []; +// 初始化扫描器,传入要解析的字符串 +parser.mScanner.init(aString); + + // 初始化背景数组 + var backgrounds = []; + // 获取第一个标记 + var token = parser.getToken(true, true); + // 循环处理标记,直到标记为空 + while (token.isNotNull()) { + /*if (token.isFunction("rgb(") || + token.isFunction("rgba(") || + token.isFunction("hsl(") || + token.isFunction("hsla(") || + token.isSymbol("#") || + token.isIdent()) { + // 如果标记为颜色相关,解析颜色并添加到背景数组中 + var color = parser.parseColor(token); + backgrounds.push( { type: "color", value: color }); + token = parser.getToken(true, true); + } + else */ + // 检查标记是否为 url 函数 + if (token.isFunction("url(")) { + // 获取下一个标记 + token = parser.getToken(true, true); + // 调用解析器的 parseURL 方法解析 URL + var urlContent = parser.parseURL(token); + // 将解析好的 URL 信息添加到背景数组中 + backgrounds.push( { type: "image", value: "url(" + urlContent }); + // 获取下一个标记 + token = parser.getToken(true, true); + } + // 检查标记是否为渐变函数 + else if (token.isFunction("-moz-linear-gradient(") || + token.isFunction("-moz-radial-gradient(") || + token.isFunction("-moz-repeating-linear-gradient(") || + token.isFunction("-moz-repeating-radial-gradient(")) { + // 调用 parseGradient 方法解析渐变 + var gradient = this.parseGradient(parser, token); + // 根据渐变类型将渐变信息添加到背景数组中 + backgrounds.push( { type: gradient.isRadial ? "radial-gradient" : "linear-gradient", value: gradient }); + // 获取下一个标记 + token = parser.getToken(true, true); + } + else + // 如果标记不符合要求,则返回 null + return null; + // 检查标记是否为逗号 + if (token.isSymbol(",")) { + // 获取下一个标记 + token = parser.getToken(true, true); + // 如果标记为空,则返回 null + if (!token.isNotNull()) + return null; + } + } + // 返回背景数组 + return backgrounds; +}, + +// 序列化渐变对象为字符串的方法 +serializeGradient: function(gradient) +{ +// 根据渐变类型和是否重复构建渐变字符串的开头部分 +var s = gradient.isRadial +? (gradient.isRepeating ? "-moz-repeating-radial-gradient(" : "-moz-radial-gradient(" ) +: (gradient.isRepeating ? "-moz-repeating-linear-gradient(" : "-moz-linear-gradient(" ); +// 如果渐变有角度或位置信息 +if (gradient.angle || gradient.position) +s += (gradient.angle ? gradient.angle + " ": "") + +(gradient.position ? gradient.position : "") + +", "; +// 如果是径向渐变且有形状或尺寸信息 +if (gradient.isRadial && (gradient.shape || gradient.size)) +s += (gradient.shape ? gradient.shape : "") + +" " + +(gradient.size ? gradient.size : "") + +", "; +// 遍历渐变的颜色停止点数组 +for (var i = 0; i < gradient.stops.length; i++) { +// 获取当前颜色停止点 +var colorstop = gradient.stops[i]; +// 将颜色停止点信息添加到渐变字符串中 +s += colorstop.color + (colorstop.position ? " " + colorstop.position : ""); +// 如果不是最后一个颜色停止点,则添加逗号 +if (i != gradient.stops.length -1) +s += ", "; +} +// 添加右括号完成渐变字符串 +s += ")"; +// 返回序列化后的渐变字符串 +return s; +}, + +// 解析边框图像的方法 +parseBorderImage: function(aString) +{ +// 创建一个 CSSParser 实例 +var parser = new CSSParser(); +// 初始化解析器 +parser._init(); +// 设置解析器不保留空白字符 +parser.mPreserveWS = false; +// 设置解析器不保留注释 +parser.mPreserveComments = false; +// 初始化保留标记数组 +parser.mPreservedTokens = []; +// 初始化扫描器,传入要解析的字符串 +parser.mScanner.init(aString); + + // 初始化边框图像对象 + var borderImage = {url: "", offsets: [], widths: [], sizes: []}; + // 获取第一个标记 + var token = parser.getToken(true, true); + // 检查标记是否为 url 函数 + if (token.isFunction("url(")) { + // 获取下一个标记 + token = parser.getToken(true, true); + // 调用解析器的 parseURL 方法解析 URL + var urlContent = parser.parseURL(token); + // 如果 URL 解析成功 + if (urlContent) { + // 处理 URL 字符串,去除首尾引号 + borderImage.url = urlContent.substr(0, urlContent.length - 1).trim(); + if ((borderImage.url[0] == '"' && borderImage.url[borderImage.url.length - 1] == '"') || + (borderImage.url[0] == "'" && borderImage.url[borderImage.url.length - 1] == "'")) + borderImage.url = borderImage.url.substr(1, borderImage.url.length - 2); + } + else + // 如果 URL 解析失败,则返回 null + return null; + } + else + // 如果标记不是 url 函数,则返回 null + return null; + + // 获取下一个标记 + token = parser.getToken(true, true); + // 检查标记是否为数字或百分比 + if (token.isNumber() || token.isPercentage()) + // 如果是,则将标记的值添加到边框图像的 offsets 数组中 + borderImage.offsets.push(token.value); + else + // 如果不是,则返回 null + return null; + // 循环处理后续的标记,最多处理 3 个 + var i; + for (i= 0; i < 3; i++) { + // 获取下一个标记 + token = parser.getToken(true, true); + // 检查标记是否为数字或百分比 + if (token.isNumber() || token.isPercentage()) + // 如果是,则将标记的值添加到边框图像的 offsets 数组中 + borderImage.offsets.push(token.value); + else + // 如果不是,则跳出循环 + break; + } + // 如果处理了 3 个标记,则获取下一个标记 + if (i == 3) + token = parser.getToken(true, true); + + // 检查标记是否为斜杠 + if (token.isSymbol("/")) { + // 获取下一个标记 + token = parser.getToken(true, true); + // 检查标记是否为尺寸、数字 0 或特定的边框宽度名称 + if (token.isDimension() + || token.isNumber("0") + || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES)) + // 如果是,则将标记的值添加到边框图像的 widths 数组中 + borderImage.widths.push(token.value); + else + // 如果不是,则返回 null + return null; + + // 循环处理后续的标记,最多处理 3 个 + for (var i = 0; i < 3; i++) { + // 获取下一个标记 + token = parser.getToken(true, true); + // 检查标记是否为尺寸、数字 0 或特定的边框宽度名称 + if (token.isDimension() + || token.isNumber("0") + || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES)) + // 如果是,则将标记的值添加到边框图像的 widths 数组中 + borderImage.widths.push(token.value); + else + // 如果不是,则跳出循环 + break; + } + // 如果处理了 3 个标记,则获取下一个标记 + if (i == 3) + token = parser.getToken(true, true); + } + + // 循环处理后续的标记,最多处理 2 个 + for (var i = 0; i < 2; i++) { + // 检查标记是否为特定的尺寸标识符 + if (token.isIdent("stretch") + || token.isIdent("repeat") + || token.isIdent("round")) + // 如果是,则将标记的值添加到边框图像的 sizes 数组中 + borderImage.sizes.push(token.value); + else if (!token.isNotNull()) + // 如果标记为空,则返回边框图像对象 + return borderImage; + else + // 如果标记不符合要求,则返回 null + return null; + // 获取下一个标记 + token = parser.getToken(true, true); + } + // 如果标记为空,则返回边框图像对象 + if (!token.isNotNull()) + return borderImage; + + // 如果解析失败,则返回 null + return null; +}, + +// 解析媒体查询的方法 +parseMediaQuery: function(aString) +{ +// 定义一个包含所有有效约束条件的对象 +var kCONSTRAINTS = { +"width": true, +"min-width": true, +"max-width": true, +"height": true, +"min-height": true, +"max-height": true, +"device-width": true, +"min-device-width": true, +"max-device-width": true, +"device-height": true, +"min-device-height": true, +"max-device-height": true, +"orientation": true, +"aspect-ratio": true, +"min-aspect-ratio": true, +"max-aspect-ratio": true, +"device-aspect-ratio": true, +"min-device-aspect-ratio": true, +"max-device-aspect-ratio": true, +"color": true, +"min-color": true, +"max-color": true, +"color-index": true, +"min-color-index": true, +"max-color-index": true, +"monochrome": true, +"min-monochrome": true, +"max-monochrome": true, +"resolution": true, +"min-resolution + +// 模拟 kCSS_VENDOR_PREFIXES +const kCSS_VENDOR_PREFIXES = { +properties: [ +{ gecko: '-moz-example', webkit: '-webkit-example', presto: '-o-example', trident: '-ms-example' } +] +}; + +// 模拟 CSSParser 类 +class CSSParser { +constructor() { +this.mScanner = { +init: function (aString) { +// 初始化扫描器逻辑 +} +}; +} + + _init() { + // 初始化解析器逻辑 + } + + getToken() { + // 模拟获取标记逻辑 + return { + isNotNull: function () { return true; }, + isFunction: function (name) { return false; }, + isAngle: function () { return false; }, + isLength: function () { return false; }, + isIdent: function (value) { return false; }, + isSymbol: function (symbol) { return false; }, + isPercentage: function () { return false; }, + isDimensionOfUnit: function (unit) { return false; }, + parseColor: function (token) { return 'color'; }, + currentToken: function () { return { isSymbol: function (symbol) { return false; } }; }, + parseURL: function (token) { return 'url-content'; } + }; + } +} + +// 定义对象 +const obj = { +kEXPORTS_FOR_GECKO: true, +kEXPORTS_FOR_WEBKIT: true, +kEXPORTS_FOR_PRESTO: true, +kEXPORTS_FOR_TRIDENT: true, +mVENDOR_PREFIXES: null, + + // 清除前缀缓存 + cleanPrefixes: function () { + this.mVENDOR_PREFIXES = null; + }, + + // 获取属性的前缀列表 + prefixesForProperty: function (aProperty) { + if (!this.mVENDOR_PREFIXES) { + this.mVENDOR_PREFIXES = {}; + // 遍历所有属性前缀 + for (var i = 0; i < kCSS_VENDOR_PREFIXES.properties.length; i++) { + var p = kCSS_VENDOR_PREFIXES.properties[i]; + if (p.gecko && (p.webkit || p.presto || p.trident)) { + var o = {}; + // 根据导出标志添加前缀 + if (this.kEXPORTS_FOR_GECKO) o[p.gecko] = true; + if (this.kEXPORTS_FOR_WEBKIT && p.webkit) o[p.webkit] = true; + if (this.kEXPORTS_FOR_PRESTO && p.presto) o[p.presto] = true; + if (this.kEXPORTS_FOR_TRIDENT && p.trident) o[p.trident] = true; + this.mVENDOR_PREFIXES[p.gecko] = []; + for (var j in o) + this.mVENDOR_PREFIXES[p.gecko].push(j) + } + } + } + if (aProperty in this.mVENDOR_PREFIXES) + return this.mVENDOR_PREFIXES[aProperty].sort(); + return null; + }, + + // 解析颜色停止点 + parseColorStop: function (parser, token) { + var color = parser.parseColor(token); + var position = ""; + if (!color) + return null; + token = parser.getToken(true, true); + // 检查是否有位置信息 + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + position = token.value; + token = parser.getToken(true, true); + } + return { color: color, position: position } + }, + + // 解析渐变 + parseGradient: function (parser, token) { + var isRadial = false; + var gradient = { isRepeating: false }; + if (token.isNotNull()) { + if (token.isFunction("-moz-linear-gradient(") || + token.isFunction("-moz-radial-gradient(") || + token.isFunction("-moz-repeating-linear-gradient(") || + token.isFunction("-moz-repeating-radial-gradient(")) { + if (token.isFunction("-moz-radial-gradient(") || + token.isFunction("-moz-repeating-radial-gradient(")) { + gradient.isRadial = true; + } + if (token.isFunction("-moz-repeating-linear-gradient(") || + token.isFunction("-moz-repeating-radial-gradient(")) { + gradient.isRepeating = true; + } + + token = parser.getToken(true, true); + var haveGradientLine = false; + var foundHorizPosition = false; + var haveAngle = false; + + // 检查是否有角度信息 + if (token.isAngle()) { + gradient.angle = token.value; + haveGradientLine = true; + haveAngle = true; + token = parser.getToken(true, true); + } + + // 检查是否有位置信息 + if (token.isLength() + || token.isIdent("top") + || token.isIdent("center") + || token.isIdent("bottom") + || token.isIdent("left") + || token.isIdent("right")) { + haveGradientLine = true; + if (token.isLength() + || token.isIdent("left") + || token.isIdent("right")) { + foundHorizPosition = true; + } + gradient.position = token.value; + token = parser.getToken(true, true); + } + + if (haveGradientLine) { + if (!haveAngle && token.isAngle()) { + gradient.angle = token.value; + haveAngle = true; + token = parser.getToken(true, true); + } + + 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")))) { + gradient.position = ("position" in gradient) ? gradient.position + " " : ""; + gradient.position += token.value; + token = parser.getToken(true, true); + } + + if (!haveAngle && token.isAngle()) { + gradient.angle = token.value; + haveAngle = true; + token = parser.getToken(true, true); + } + + if (!token.isSymbol(",")) + return null; + token = parser.getToken(true, true); + } + + if (gradient.isRadial) { + // 检查是否有形状信息 + if (token.isIdent("circle") || + token.isIdent("ellipse")) { + gradient.shape = token.value; + token = parser.getToken(true, true); + } + // 检查是否有大小信息 + if (token.isIdent("closest-side") || + token.isIdent("closest-corner") || + token.isIdent("farthest-side") || + token.isIdent("farthest-corner") || + token.isIdent("contain") || + token.isIdent("cover")) { + gradient.size = token.value; + token = parser.getToken(true, true); + } + if (!("shape" in gradient) && + (token.isIdent("circle") || + token.isIdent("ellipse"))) { + gradient.shape = token.value; + token = parser.getToken(true, true); + } + if ((("shape" in gradient) || ("size" in gradient)) && !token.isSymbol(",")) + return null; + else if (("shape" in gradient) || ("size" in gradient)) + token = parser.getToken(true, true); + } + + var stop1 = this.parseColorStop(parser, token); + if (!stop1) + return null; + token = parser.currentToken(); + if (!token.isSymbol(",")) + return null; + token = parser.getToken(true, true); + var stop2 = this.parseColorStop(parser, token); + if (!stop2) + return null; + token = parser.currentToken(); + if (token.isSymbol(",")) { + token = parser.getToken(true, true); + } + gradient.stops = [stop1, stop2]; + // 解析所有颜色停止点 + while (!token.isSymbol(")")) { + var colorstop = this.parseColorStop(parser, token); + if (!colorstop) + return null; + token = parser.currentToken(); + if (!token.isSymbol(")") && !token.isSymbol(",")) + return null; + if (token.isSymbol(",")) + token = parser.getToken(true, true); + gradient.stops.push(colorstop); + } + return gradient; + } + } + return null; + }, + + // 解析盒子阴影 + parseBoxShadows: function (aString) { + var parser = new CSSParser(); + parser._init(); + parser.mPreserveWS = false; + parser.mPreserveComments = false; + parser.mPreservedTokens = []; + parser.mScanner.init(aString); + + var shadows = []; + var token = parser.getToken(true, true); + var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px", spreadRadius = "0px"; + var inset = false; + while (token.isNotNull()) { + if (token.isIdent("none")) { + shadows.push({ none: true }); + token = parser.getToken(true, true); + } + else { + // 检查是否有 inset 关键字 + if (token.isIdent('inset')) { + inset = true; + token = parser.getToken(true, true); + } + + // 解析偏移量 X + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + var offsetX = token.value; + token = parser.getToken(true, true); + } + else + return []; + + if (!inset && token.isIdent('inset')) { + inset = true; + token = parser.getToken(true, true); + } + + // 解析偏移量 Y + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + var offsetY = token.value; + token = parser.getToken(true, true); + } + else + return []; + + if (!inset && token.isIdent('inset')) { + inset = true; + token = parser.getToken(true, true); + } + + // 解析模糊半径 + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + var blurRadius = token.value; + token = parser.getToken(true, true); + } + + if (!inset && token.isIdent('inset')) { + inset = true; + token = parser.getToken(true, true); + } + + // 解析颜色 + if (token.isFunction("rgb(") || + token.isFunction("rgba(") || + token.isFunction("hsl(") || + token.isFunction("hsla(") || + token.isSymbol("#") || + token.isIdent()) { + var color = parser.parseColor(token); + token = parser.getToken(true, true); + } + + if (!inset && token.isIdent('inset')) { + inset = true; + token = parser.getToken(true, true); + } + + shadows.push({ none: false, + color: color, + offsetX: offsetX, offsetY: offsetY, + blurRadius: blurRadius, + spreadRadius: spreadRadius }); + + if (token.isSymbol(",")) { + inset = false; + color = ""; + blurRadius = "0px"; + spreadRadius = "0px" + offsetX = "0px"; + offsetY = "0px"; + token = parser.getToken(true, true); + } + else if (!token.isNotNull()) + return shadows; + else + return []; + } + } + return shadows; + }, + + // 解析文本阴影 + parseTextShadows: function (aString) { + var parser = new CSSParser(); + parser._init(); + parser.mPreserveWS = false; + parser.mPreserveComments = false; + parser.mPreservedTokens = []; + parser.mScanner.init(aString); + + var shadows = []; + var token = parser.getToken(true, true); + var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px"; + while (token.isNotNull()) { + if (token.isIdent("none")) { + shadows.push({ none: true }); + token = parser.getToken(true, true); + } + else { + // 解析颜色 + if (token.isFunction("rgb(") || + token.isFunction("rgba(") || + token.isFunction("hsl(") || + token.isFunction("hsla(") || + token.isSymbol("#") || + token.isIdent()) { + var color = parser.parseColor(token); + token = parser.getToken(true, true); + } + // 解析偏移量 X + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + var offsetX = token.value; + token = parser.getToken(true, true); + } + else + return []; + // 解析偏移量 Y + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + var offsetY = token.value; + token = parser.getToken(true, true); + } + else + return []; + // 解析模糊半径 + if (token.isPercentage() || + token.isDimensionOfUnit("cm") || + token.isDimensionOfUnit("mm") || + token.isDimensionOfUnit("in") || + token.isDimensionOfUnit("pc") || + token.isDimensionOfUnit("px") || + token.isDimensionOfUnit("em") || + token.isDimensionOfUnit("ex") || + token.isDimensionOfUnit("pt")) { + var blurRadius = token.value; + token = parser.getToken(true, true); + } + if (!color && + (token.isFunction("rgb(") || + token.isFunction("rgba(") || + token.isFunction("hsl(") || + token.isFunction("hsla(") || + token.isSymbol("#") || + token.isIdent())) { + var color = parser.parseColor(token); + token = parser.getToken(true, true); + } + + shadows.push({ none: false, + color: color, + offsetX: offsetX, offsetY: offsetY, + blurRadius: blurRadius }); + + if (token.isSymbol(",")) { + color = ""; + blurRadius = "0px"; + offsetX = "0px"; + offsetY = "0px"; + token = parser.getToken(true, true); + } + else if (!token.isNotNull()) + return shadows; + else + return []; + } + } + return shadows; + }, + + // 解析背景图像 + parseBackgroundImages: function (aString) { + var parser = new CSSParser(); + parser._init(); + parser.mPreserveWS = false; + parser.mPreserveComments = false; + parser.mPreservedTokens = []; + parser.mScanner.init(aString); + + var backgrounds = []; + var token = parser.getToken(true, true); + while (token.isNotNull()) { + if (token.isFunction("url(")) { + token = parser.getToken(true, true); + var urlContent = parser.parseURL(token); + backgrounds.push({ type: "image", value: "url(" + urlContent }); + token = parser.getToken(true, true); + } + else if (token.isFunction("-moz-linear-gradient(") || + token.isFunction("-moz-radial-gradient(") || + token.isFunction("-moz-repeating-linear-gradient(") || + token.isFunction("-moz-repeating-radial-gradient(")) { + var gradient = this.parseGradient(parser, token); + backgrounds.push({ type: gradient.isRadial ? "radial-gradient" : "linear-gradient", value: gradient }); + token = parser.getToken(true, true); + } + else + return null; + if (token.isSymbol(",")) { + token = parser.getToken(true, true); + if (!token.isNotNull()) + return null; + } + } + return backgrounds; + }, + + // 序列化渐变 + serializeGradient: function (gradient) { + var s = gradient.isRadial + ? (gradient.isRepeating ? "-moz-repeating-radial-gradient(" : "-moz-radial-gradient(" ) + : (gradient.isRepeating ? "-moz-repeating-linear-gradient(" : "-moz-linear-gradient(" ); + if (gradient.angle || gradient.position) + s += (gradient.angle ? gradient.angle + " " : "") + + (gradient.position ? gradient.position : "") + + ", "; + if (gradient.isRadial && (gradient.shape || gradient.size)) + s += (gradient.shape ? gradient.shape : "") + + " " + + (gradient.size ? gradient.size : "") + + ", "; + for (var i = 0; i < gradient.stops.length; i++) { + var colorstop = gradient.stops[i]; + s += colorstop.color + (colorstop.position ? " " + colorstop.position : ""); + if (i != gradient.stops.length - 1) + s += ", "; + } + s += ")"; + return s; + }, + + // 解析边框图像 + parseBorderImage: function (aString) { + var parser = new CSSParser(); + parser._init(); + parser.mPreserveWS = false; + parser.mPreserveComments = false; + parser.mPreservedTokens = []; + parser.mScanner.init(aString); + + var borderImage = { url: "", offsets: [], widths: [], sizes: [] }; + var token = parser.getToken(true, true); + if (token.isFunction("url(")) { + token = parser.getToken(true, true); + var urlContent = parser.parseURL(token); + if (urlContent) { + borderImage.url = urlContent.substr(0, urlContent.length - 1).trim(); + if ((borderImage.url[0] == '"' && borderImage.url[borderImage.url.length - 1] == '"') || + (borderImage.url[0] == "'" && borderImage.url[borderImage.url.length - 1] == "'")) + borderImage.url = borderImage.url.substr(1, borderImage.url.length - 2); + } + else + return null; + } + else + return null; + + token = parser.getToken(true, true); + if (token.isNumber() || token.isPercentage()) + borderImage.offsets.push(token.value); + else + return null; + var i; + for (i = 0; i < 3; i++) { + token = parser.getToken(true, true); + if (token.isNumber() || token.isPercentage()) + borderImage.offsets.push(token.value); + else + break; + } + if (i == 3) + token = parser.getToken(true, true); + + if (token.isSymbol("/")) { + token = parser.getToken(true, true); + if (token.isDimension() + || token.isNumber("0") + || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES)) + borderImage.widths.push(token.value); + else + return null; + + for (var i = 0; i < 3; i++) { + token = parser.getToken(true, true); + if (token.isDimension() + || token.isNumber("0") + || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES)) + borderImage.widths.push(token.value); + else + break; + } + if (i == 3) + token = parser.getToken(true, true); + } + + for (var i = 0; i < 2; i++) { + if (token.isIdent("stretch") + || token.isIdent("repeat") + || token.isIdent("round")) + borderImage.sizes.push(token.value); + else if (!token.isNotNull()) + return borderImage; + else + return null; + token = parser.getToken(true, true); + } + if (!token.isNotNull()) + return borderImage; + + return null; + }, + + // 解析媒体查询 + parseMediaQuery: function (aString) { + var kCONSTRAINTS = { + "width": true, + "min-width": true, + "max-width": true, + "height": true, + "min-height": true, + "max-height": true, + "device-width": true, + "min-device-width": true, + "max-device-width": true, + "device-height": true, + "min-device-height": true, + "max-device-height": true, + "orientation": true, + "aspect-ratio": true, + "min-aspect-ratio": true, + "max-aspect-ratio": true, + "device-aspect-ratio": true, + "min-device-aspect-ratio": true, + "max-device-aspect-ratio": true, + "color": true, + "min-color": true, + "max-color": true, + "color-index": true, + "min-color-index": true, + "max-color-index": true, + "monochrome": true, + "min-monochrome": true, + "max-monochrome": true, + "resolution": true, + "min-resolution": true, + "max-resolution": true, + "scan": true, + "grid": true + }; + var parser = new CSSParser(); + parser._init(); + parser.mPreserveWS = false; + parser.mPreserveComments = false; + parser.mPreservedTokens = []; + parser.mScanner.init(aString); + + var m = { amplifier: "", medium: "", constraints: [] }; + var token = parser.getToken(true, true); + + if (token.isIdent("all") || + token.isIdent("aural") || + token.isIdent("braille") || + token.isIdent("handheld") || + token.isIdent("print") || + token.isIdent("projection") || + token.isIdent("screen") || + token.isIdent("tty") || + token.isIdent("tv")) { + m.medium = token.value; + token = parser.getToken(true, true); + } + else if (token.isIdent("not") || token.isIdent("only")) { + m.amplifier = token.value; + token = parser.getToken(true, true); + if (token.isIdent("all") || + token.isIdent("aural") || + token.isIdent("braille") || + token.isIdent("handheld") || + token.isIdent("print") || + token.isIdent("projection") || + token.isIdent("screen") || + token.isIdent("tty") || + token.isIdent("tv")) { + m.medium = token.value; + token = parser.getToken(true, true); + } + else + return null; + } + + if (m.medium) { + if (!token.isNotNull()) + return m; + if (token.isIdent("and")) { + token = parser.getToken(true, true); + } + else + return null; + } + + while (token.isSymbol("(")) { + token = parser.getToken(true, true); + if (token.isIdent() && (token.value in kCONSTRAINTS)) { + var constraint = token.value; + token = parser.getToken(true, true); + if (token.isSymbol(":")) { + token = parser.getToken(true, true); + var values = []; + while (!token.isSymbol(")")) { + values.push(token.value); + token = parser.getToken(true, true); + } + if (token.isSymbol(")")) { + m.constraints.push({ constraint: constraint, value: values }); + token = parser.getToken(true, true); + if (token.isNotNull()) { + if (token.isIdent("and")) { + token = parser.getToken(true, true); + } + else + return null; + } + else + return m; + } + else + return null; + } + else if (token.isSymbol(")")) { + m.constraints.push({ constraint: constraint, value: null }); + token = parser.getToken(true, true); + if (token.isNotNull()) { + if (token.isIdent("and")) { + token = parser.getToken(true, true); + } + else + return null; + } + else + return m; + } + else + return null; + } + else + return null; + } + return m; + } +}; + +// 简单测试 +console.log(obj.prefixesForProperty('-moz-example')); + +// 解析命名空间规则 +parseNamespaceRule: function(aToken, aSheet) { +// 获取当前行号,通过 CountLF 函数统计已扫描内容中的换行符数量 +var currentLine = CountLF(this.mScanner.getAlreadyScanned()); +// 初始化规则字符串,赋值为当前 token 的值 +var s = aToken.value; +// 标记规则是否有效,初始为 false +var valid = false; +// 保存当前解析状态 +this.preserveState(); +// 获取下一个 token +var token = this.getToken(true, true); +if (token.isNotNull()) { +// 初始化前缀为空字符串 +var prefix = ""; +// 初始化 URL 为空字符串 +var url = ""; +if (token.isIdent()) { +// 如果 token 是标识符,将其赋值给前缀 +prefix = token.value; +// 将前缀添加到规则字符串中 +s += " " + prefix; +// 获取下一个 token +token = this.getToken(true, true); +} +if (token) { +// 标记是否找到 URL,初始为 false +var foundURL = false; +if (token.isString()) { +// 如果 token 是字符串,标记找到 URL +foundURL = true; +// 将字符串赋值给 URL +url = token.value; +// 将 URL 添加到规则字符串中 +s += " " + url; +} else if (token.isFunction("url(")) { +// 如果 token 是 url 函数,获取下一个 token +token = this.getToken(true, true); +// 解析 URL 内容 +var urlContent = this.parseURL(token); +if (urlContent) { +// 如果解析成功,将 url 内容添加到 URL 中 +url += "url(" + urlContent; +// 标记找到 URL +foundURL = true; +// 将 url 内容添加到规则字符串中 +s += " " + urlContent; +} +} +} +if (foundURL) { +// 如果找到 URL,获取下一个 token +token = this.getToken(true, true); +if (token.isSymbol(";")) { +// 如果 token 是分号,将分号添加到规则字符串中 +s += ";"; +// 忘记之前保存的状态 +this.forgetState(); +// 创建一个新的 jscsspNamespaceRule 对象 +var rule = new jscsspNamespaceRule(); +// 设置规则的当前行号 +rule.currentLine = currentLine; +// 设置规则的解析后的 CSS 文本 +rule.parsedCssText = s; +// 设置规则的前缀 +rule.prefix = prefix; +// 设置规则的 URL +rule.url = url; +// 设置规则的父样式表 +rule.parentStyleSheet = aSheet; +// 将规则添加到父样式表的 CSS 规则列表中 +aSheet.cssRules.push(rule); +// 返回 true 表示规则解析成功 +return true; +} +} +} +// 恢复之前保存的状态 +this.restoreState(); +// 将未知的 @namespace 规则添加到样式表中 +this.addUnknownAtRule(aSheet, "@namespace"); +// 返回 false 表示规则解析失败 +return false; +}, + +// 解析字体规则 +parseFontFaceRule: function(aToken, aSheet) { +// 获取当前行号,通过 CountLF 函数统计已扫描内容中的换行符数量 +var currentLine = CountLF(this.mScanner.getAlreadyScanned()); +// 初始化规则字符串,赋值为当前 token 的值 +var s = aToken.value; +// 标记规则是否有效,初始为 false +var valid = false; +// 初始化描述符数组 +var descriptors = []; +// 保存当前解析状态 +this.preserveState(); +// 获取下一个 token +var token = this.getToken(true, true); +if (token.isNotNull()) { +// 期望遇到块开始符号 { +if (token.isSymbol("{")) { +// 将块开始符号添加到规则字符串中 +s += " " + token.value; +// 获取下一个 token +var token = this.getToken(true, false); +while (true) { +if (token.isSymbol("}")) { +// 如果遇到块结束符号 },将其添加到规则字符串中 +s += "}"; +// 标记规则有效 +valid = true; +// 跳出循环 +break; +} else { +// 解析声明 +var d = this.parseDeclaration(token, descriptors, false, false, aSheet); +// 将声明添加到规则字符串中 +s += ((d && descriptors.length) ? " " : "") + d; +} +// 获取下一个 token +token = this.getToken(true, false); +} +} +} +if (valid) { +// 如果规则有效,忘记之前保存的状态 +this.forgetState(); +// 创建一个新的 jscsspFontFaceRule 对象 +var rule = new jscsspFontFaceRule(); +// 设置规则的当前行号 +rule.currentLine = currentLine; +// 设置规则的解析后的 CSS 文本 +rule.parsedCssText = s; +// 设置规则的描述符 +rule.descriptors = descriptors; +// 设置规则的父样式表 +rule.parentStyleSheet = aSheet; +// 将规则添加到父样式表的 CSS 规则列表中 +aSheet.cssRules.push(rule); +// 返回 true 表示规则解析成功 +return true; +} +// 恢复之前保存的状态 +this.restoreState(); +// 返回 false 表示规则解析失败 +return false; +}, + +// 解析页面规则 +parsePageRule: function(aToken, aSheet) { +// 获取当前行号,通过 CountLF 函数统计已扫描内容中的换行符数量 +var currentLine = CountLF(this.mScanner.getAlreadyScanned()); +// 初始化规则字符串,赋值为当前 token 的值 +var s = aToken.value; +// 标记规则是否有效,初始为 false +var valid = false; +// 初始化声明数组 +var declarations = []; +// 保存当前解析状态 +this.preserveState(); +// 获取下一个 token +var token = this.getToken(true, true); +// 初始化页面选择器为空字符串 +var pageSelector = ""; +if (token.isSymbol(":") || token.isIdent()) { +if (token.isSymbol(":")) { +// 如果 token 是冒号,将其添加到页面选择器中 +pageSelector = ":"; +// 获取下一个 token +token = this.getToken(false, false); +} +if (token.isIdent()) { +// 如果 token 是标识符,将其添加到页面选择器中 +pageSelector += token.value; +// 将页面选择器添加到规则字符串中 +s += " " + pageSelector; +// 获取下一个 token +token = this.getToken(true, true); +} +} +if (token.isNotNull()) { +// 期望遇到块开始符号 { +if (token.isSymbol("{")) { +// 将块开始符号添加到规则字符串中 +s += " " + token.value; +// 获取下一个 token +var token = this.getToken(true, false); +while (true) { +if (token.isSymbol("}")) { +// 如果遇到块结束符号 },将其添加到规则字符串中 +s += "}"; +// 标记规则有效 +valid = true; +// 跳出循环 +break; +} else { +// 解析声明 +var d = this.parseDeclaration(token, declarations, true, true, aSheet); +// 将声明添加到规则字符串中 +s += ((d && declarations.length) ? " " : "") + d; +} +// 获取下一个 token +token = this.getToken(true, false); +} +} +} +if (valid) { +// 如果规则有效,忘记之前保存的状态 +this.forgetState(); +// 创建一个新的 jscsspPageRule 对象 +var rule = new jscsspPageRule(); +// 设置规则的当前行号 +rule.currentLine = currentLine; +// 设置规则的解析后的 CSS 文本 +rule.parsedCssText = s; +// 设置规则的页面选择器 +rule.pageSelector = pageSelector; +// 设置规则的声明 +rule.declarations = declarations; +// 设置规则的父样式表 +rule.parentStyleSheet = aSheet; +// 将规则添加到父样式表的 CSS 规则列表中 +aSheet.cssRules.push(rule); +// 返回 true 表示规则解析成功 +return true; +} +// 恢复之前保存的状态 +this.restoreState(); +// 返回 false 表示规则解析失败 +return false; +}, + +// 解析默认属性值 +parseDefaultPropertyValue: function(token, aDecl, aAcceptPriority, descriptor, aSheet) { +// 初始化属性值文本为空字符串 +var valueText = ""; +// 初始化块栈,用于处理嵌套的块 +var blocks = []; +// 标记是否找到优先级,初始为 false +var foundPriority = false; +// 初始化值数组 +var values = []; +while (token.isNotNull()) { +if ((token.isSymbol(";") +|| token.isSymbol("}") +|| token.isSymbol("!")) +&& !blocks.length) { +if (token.isSymbol("}")) { +// 如果遇到块结束符号 },将其放回扫描器 +this.ungetToken(); +} +// 跳出循环 +break; +} +if (token.isIdent(this.kINHERIT)) { +if (values.length) { +// 如果值数组不为空,返回空字符串表示解析失败 +return ""; +} else { +// 将 inherit 赋值给属性值文本 +valueText = this.kINHERIT; +// 创建一个新的 jscsspVariable 对象表示 inherit 值 +var value = new jscsspVariable(kJscsspINHERIT_VALUE, aSheet); +// 将值添加到值数组中 +values.push(value); +// 获取下一个 token +token = this.getToken(true, true); +// 跳出循环 +break; +} +} else if (token.isSymbol("{") +|| token.isSymbol("(") +|| token.isSymbol("[")) { +// 如果遇到块开始符号,将其添加到块栈中 +blocks.push(token.value); +} else if (token.isSymbol("}") +|| token.isSymbol("]")) { +if (blocks.length) { +// 获取块栈顶元素 +var ontop = blocks[blocks.length - 1]; +if ((token.isSymbol("}") && ontop == "{") +|| (token.isSymbol(")") && ontop == "(") +|| (token.isSymbol("]") && ontop == "[")) { +// 如果匹配到对应的块结束符号,将栈顶元素弹出 +blocks.pop(); +} +} +} +// 处理函数调用 +if (token.isFunction()) { +if (token.isFunction("var(")) { +// 如果是 var 函数,获取下一个 token +token = this.getToken(true, true); +if (token.isIdent()) { +// 如果是标识符,获取变量名 +var name = token.value; +// 获取下一个 token +token = this.getToken(true, true); +if (token.isSymbol(")")) { +// 如果是右括号,创建一个新的 jscsspVariable 对象表示变量值 +var value = new jscsspVariable(kJscsspVARIABLE_VALUE, aSheet); +// 将变量名添加到属性值文本中 +valueText += "var(" + name + ")"; +// 设置变量名 +value.name = name; +// 将值添加到值数组中 +values.push(value); +} else { +// 解析失败,返回空字符串 +return ""; +} +} else { +// 解析失败,返回空字符串 +return ""; +} +} else { +// 如果是其他函数,获取函数名 +var fn = token.value; +// 获取下一个 token +token = this.getToken(false, true); +// 解析函数参数 +var arg = this.parseFunctionArgument(token); +if (arg) { +// 如果解析成功,将函数名和参数添加到属性值文本中 +valueText += fn + arg; +// 创建一个新的 jscsspVariable 对象表示函数值 +var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); +// 设置函数值 +value.value = fn + arg; +// 将值添加到值数组中 +values.push(value); +} else { +// 解析失败,返回空字符串 +return ""; +} +} +} else if (token.isSymbol("#")) { +// 如果是 # 符号,解析颜色值 +var color = this.parseColor(token); +if (color) { +// 如果解析成功,将颜色值添加到属性值文本中 +valueText += color; +// 创建一个新的 jscsspVariable 对象表示颜色值 +var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); +// 设置颜色值 +value.value = color; +// 将值添加到值数组中 +values.push(value); +} else { +// 解析失败,返回空字符串 +return ""; +} +} else if (!token.isWhiteSpace() && !token.isSymbol(",")) { +// 如果不是空白字符或逗号,创建一个新的 jscsspVariable 对象表示原始值 +var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); +// 设置原始值 +value.value = token.value; +// 将值添加到值数组中 +values.push(value); +// 将原始值添加到属性值文本中 +valueText += token.value; +} else { +// 将空白字符或逗号添加到属性值文本中 +valueText += token.value; +} +// 获取下一个 token +token = this.getToken(false, true); +} +if (values.length && valueText) { +// 如果值数组和属性值文本都不为空,忘记之前保存的状态 +this.forgetState(); +// 创建一个新的 jscsspDeclaration 对象并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValuesArray(descriptor, values, valueText)); +// 返回属性值文本 +return valueText; +} +// 解析失败,返回空字符串 +return ""; +}, + +// 解析边距或内边距简写属性 +parseMarginOrPaddingShorthand: function(token, aDecl, aAcceptPriority, aProperty) { +// 初始化顶部边距或内边距为 null +var top = null; +// 初始化底部边距或内边距为 null +var bottom = null; +// 初始化左边距或内边距为 null +var left = null; +// 初始化右边距或内边距为 null +var right = null; +// 初始化值数组 +var values = []; +while (true) { +if (!token.isNotNull()) { +// 如果 token 为空,跳出循环 +break; +} +if (token.isSymbol(";") +|| (aAcceptPriority && token.isSymbol("!")) +|| token.isSymbol("}")) { +if (token.isSymbol("}")) { +// 如果遇到块结束符号 },将其放回扫描器 +this.ungetToken(); +} +// 跳出循环 +break; +} else if (!values.length && token.isIdent(this.kINHERIT)) { +// 如果值数组为空且 token 是 inherit,将 inherit 添加到值数组中 +values.push(token.value); +// 获取下一个 token +token = this.getToken(true, true); +// 跳出循环 +break; +} else if (token.isDimension() +|| token.isNumber("0") +|| token.isPercentage() +|| token.isIdent("auto")) { +// 如果 token 是尺寸、数字 0、百分比或 auto,将其添加到值数组中 +values.push(token.value); +} else { +// 解析失败,返回空字符串 +return ""; +} +// 获取下一个 token +token = this.getToken(true, true); +} +// 获取值数组的长度 +var count = values.length; +switch (count) { +case 1: +// 如果只有一个值,将其赋值给顶部、底部、左边和右边的边距或内边距 +top = values[0]; +bottom = top; +left = top; +right = top; +break; +case 2: +// 如果有两个值,将第一个值赋值给顶部和底部,第二个值赋值给左边和右边 +top = values[0]; +bottom = top; +left = values[1]; +right = left; +break; +case 3: +// 如果有三个值,将第一个值赋值给顶部,第二个值赋值给左边和右边,第三个值赋值给底部 +top = values[0]; +left = values[1]; +right = left; +bottom = values[2]; +break; +case 4: +// 如果有四个值,分别赋值给顶部、右边、底部和左边 +top = values[0]; +right = values[1]; +bottom = values[2]; +left = values[3]; +break; +default: +// 解析失败,返回空字符串 +return ""; +} +// 忘记之前保存的状态 +this.forgetState(); +// 创建顶部边距或内边距的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-top", top)); +// 创建右边距或内边距的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-right", right)); +// 创建底部边距或内边距的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-bottom", bottom)); +// 创建左边距或内边距的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-left", left)); +// 返回边距或内边距的值 +return top + " " + right + " " + bottom + " " + left; +}, + +// 解析边框颜色简写属性 +parseBorderColorShorthand: function(token, aDecl, aAcceptPriority) { +// 初始化顶部边框颜色为 null +var top = null; +// 初始化底部边框颜色为 null +var bottom = null; +// 初始化左边框颜色为 null +var left = null; +// 初始化右边框颜色为 null +var right = null; +// 初始化值数组 +var values = []; +while (true) { +if (!token.isNotNull()) { +// 如果 token 为空,跳出循环 +break; +} +if (token.isSymbol(";") +|| (aAcceptPriority && token.isSymbol("!")) +|| token.isSymbol("}")) { +if (token.isSymbol("}")) { +// 如果遇到块结束符号 },将其放回扫描器 +this.ungetToken(); +} +// 跳出循环 +break; +} else if (!values.length && token.isIdent(this.kINHERIT)) { +// 如果值数组为空且 token 是 inherit,将 inherit 添加到值数组中 +values.push(token.value); +// 获取下一个 token +token = this.getToken(true, true); +// 跳出循环 +break; +} else { +// 解析颜色值 +var color = this.parseColor(token); +if (color) { +// 如果解析成功,将颜色值添加到值数组中 +values.push(color); +} else { +// 解析失败,返回空字符串 +return ""; +} +} +// 获取下一个 token +token = this.getToken(true, true); +} +// 获取值数组的长度 +var count = values.length; +switch (count) { +case 1: +// 如果只有一个值,将其赋值给顶部、底部、左边和右边的边框颜色 +top = values[0]; +bottom = top; +left = top; +right = top; +break; +case 2: +// 如果有两个值,将第一个值赋值给顶部和底部,第二个值赋值给左边和右边 +top = values[0]; +bottom = top; +left = values[1]; +right = left; +break; +case 3: +// 如果有三个值,将第一个值赋值给顶部,第二个值赋值给左边和右边,第三个值赋值给底部 +top = values[0]; +left = values[1]; +right = left; +bottom = values[2]; +break; +case 4: +// 如果有四个值,分别赋值给顶部、右边、底部和左边 +top = values[0]; +right = values[1]; +bottom = values[2]; +left = values[3]; +break; +default: +// 解析失败,返回空字符串 +return ""; +} +// 忘记之前保存的状态 +this.forgetState(); +// 创建顶部边框颜色的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("border-top-color", top)); +// 创建右边框颜色的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("border-right-color", right)); +// 创建底部边框颜色的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-color", bottom)); +// 创建左边框颜色的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("border-left-color", left)); +// 返回边框颜色的值 +return top + " " + right + " " + bottom + " " + left; +}, + +// 解析提示音简写属性 +parseCueShorthand: function(token, declarations, aAcceptPriority) { +// 初始化提示音开始为空字符串 +var before = ""; +// 初始化提示音结束为空字符串 +var after = ""; +// 初始化值数组 +var values = []; +while (true) { +if (!token.isNotNull()) { +// 如果 token 为空,跳出循环 +break; +} +if (token.isSymbol(";") +|| (aAcceptPriority && token.isSymbol("!")) +|| token.isSymbol("}")) { +if (token.isSymbol("}")) { +// 如果遇到块结束符号 },将其放回扫描器 +this.ungetToken(); +} +// 跳出循环 +break; +} else if (!values.length && token.isIdent(this.kINHERIT)) { +// 如果值数组为空且 token 是 inherit,将 inherit 添加到值数组中 +values.push(token.value); +} else if (token.isIdent("none")) { +// 如果 token 是 none,将其添加到值数组中 +values.push(token.value); +} else if (token.isFunction("url(")) { +// 如果 token 是 url 函数,获取下一个 token +var token = this.getToken(true, true); +// 解析 URL 内容 +var urlContent = this.parseURL(token); +if (urlContent) { +// 如果解析成功,将 url 内容添加到值数组中 +values.push("url(" + urlContent); +} else { +// 解析失败,返回空字符串 +return ""; +} +} else { +// 解析失败,返回空字符串 +return ""; +} +// 获取下一个 token +token = this.getToken(true, true); +} +// 获取值数组的长度 +var count = values.length; +switch (count) { +case 1: +// 如果只有一个值,将其赋值给提示音开始和结束 +before = values[0]; +after = before; +break; +case 2: +// 如果有两个值,分别赋值给提示音开始和结束 +before = values[0]; +after = values[1]; +break; +default: +// 解析失败,返回空字符串 +return ""; +} +// 忘记之前保存的状态 +this.forgetState(); +// 创建提示音开始的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("cue-before", before)); +// 创建提示音结束的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("cue-after", after)); +// 返回提示音的值 +return before + " " + after; +}, + +// 解析暂停时间简写属性 +parsePauseShorthand: function(token, declarations, aAcceptPriority) { +// 初始化暂停开始时间为空字符串 +var before = ""; +// 初始化暂停结束时间为空字符串 +var after = ""; +// 初始化值数组 +var values = []; +while (true) { +if (!token.isNotNull()) { +// 如果 token 为空,跳出循环 +break; +} +if (token.isSymbol(";") +|| (aAcceptPriority && token.isSymbol("!")) +|| token.isSymbol("}")) { +if (token.isSymbol("}")) { +// 如果遇到块结束符号 },将其放回扫描器 +this.ungetToken(); +} +// 跳出循环 +break; +} else if (!values.length && token.isIdent(this.kINHERIT)) { +// 如果值数组为空且 token 是 inherit,将 inherit 添加到值数组中 +values.push(token.value); +} else if (token.isDimensionOfUnit("ms") +|| token.isDimensionOfUnit("s") +|| token.isPercentage() +|| token.isNumber("0")) { +// 如果 token 是毫秒、秒、百分比或数字 0,将其添加到值数组中 +values.push(token.value); +} else { +// 解析失败,返回空字符串 +return ""; +} +// 获取下一个 token +token = this.getToken(true, true); +} +// 获取值数组的长度 +var count = values.length; +switch (count) { +case 1: +// 如果只有一个值,将其赋值给暂停开始和结束时间 +before = values[0]; +after = before; +break; +case 2: +// 如果有两个值,分别赋值给暂停开始和结束时间 +before = values[0]; +after = values[1]; +break; +default: +// 解析失败,返回空字符串 +return ""; +} +// 忘记之前保存的状态 +this.forgetState(); +// 创建暂停开始时间的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("pause-before", before)); +// 创建暂停结束时间的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("pause-after", after)); +// 返回暂停时间的值 +return before + " " + after; +}, + +// 解析边框宽度简写属性 +parseBorderWidthShorthand: function(token, aDecl, aAcceptPriority) { +// 初始化顶部边框宽度为 null +var top = null; +// 初始化底部边框宽度为 null +var bottom = null; +// 初始化左边框宽度为 null +var left = null; +// 初始化右边框宽度为 null +var right = null; +// 初始化值数组 +var values = []; +while (true) { +if (!token.isNotNull()) { +// 如果 token 为空,跳出循环 +break; +} +if (token.isSymbol(";") +|| (aAcceptPriority && token.isSymbol("!")) +|| token.isSymbol("}")) { +if (token.isSymbol("}")) { +// 如果遇到块结束符号 },将其放回扫描器 +this.ungetToken(); +} +// 跳出循环 +break; +} else if (!values.length && token.isIdent(this.kINHERIT)) { +// 如果值数组为空且 token 是 inherit,将 inherit 添加到值数组中 +values.push(token.value); +} else if (token.isDimension() +|| token.isNumber("0") +|| (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES)) { +// 如果 token 是尺寸、数字 0 或边框宽度名称,将其添加到值数组中 +values.push(token.value); +} else { +// 解析失败,返回空字符串 +return ""; +} +// 获取下一个 token +token = this.getToken(true, true); +} +// 获取值数组的长度 +var count = values.length; +switch (count) { +case 1: +// 如果只有一个值,将其赋值给顶部、底部、左边和右边的边框宽度 +top = values[0]; +bottom = top; +left = top; +right = top; +break; +case 2: +// 如果有两个值,将第一个值赋值给顶部和底部,第二个值赋值给左边和右边 +top = values[0]; +bottom = top; +left = values[1]; +right = left; +break; +case 3: +// 如果有三个值,将第一个值赋值给顶部,第二个值赋值给左边和右边,第三个值赋值给底部 +top = values[0]; +left = values[1]; +right = left; +bottom = values[2]; +break; +case 4: +// 如果有四个值,分别赋值给顶部、右边、底部和左边 +top = values[0]; +right = values[1]; +bottom = values[2]; +left = values[3]; +break; +default: +// 解析失败,返回空字符串 +return ""; +} +// 忘记之前保存的状态 +this.forgetState(); +// 创建顶部边框宽度的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("border-top-width", top)); +// 创建右边框宽度的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("border-right-width", right)); +// 创建底部边框宽度的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-width", bottom)); +// 创建左边框宽度的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFromValue("border-left-width", left)); +// 返回边框宽度的值 +return top + " " + right + " " + bottom + " " + left; +}, + +// 解析边框样式简写属性 +parseBorderStyleShorthand: function(token, aDecl, aAcceptPriority) { +// 初始化顶部边框样式为 null +var top = null; +// 初始化底部边框样式为 null +var bottom = null; +// 初始化左边框样式为 null +var left = null; +// 初始化右边框样式为 null +var right = null; +// 初始化值数组 +var values = []; +while (true) { +if (!token.isNotNull()) { +// 如果 token 为空,跳出循环 +break; +} +if (token.isSymbol(";") +|| (aAcceptPriority && token.isSymbol("!")) +|| token.isSymbol("}")) { +if (token.isSymbol("}")) { +// 如果遇到块结束符号 },将其放回扫描器 +this.ungetToken(); +} +// 跳出循环 +break; +} else if (!values.length && token.isIdent(this.kINHERIT)) { +// 如果值数组为空且 token 是 inherit,将 inherit 添加到值数组中 +values.push(token.value); +} else if (token.isIdent() && token.value in this.kBORDER_STYLE_NAMES) { +// 如果 token 是边框样式名称,将其添加到值数组中 +values.push(token.value); +} else { +// 解析失败,返回空字符串 +return ""; +} +// 获取下一个 token +token = this.getToken(true, true); +} +// 获取值数组的长度 +var count = values.length; +switch (count) { +case 1: +// 如果只有一个值,将其赋值给顶部、底部、左边和右边的边框样式 +top = values[0]; +bottom = top; +left = top; +right = top; +break; +case 2: +// 如果有两个值,将第一个值赋值给顶部和底部,第二个值赋值给左边和右边 +top = values[0]; +bottom = top; +left = values[1]; +right = left; +break; +case 3: +// 如果有三个值,将第一个值赋值给顶部,第二个值赋值给左边和右边,第三个值赋值给底部 +top = values[0]; +left = values[1]; +right = left; +bottom = values[2]; +break; +case 4: +// 如果有四个值,分别赋值给顶部、右边、底部和左边 +top = values[0]; +right = values[1]; +bottom = values[2]; +left = values[3]; +break; +default: +// 解析失败,返回空字符串 +return ""; +} +// 忘记之前保存的状态 +this.forgetState(); +// 创建顶部边框样式的声明并添加到声明数组中 +aDecl.push(this._createJscsspDeclarationFrom + +以下是为你提供的代码注释: + +```javascript +// 解析媒体规则的函数 +// aToken: 当前的 token +// aSheet: 当前的样式表 +parseMediaRule: function(aToken, aSheet) { + // 开启媒体查询模式 + this.mScanner.mMediaQueryMode = true; + // 计算当前行数 + var currentLine = CountLF(this.mScanner.getAlreadyScanned()); + // 获取当前 token 的值 + var s = aToken.value; + // 标记规则是否有效 + var valid = false; + // 创建一个新的媒体规则对象 + var mediaRule = new jscsspMediaRule(); + // 设置媒体规则的当前行数 + mediaRule.currentLine = currentLine; + // 保存当前状态 + this.preserveState(); + // 获取下一个 token + var token = this.getToken(true, true); + // 标记是否找到媒体类型 + var foundMedia = false; + // 循环处理 token + while (token.isNotNull()) { + if (token.isIdent()) { + // 找到媒体类型 + foundMedia = true; + // 拼接媒体类型到字符串 s 中 + s += " " + token.value; + // 将媒体类型添加到媒体规则的媒体列表中 + mediaRule.media.push(token.value); + // 获取下一个 token + token = this.getToken(true, true); + if (token.isSymbol(",")) { + // 如果是逗号,拼接逗号到字符串 s 中 + s += ","; + } else { + if (token.isSymbol("{")) + // 如果是左花括号,将 token 放回队列 + this.ungetToken(); + else { + // 错误处理,将 token 类型设为 NULL_TYPE + token.type = jscsspToken.NULL_TYPE; + break; + } + } + } + else if (token.isSymbol("{")) + // 如果是左花括号,跳出循环 + break; + else if (foundMedia) { + // 如果已经找到媒体类型,但当前 token 不符合要求,将 token 类型设为 NULL_TYPE + token.type = jscsspToken.NULL_TYPE; + // 不是有效的媒体列表,跳出循环 + break; + } + // 获取下一个 token + token = this.getToken(true, true); + } + if (token.isSymbol("{") && mediaRule.media.length) { + // 如果是左花括号且媒体列表不为空,开始解析样式规则 + s += " { "; + // 获取下一个 token + token = this.getToken(true, false); + while (token.isNotNull()) { + if (token.isComment() && this.mPreserveComments) { + // 如果是注释且需要保留注释,拼接注释到字符串 s 中 + s += " " + token.value; + // 创建一个新的注释对象 + var comment = new jscsspComment(); + // 设置注释对象的解析后的 CSS 文本 + comment.parsedCssText = token.value; + // 将注释对象添加到媒体规则的 CSS 规则列表中 + mediaRule.cssRules.push(comment); + } else if (token.isSymbol("}")) { + // 如果是右花括号,标记规则有效 + valid = true; + break; + } else { + // 解析样式规则 + var r = this.parseStyleRule(token, mediaRule, true); + if (r) + // 如果解析成功,拼接解析结果到字符串 s 中 + s += r; + } + // 获取下一个 token + token = this.getToken(true, false); + } + } + if (valid) { + // 如果规则有效,忘记保存的状态 + this.forgetState(); + // 设置媒体规则的解析后的 CSS 文本 + mediaRule.parsedCssText = s; + // 将媒体规则添加到样式表的 CSS 规则列表中 + aSheet.cssRules.push(mediaRule); + return true; + } + // 恢复保存的状态 + this.restoreState(); + return false; +}, + +// 去除字符串首尾空格的函数 +// str: 要处理的字符串 +trim11: function(str) { + // 去除字符串开头的空格 + str = str.replace(/^\s+/, ''); + // 从字符串末尾开始遍历 + for (var i = str.length - 1; i >= 0; i--) { + if (/\S/.test( str.charAt(i) )) { + // 如果当前字符不是空格,截取字符串 + str = str.substring(0, i + 1); + break; + } + } + return str; +}, + +// 解析样式规则的函数 +// aToken: 当前的 token +// aOwner: 规则的所有者 +// aIsInsideMediaRule: 是否在媒体规则内部 +parseStyleRule: function(aToken, aOwner, aIsInsideMediaRule) +{ + // 计算当前行数 + var currentLine = CountLF(this.mScanner.getAlreadyScanned()); + // 保存当前状态 + this.preserveState(); + // 解析选择器 + var selector = this.parseSelector(aToken, false); + // 标记规则是否有效 + var valid = false; + // 声明列表 + var declarations = []; + if (selector) { + // 去除选择器首尾空格 + selector = this.trim11(selector.selector); + // 选择器字符串 + var s = selector; + // 获取下一个 token + var token = this.getToken(true, true); + if (token.isSymbol("{")) { + // 如果是左花括号,拼接左花括号到字符串 s 中 + s += " { "; + // 获取下一个 token + var token = this.getToken(true, false); + while (true) { + if (!token.isNotNull()) { + // 如果 token 为空,标记规则有效 + valid = true; + break; + } + if (token.isSymbol("}")) { + // 如果是右花括号,拼接右花括号到字符串 s 中,标记规则有效 + s += "}"; + valid = true; + break; + } else { + // 解析声明 + var d = this.parseDeclaration(token, declarations, true, true, aOwner); + s += ((d && declarations.length) ? " " : "") + d; + } + // 获取下一个 token + token = this.getToken(true, false); + } + } + } + else { + // 选择器无效,整个规则无效 + } + + if (valid) { + // 如果规则有效,创建一个新的样式规则对象 + var rule = new jscsspStyleRule(); + // 设置样式规则的当前行数 + rule.currentLine = currentLine; + // 设置样式规则的解析后的 CSS 文本 + rule.parsedCssText = s; + // 设置样式规则的声明列表 + rule.declarations = declarations; + // 设置样式规则的选择器文本 + rule.mSelectorText = selector; + if (aIsInsideMediaRule) + // 如果在媒体规则内部,设置样式规则的父规则 + rule.parentRule = aOwner; + else + // 否则,设置样式规则的父样式表 + rule.parentStyleSheet = aOwner; + // 将样式规则添加到所有者的 CSS 规则列表中 + aOwner.cssRules.push(rule); + return s; + } + // 恢复保存的状态 + this.restoreState(); + // 获取当前 token 的值 + s = this.currentToken().value; + // 添加未知的 @ 规则 + this.addUnknownAtRule(aOwner, s); + return ""; +}, + +// 解析选择器的函数 +// aToken: 当前的 token +// aParseSelectorOnly: 是否只解析选择器 +parseSelector: function(aToken, aParseSelectorOnly) { + // 选择器字符串 + var s = ""; + // 选择器的优先级 + var specificity = {a: 0, b: 0, c: 0, d: 0}; + // 标记是否是选择器链的第一个元素 + var isFirstInChain = true; + // 当前 token + var token = aToken; + // 标记选择器是否有效 + var valid = false; + // 标记是否找到组合器 + var combinatorFound = false; + while (true) { + if (!token.isNotNull()) { + if (aParseSelectorOnly) + // 如果只解析选择器,返回选择器和优先级 + return {selector: s, specificity: specificity }; + return ""; + } + + if (!aParseSelectorOnly && token.isSymbol("{")) { + // 如果不是只解析选择器且遇到左花括号,结束选择器解析 + valid = !combinatorFound; + if (valid) this.ungetToken(); + break; + } + + if (token.isSymbol(",")) { + // 如果是逗号,拼接逗号到字符串 s 中 + s += token.value; + // 标记是选择器链的第一个元素 + isFirstInChain = true; + // 标记未找到组合器 + combinatorFound = false; + // 获取下一个 token + token = this.getToken(false, true); + continue; + } + // 处理组合器和分组 + else if (!combinatorFound + && (token.isWhiteSpace() + || token.isSymbol(">") + || token.isSymbol("+") + || token.isSymbol("~"))) { + if (token.isWhiteSpace()) { + // 如果是空格,拼接空格到字符串 s 中 + s += " "; + // 查看下一个 token + var nextToken = this.lookAhead(true, true); + if (!nextToken.isNotNull()) { + if (aParseSelectorOnly) + // 如果只解析选择器,返回选择器和优先级 + return {selector: s, specificity: specificity }; + return ""; + } + if (nextToken.isSymbol(">") + || nextToken.isSymbol("+") + || nextToken.isSymbol("~")) { + // 如果下一个 token 是组合器,获取下一个 token 并拼接 + token = this.getToken(true, true); + s += token.value + " "; + // 标记找到组合器 + combinatorFound = true; + } + } + else { + // 如果不是空格,拼接组合器到字符串 s 中 + s += token.value; + // 标记找到组合器 + combinatorFound = true; + } + // 标记是选择器链的第一个元素 + isFirstInChain = true; + // 获取下一个 token + token = this.getToken(true, true); + continue; + } + else { + // 解析简单选择器 + var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, true); + if (!simpleSelector) + // 如果解析失败,跳出循环 + break; + // 拼接简单选择器到字符串 s 中 + s += simpleSelector.selector; + // 更新选择器的优先级 + specificity.b += simpleSelector.specificity.b; + specificity.c += simpleSelector.specificity.c; + specificity.d += simpleSelector.specificity.d; + // 标记不是选择器链的第一个元素 + isFirstInChain = false; + // 标记未找到组合器 + combinatorFound = false; + } + + // 获取下一个 token + token = this.getToken(false, true); + } + + if (valid) { + // 如果选择器有效,返回选择器和优先级 + return {selector: s, specificity: specificity }; + } + return ""; +}, + +// 判断是否为伪元素的函数 +// aIdent: 要判断的标识符 +isPseudoElement: function(aIdent) +{ + switch (aIdent) { + case "first-letter": + case "first-line": + case "before": + case "after": + case "marker": + return true; + break; + default: return false; + break; + } +}, + +// 解析简单选择器的函数 +// token: 当前的 token +// isFirstInChain: 是否是选择器链的第一个元素 +// canNegate: 是否可以使用否定伪类 +parseSimpleSelector: function(token, isFirstInChain, canNegate) +{ + // 简单选择器字符串 + var s = ""; + // 简单选择器的优先级 + var specificity = {a: 0, b: 0, c: 0, d: 0}; + + if (isFirstInChain + && (token.isSymbol("*") || token.isSymbol("|") || token.isIdent())) { + // 如果是选择器链的第一个元素,处理类型或通用选择器 + if (token.isSymbol("*") || token.isIdent()) { + // 可能是前缀或通用选择器 + s += token.value; + // 标记是否为标识符 + var isIdent = token.isIdent(); + // 获取下一个 token + token = this.getToken(false, true); + if (token.isSymbol("|")) { + // 如果是竖线,拼接竖线到字符串 s 中 + s += token.value; + // 获取下一个 token + token = this.getToken(false, true); + if (token.isIdent() || token.isSymbol("*")) { + // 如果是标识符或星号,拼接标识符或星号到字符串 s 中 + s += token.value; + if (token.isIdent()) + // 如果是标识符,更新优先级 + specificity.d++; + } else + // 错误处理,返回 null + return null; + } else { + // 将 token 放回队列 + this.ungetToken(); + if (isIdent) + // 如果是标识符,更新优先级 + specificity.d++; + } + } else if (token.isSymbol("|")) { + // 如果是竖线,拼接竖线到字符串 s 中 + s += token.value; + // 获取下一个 token + token = this.getToken(false, true); + if (token.isIdent() || token.isSymbol("*")) { + // 如果是标识符或星号,拼接标识符或星号到字符串 s 中 + s += token.value; + if (token.isIdent()) + // 如果是标识符,更新优先级 + specificity.d++; + } else + // 错误处理,返回 null + return null; + } + } + + else if (token.isSymbol(".") || token.isSymbol("#")) { + // 如果是点号或井号,处理类选择器或 ID 选择器 + var isClass = token.isSymbol("."); + // 拼接点号或井号到字符串 s 中 + s += token.value; + // 获取下一个 token + token = this.getToken(false, true); + if (token.isIdent()) { + // 如果是标识符,拼接标识符到字符串 s 中 + s += token.value; + if (isClass) + // 如果是类选择器,更新优先级 + specificity.c++; + else + // 如果是 ID 选择器,更新优先级 + specificity.b++; + } + else + // 错误处理,返回 null + return null; + } + + else if (token.isSymbol(":")) { + // 如果是冒号,处理伪类或伪元素 + s += token.value; + // 获取下一个 token + token = this.getToken(false, true); + if (token.isSymbol(":")) { + // 如果是双冒号,拼接双冒号到字符串 s 中 + s += token.value; + // 获取下一个 token + token = this.getToken(false, true); + } + if (token.isIdent()) { + // 如果是标识符,拼接标识符到字符串 s 中 + s += token.value; + if (this.isPseudoElement(token.value)) + // 如果是伪元素,更新优先级 + specificity.d++; + else + // 如果是伪类,更新优先级 + specificity.c++; + } + else if (token.isFunction()) { + // 如果是函数,拼接函数到字符串 s 中 + s += token.value; + if (token.isFunction(":not(")) { + // 如果是 :not() 函数 + if (!canNegate) + // 如果不允许使用否定伪类,返回 null + return null; + // 获取下一个 token + token = this.getToken(true, true); + // 解析简单选择器 + var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, false); + if (!simpleSelector) + // 如果解析失败,返回 null + return null; + else { + // 拼接简单选择器到字符串 s 中 + s += simpleSelector.selector; + // 获取下一个 token + token = this.getToken(true, true); + if (token.isSymbol(")")) + // 如果是右括号,拼接右括号到字符串 s 中 + s += ")"; + else + // 错误处理,返回 null + return null; + } + // 更新优先级 + specificity.c++; + } + else { + while (true) { + // 处理函数参数 + token = this.getToken(false, true); + if (token.isSymbol(")")) { + // 如果是右括号,拼接右括号到字符串 s 中 + s += ")"; + break; + } else + // 拼接参数到字符串 s 中 + s += token.value; + } + // 更新优先级 + specificity.c++; + } + } else + // 错误处理,返回 null + return null; + + } else if (token.isSymbol("[")) { + // 如果是左方括号,处理属性选择器 + s += "["; + // 获取下一个 token + token = this.getToken(true, true); + if (token.isIdent() || token.isSymbol("*")) { + // 如果是标识符或星号,拼接标识符或星号到字符串 s 中 + s += token.value; + // 获取下一个 token + var nextToken = this.getToken(true, true); + if (token.isSymbol("|")) { + // 如果是竖线,拼接竖线到字符串 s 中 + s += "|"; + // 获取下一个 token + token = this.getToken(true, true); + if (token.isIdent()) + // 如果是标识符,拼接标识符到字符串 s 中 + s += token.value; + else + // 错误处理,返回 null + return null; + } else + // 将 token 放回队列 + this.ungetToken(); + } else if (token.isSymbol("|")) { + // 如果是竖线,拼接竖线到字符串 s 中 + s += "|"; + // 获取下一个 token + token = this.getToken(true, true); + if (token.isIdent()) + // 如果是标识符,拼接标识符到字符串 s 中 + s += token.value; + else + // 错误处理,返回 null + return null; + } + else + // 错误处理,返回 null + return null; + + // 处理属性选择器的操作符 + token = this.getToken(true, true); + if (token.isIncludes() + || token.isDashmatch() + || token.isBeginsmatch() + || token.isEndsmatch() + || token.isContainsmatch() + || token.isSymbol("=")) { + // 如果是操作符,拼接操作符到字符串 s 中 + s += token.value; + // 获取下一个 token + token = this.getToken(true, true); + if (token.isString() || token.isIdent()) { + // 如果是字符串或标识符,拼接字符串或标识符到字符串 s 中 + s += token.value; + // 获取下一个 token + token = this.getToken(true, true); + } + else + // 错误处理,返回 null + return null; + + if (token.isSymbol("]")) { + // 如果是右方括号,拼接右方括号到字符串 s 中 + s += token.value; + // 更新优先级 + specificity.c++; + } + else + // 错误处理,返回 null + return null; + } + else if (token.isSymbol("]")) { + // 如果是右方括号,拼接右方括号到字符串 s 中 + s += token.value; + // 更新优先级 + specificity.c++; + } + else + // 错误处理,返回 null + return null; + + } + else if (token.isWhiteSpace()) { + // 如果是空格,查看下一个 token + var t = this.lookAhead(true, true); + if (t.isSymbol('{')) + // 如果下一个 token 是左花括号,返回空字符串 + return "" + } + if (s) + // 如果简单选择器字符串不为空,返回简单选择器和优先级 + return {selector: s, specificity: specificity }; + return null; +}, + +// 保存当前状态的函数 +preserveState: function() { + // 将当前 token 保存到保存的 token 列表中 + this.mPreservedTokens.push(this.currentToken()); + // 保存扫描器的状态 + this.mScanner.preserveState(); +}, + +// 恢复保存状态的函数 +restoreState: function() { + if (this.mPreservedTokens.length) { + // 如果保存的 token 列表不为空,恢复扫描器的状态 + this.mScanner.restoreState(); + // 从保存的 token 列表中取出最后一个 token + this.mToken = this.mPreservedTokens.pop(); + } +}, + +// 忘记保存状态的函数 +forgetState: function() { + if (this.mPreservedTokens.length) { + // 如果保存的 token 列表不为空,忘记扫描器的状态 + this.mScanner.forgetState(); + // 从保存的 token 列表中取出最后一个 token + this.mPreservedTokens.pop(); + } +}, + +// 解析 CSS 字符串的函数 +// aString: 要解析的 CSS 字符串 +// aTryToPreserveWhitespaces: 是否尝试保留空格 +// aTryToPreserveComments: 是否尝试保留注释 +parse: function(aString, aTryToPreserveWhitespaces, aTryToPreserveComments) { + if (!aString) + // 如果字符串为空,返回 null + return null; + + // 设置是否保留空格 + this.mPreserveWS = aTryToPreserveWhitespaces; + // 设置是否保留注释 + this.mPreserveComments = aTryToPreserveComments; + // 初始化保存的 token 列表 + this.mPreservedTokens = []; + // 初始化扫描器 + this.mScanner.init(aString); + // 创建一个新的样式表对象 + var sheet = new jscsspStylesheet(); + + // @charset 规则只能出现在样式表的开头 + var token = this.getToken(false, false); + if (!token.isNotNull()) + return; + if (token.isAtRule("@charset")) { + // 解析 @charset 规则 + this.parseCharsetRule(token, sheet); + // 获取下一个 token + token = this.getToken(false, false); + } + + // 标记是否找到样式规则 + var foundStyleRules = false; + // 标记是否找到 @import 规则 + var foundImportRules = false; + // 标记是否找到 @namespace 规则 + var foundNameSpaceRules = false; + while (true) { + if (!token.isNotNull()) + // 如果 token 为空,跳出循环 + break; + if (token.isWhiteSpace()) + { + if (aTryToPreserveWhitespaces) + // 如果需要保留空格,添加空格到样式表中 + this.addWhitespace(sheet, token.value); + } + + else if (token.isComment()) + { + if (this.mPreserveComments) + // 如果需要保留注释,添加注释到样式表中 + this.addComment(sheet, token.value); + } + + else if (token.isAtRule()) { + if (token.isAtRule("@variables")) { + // 如果是 @variables 规则 + if (!foundImportRules && !foundStyleRules) + // 如果还没有找到 @import 规则和样式规则,解析 @variables 规则 + this.parseVariablesRule(token, sheet); + else { + // 错误处理,报告错误并添加未知的 @ 规则 + this.reportError(kVARIABLES_RULE_POSITION); + this.addUnknownAtRule(sheet, token.value); + } + } + else if (token.isAtRule("@import")) { + // 如果是 @import 规则 + // @import 规则必须出现在所有样式规则和 @namespace 规则之前 + if (!foundStyleRules && !foundNameSpaceRules) + // 如果还没有找到样式规则和 @namespace 规则,解析 @import 规则 + foundImportRules = this.parseImportRule(token, sheet); + else { + // 错误处理,报告错误并添加未知的 @ 规则 + this.reportError(kIMPORT_RULE_POSITION); + this.addUnknownAtRule(sheet, token.value); + } + } + else if (token.isAtRule("@namespace")) { + // 如果是 @namespace 规则 + // @namespace 规则必须出现在所有样式规则之后,所有 @import 规则之前 + if (!foundStyleRules) + // 如果还没有找到样式规则,解析 @namespace 规则 + foundNameSpaceRules = this.parseNamespaceRule(token, sheet); + else { + // 错误处理,报告错误并添加未知的 @ 规则 + this.reportError(kNAMESPACE_RULE_POSITION); + this.addUnknownAtRule(sheet, token.value); + } + } + else if (token.isAtRule("@font-face")) { + // 如果是 @font-face 规则 + if (this.parseFontFaceRule(token, sheet)) + // 如果解析成功,标记找到样式规则 + foundStyleRules = true; + else + // 解析失败,添加未知的 @ 规则 + this.addUnknownAtRule(sheet, token.value); + } + else if (token.isAtRule("@page")) { + // 如果是 @page 规则 + if (this.parsePageRule(token, sheet)) + // 如果解析成功,标记找到样式规则 + foundStyleRules = true; + else + // 解析失败,添加未知的 @ 规则 + this.addUnknownAtRule(sheet, token.value); + } + else if (token.isAtRule("@media")) { + // 如果是 @media 规则 + if (this.parseMediaRule(token, sheet)) + // 如果解析成功,标记找到样式规则 + foundStyleRules = true; + else + // 解析失败,添加未知的 @ 规则 + this.addUnknownAtRule(sheet, token.value); + } + else if (token.isAtRule("@keyframes")) { + // 如果是 @keyframes 规则 + if (!this.parseKeyframesRule(token, sheet)) + // 如果解析失败,添加未知的 @ 规则 + this.addUnknownAtRule(sheet, token.value); + } + else if (token.isAtRule("@charset")) { + // 如果是 @charset 规则出现在非开头位置,报告错误并添加未知的 @ 规则 + this.reportError(kCHARSET_RULE_CHARSET_SOF); + this.addUnknownAtRule(sheet, token.value); + } + else { + // 未知的 @ 规则,报告错误并添加未知的 @ 规则 + this.reportError(kUNKNOWN_AT_RULE); + this.addUnknownAtRule(sheet, token.value); + } + } + + else // 普通样式规则 + { + // 解析样式规则 + var ruleText = this.parseStyleRule(token, sheet, false); + if (ruleText) + // 如果解析成功,标记找到样式规则 + foundStyleRules = true; + } + // 获取下一个 token + token = this.getToken(false); + } + + return sheet; +} + +}; + +// jscsspToken 构造函数 +// aType: token 的类型 +// aValue: token 的值 +// aUnit: token 的单位 +function jscsspToken(aType, aValue, aUnit) +{ + // 设置 token 的类型 + this.type = aType; + // 设置 token 的值 + this.value = aValue; + // 设置 token 的单位 + this.unit = aUnit; +} + +// 定义 token 的类型 +jscsspToken.NULL_TYPE = 0; + +jscsspToken.WHITESPACE_TYPE = 1; +jscsspToken.STRING_TYPE = 2; +jscsspToken.COMMENT_TYPE = 3; +jscsspToken.NUMBER_TYPE = 4; +jscsspToken.IDENT_TYPE = 5; +jscsspToken.FUNCTION_TYPE = 6; +jscsspToken.ATRULE_TYPE = 7; +jscsspToken.INCLUDES_TYPE = 8; +jscsspToken.DASHMATCH_TYPE = 9; +jscsspToken.BEGINSMATCH_TYPE = 10; +jscsspToken.ENDSMATCH_TYPE = 11; +jscsspToken.CONTAINSMATCH_TYPE = 12; +jscsspToken.SYMBOL_TYPE = 13; +jscsspToken.DIMENSION_TYPE = 14; +jscsspToken.PERCENTAGE_TYPE = 15; +jscsspToken.HEX_TYPE = 16; + +// jscsspToken 原型对象 +jscsspToken.prototype = { + + // 判断 token 是否不为空的函数 + isNotNull: function () + { + return this.type; + }, + + // 判断 token 是否为指定类型和值的函数 + _isOfType: function (aType, aValue) + { + return (this.type == aType && (!aValue || this.value.toLowerCase() == aValue)); + }, + + // 判断 token 是否为空格的函数 + isWhiteSpace: function(w) + { + return this._isOfType(jscsspToken.WHITESPACE_TYPE, w); + }, + + // 判断 token 是否为字符串的函数 + isString: function() + { + return this._isOfType(jscsspToken.STRING_TYPE); + }, + + // 判断 token 是否为注释的函数 + isComment: function() + { + return this._isOfType(jscsspToken.COMMENT_TYPE); + }, + + // 判断 token 是否为数字的函数 + isNumber: function(n) + { + return this._isOfType(jscsspToken.NUMBER_TYPE, n); + }, + + // 判断 token 是否为符号的函数 + isSymbol: function(c) + { + return this._isOfType(jscsspToken.SYMBOL_TYPE, c); + }, + + // 判断 token 是否为标识符的函数 + isIdent: function(i) + { + return this._isOfType(jscsspToken.IDENT_TYPE, i); + }, + + // 判断 token 是否为函数的函数 + isFunction: function(f) + { + return this._isOfType(jscsspToken.FUNCTION_TYPE, f); + }, + + // 判断 token 是否为 @ 规则的函数 + isAtRule: function(a) + { + return this._isOfType(jscsspToken.ATRULE_TYPE, a); + }, + + // 判断 token 是否为包含操作符的函数 + isIncludes: function() + { + return this._isOfType(jscsspToken.INCLUDES_TYPE); + }, + + // 判断 token 是否为连字符匹配操作符的函数 + isDashmatch: function() + { + return this._isOfType(jscsspToken.DASHMATCH_TYPE); + }, + + // 判断 token 是否为开头匹配操作符的函数 + isBeginsmatch: function() + { + return this._isOfType(jscsspToken.BEGINSMATCH_TYPE); + }, + + // 判断 token 是否为结尾匹配操作符的函数 + isEndsmatch: function() + { + return this._isOfType(jscsspToken.ENDSMATCH_TYPE); + }, + + // 判断 token 是否为包含匹配操作符的函数 + isContainsmatch: function() + { + return this._isOfType(jscsspToken.CONTAINSMATCH_TYPE); + }, + + // 判断 token 是否为符号的函数 + isSymbol: function(c) + { + return this._isOfType(jscsspToken.SYMBOL_TYPE, c); + }, + + // 判断 token 是否为维度的函数 + isDimension: function() + { + return this._isOfType(jscsspToken.DIMENSION_TYPE); + }, + + // 判断 token 是否为百分比的函数 + isPercentage: function() + { + return this._isOfType(jscsspToken.PERCENTAGE_TYPE); + }, + + // 判断 token 是否为十六进制的函数 + isHex: function() + { + return this._isOfType(jscsspToken.HEX_TYPE); + }, + + // 判断 token 是否为指定单位的维度的函数 + isDimensionOfUnit: function(aUnit) + { + return (this.isDimension() && this.unit == aUnit); + }, + + // 判断 token 是否为长度的函数 + isLength: function() + { + return (this.isPercentage() || + this.isDimensionOfUnit("cm") || + this.isDimensionOfUnit("mm") || + this.isDimensionOfUnit("in") || + this.isDimensionOfUnit("pc") || + this.isDimensionOfUnit("px") || + this.isDimensionOfUnit("em") || + this.isDimensionOfUnit("ex") || + this.isDimensionOfUnit("pt")); + }, + + // 判断 token 是否为角度的函数 + isAngle: function() + { + return (this.isDimensionOfUnit("deg") || + this.isDimensionOfUnit("rad") || + this.isDimensionOfUnit("grad")); + } +} + +// 定义规则类型常量 +var kJscsspUNKNOWN_RULE = 0; +var kJscsspSTYLE_RULE = 1 +var kJscsspCHARSET_RULE = 2; +var kJscsspIMPORT_RULE = 3; +var kJscsspMEDIA_RULE = 4; +var kJscsspFONT_FACE_RULE = 5; +var kJscsspPAGE_RULE = 6; + +var kJscsspKEYFRAMES_RULE = 7; +var kJscsspKEYFRAME_RULE = 8; + +var kJscsspNAMESPACE_RULE = 100; +var kJscsspCOMMENT = 101; +var kJscsspWHITE_SPACE \ No newline at end of file