/* 解析和匹配 Css 的选择器 github地址:https://github.com/jin-yufeng/Parser 文档地址:https://jin-yufeng.github.io/Parser author:JinYufeng */ const userAgentStyles = require("./config.js").userAgentStyles; class CssHandler { constructor(tagStyle = {}) { this.styles = Object.assign({}, tagStyle); }; getStyle(data) { var style = ''; data = data.replace(/<[sS][tT][yY][lL][eE][\s\S]*?>([\s\S]*?)<\/[sS][tT][yY][lL][eE][\s\S]*?>/g, function() { style += arguments[1]; return ''; }) this.styles = new CssParser(style, this.styles).parse(); return data; }; parseCss(css) { return new CssParser(css, {}, true).parse(); }; match(name, attrs) { var tmp, matched = ((tmp = this.styles[name]) ? (tmp + ';') : ''); if (attrs.class) { var classes = attrs.class.split(' '); for (var i = 0; i < classes.length; i++) if (tmp = this.styles['.' + classes[i]]) matched += (tmp + ';'); } if (tmp = this.styles['#' + attrs.id]) matched += tmp; return matched; }; } module.exports = CssHandler; function isBlankChar(c) { return c == ' ' || c == '\u00A0' || c == '\t' || c == '\r' || c == '\n' || c == '\f'; }; class CssParser { constructor(data, tagStyle, api) { this.data = data; this.res = tagStyle; if (!api) for (var item in userAgentStyles) { if (tagStyle[item]) tagStyle[item] = userAgentStyles[item] + ';' + tagStyle[item]; else tagStyle[item] = userAgentStyles[item]; } this._floor = 0; this._i = 0; this._list = []; this._comma = false; this._sectionStart = 0; this._state = this.Space; }; parse() { for (; this._i < this.data.length; this._i++) this._state(this.data[this._i]); return this.res; }; // 状态机 Space(c) { if (c == '.' || c == '#' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { this._sectionStart = this._i; this._state = this.StyleName; } else if (c == '/' && this.data[this._i + 1] == '*') this.Comment(); else if (!isBlankChar(c) && c != ';') this._state = this.Ignore; }; Comment() { this._i = this.data.indexOf("*/", this._i); if (this._i == -1) this._i = this.data.length; this._i++; this._state = this.Space; }; Ignore(c) { if (c == '{') this._floor++; else if (c == '}' && --this._floor <= 0) { this._list = []; this._state = this.Space; } }; StyleName(c) { if (isBlankChar(c)) { this._list.push(this.data.substring(this._sectionStart, this._i)); this._state = this.NameSpace; } else if (c == '{') { this._list.push(this.data.substring(this._sectionStart, this._i)); this._floor = 1; this._sectionStart = this._i + 1; this.Content(); } else if (c == ',') { this._list.push(this.data.substring(this._sectionStart, this._i)); this._sectionStart = this._i + 1; this._comma = true; } else if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9') && c != '.' && c != '#' && c != '-' && c != '_') this._state = this.Ignore; }; NameSpace(c) { if (c == '{') { this._floor = 1; this._sectionStart = this._i + 1; this.Content(); } else if (c == ',') { this._comma = true; this._sectionStart = this._i + 1; this._state = this.StyleName; } else if (!isBlankChar(c)) { if (this._comma) { this._state = this.StyleName; this._sectionStart = this._i; this._i--; this._comma = false; } else this._state = this.Ignore; } }; Content() { this._i = this.data.indexOf('}', this._i); if (this._i == -1) this._i = this.data.length; // 去除空白符 var flag = false, pos, content = this.data.substring(this._sectionStart, this._i); for (var i = 0; i < content.length; i++) { if (isBlankChar(content[i])) { if (!flag) { pos = i; flag = true; } } else { if (flag) { if (pos == 0) content = content.substring(i); else if (i - pos > 1) content = content.substring(0, pos) + (content[pos - 1] == ';' ? (pos--, '') : ' ') + content.substring(i); i = pos; flag = false; } } } if (flag) content = content.substring(0, pos); for (var i = 0; i < this._list.length; i++) this.res[this._list[i]] = (this.res[this._list[i]] || '') + content; this._list = []; this._state = this.Space; } }