CssHandler.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. //CssHandler.js
  2. // #ifdef MP-WEIXIN
  3. const CanIUse = require('./api.js').versionHigherThan('2.7.1');
  4. // #endif
  5. function CssHandler(style, tagStyle) {
  6. this._style = new CssTokenizer(style, tagStyle).parse();
  7. }
  8. CssHandler.prototype.match = function(name, attrs) {
  9. let matched = this._style[name] ? (this._style[name] + ';') : '';
  10. if (attrs.id)
  11. matched += (this._style['#' + attrs.id] ? (this._style['#' + attrs.id] + ';') : '');
  12. if (attrs.class)
  13. for (var Class of attrs.class.split(' '))
  14. matched += (this._style['.' + Class] ? (this._style['.' + Class] + ';') : '');
  15. return matched;
  16. }
  17. function CssTokenizer(style = '', tagStyle = {}) {
  18. this.res = this.initClass(tagStyle);
  19. this._state = "SPACE";
  20. this._buffer = style;
  21. this._sectionStart = 0;
  22. this._index = 0;
  23. this._name = '';
  24. this._content = '';
  25. this._list = [];
  26. this._comma = false;
  27. }
  28. CssTokenizer.prototype.initClass = function(tagStyle) {
  29. let initStyle = JSON.parse(JSON.stringify(tagStyle));
  30. initStyle.a = "display:inline;color:#366092;word-break:break-all;" + (initStyle.a || "");
  31. initStyle.address = "font-style:italic;" + (initStyle.address || "");
  32. initStyle.blockquote = initStyle.blockquote ||
  33. 'background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px;';
  34. initStyle.center = 'text-align:center;' + (initStyle.center || "");
  35. initStyle.cite = "font-style:italic;" + (initStyle.cite || "");
  36. initStyle.code = initStyle.code ||
  37. 'padding:0 1px 0 1px;margin-left:2px;margin-right:2px;background-color:#f8f8f8;border:1px solid #cccccc;border-radius:3px;';
  38. initStyle.dd = "margin-left:40px;" + (initStyle.dd || "");
  39. initStyle.img = "max-width:100%;" + (initStyle.img || "");
  40. initStyle.mark = "display:inline;background-color:yellow;" + (initStyle.mark || "");
  41. initStyle.pre = "overflow:scroll;" + (initStyle.pre || 'background-color:#f6f8fa;padding:5px;border-radius:5px;');
  42. initStyle.s = "display:inline;text-decoration:line-through;" + (initStyle.s || "");
  43. initStyle.u = "display:inline;text-decoration:underline;" + (initStyle.u || "");
  44. // #ifdef MP-WEIXIN
  45. //低版本兼容
  46. if (!CanIUse) {
  47. // #endif
  48. initStyle.big = "display:inline;font-size:1.2em;" + (initStyle.big || "");
  49. initStyle.small = "display:inline;font-size:0.8em;" + (initStyle.small || "");
  50. initStyle.pre = "font-family:monospace;white-space:pre;" + initStyle.pre;
  51. // #ifdef MP-WEIXIN
  52. }
  53. // #endif
  54. return initStyle;
  55. }
  56. CssTokenizer.prototype.SPACE = function(c) {
  57. if (/[a-zA-Z.#]/.test(c)) {
  58. this._sectionStart = this._index;
  59. this._state = "InName";
  60. } else if (c == '@') this._state = "Ignore1";
  61. else if (c == '/') this._state = "BeforeComment";
  62. };
  63. CssTokenizer.prototype.BeforeComment = function(c) {
  64. if (c == '*') this._state = "InComment";
  65. else {
  66. this._index--;
  67. this._state = "SPACE";
  68. }
  69. };
  70. CssTokenizer.prototype.InComment = function(c) {
  71. if (c == '*') this._state = "AfterComment";
  72. };
  73. CssTokenizer.prototype.AfterComment = function(c) {
  74. if (c == '/') this._state = "SPACE";
  75. else {
  76. this._index--;
  77. this._state = "InComment"
  78. }
  79. };
  80. CssTokenizer.prototype.InName = function(c) {
  81. if (c == '{') {
  82. this._list.push(this._buffer.substring(this._sectionStart, this._index))
  83. this._sectionStart = this._index + 1;
  84. this._state = "InContent";
  85. } else if (c == ',') {
  86. this._list.push(this._buffer.substring(this._sectionStart, this._index));
  87. this._sectionStart = this._index + 1;
  88. this._comma = true;
  89. } else if ((c == '.' || c == '#') && !this._comma) {
  90. this._buffer = this._buffer.splice(this._index, 1, ' ');
  91. } else if (/\s/.test(c)) {
  92. this._name = this._buffer.substring(this._sectionStart, this._index);
  93. this._state = "NameSpace";
  94. } else if (/[>:\[]/.test(c)) {
  95. if (this._list.length) this._state = "IgnoreName";
  96. else this._state = "Ignore1";
  97. } else this._comma = false;
  98. };
  99. CssTokenizer.prototype.NameSpace = function(c) {
  100. if (c == '{') {
  101. this._list.push(this._name);
  102. this._sectionStart = this._index + 1;
  103. this._state = "InContent";
  104. } else if (c == ',') {
  105. this._comma = true;
  106. this._list.push(this._name);
  107. this._sectionStart = this._index + 1;
  108. this._state = "InName"
  109. } else if (/\S/.test(c)) {
  110. if (this._comma) {
  111. this._sectionStart = this._index;
  112. this._index--;
  113. this._state = "InName";
  114. } else if (this._list.length) this._state = "IgnoreName";
  115. else this._state = "Ignore1"
  116. }
  117. };
  118. CssTokenizer.prototype.InContent = function(c) {
  119. if (c == '}') {
  120. this._content = this._buffer.substring(this._sectionStart, this._index);
  121. for (let item of this._list)
  122. this.res[item] = (this.res[item] || '') + ";" + this._content;
  123. this._list = [];
  124. this._comma = false;
  125. this._state = "SPACE";
  126. }
  127. };
  128. CssTokenizer.prototype.IgnoreName = function(c) {
  129. if (c == ',') {
  130. this._sectionStart = this._index + 1;
  131. this._state = "InName";
  132. } else if (c == '{') {
  133. this._sectionStart = this._index + 1;
  134. this._state = "InContent";
  135. }
  136. }
  137. CssTokenizer.prototype.Ignore1 = function(c) {
  138. if (c == ';') {
  139. this._state = "SPACE";
  140. this._sectionStart = this._index + 1;
  141. } else if (c == '{') this._state = "Ignore2";
  142. };
  143. CssTokenizer.prototype.Ignore2 = function(c) {
  144. if (c == '}') {
  145. this._state = "SPACE";
  146. this._sectionStart = this._index + 1;
  147. } else if (c == '{') this._state = "Ignore3";
  148. };
  149. CssTokenizer.prototype.Ignore3 = function(c) {
  150. if (c == '}') this._state = "Ignore2";
  151. };
  152. CssTokenizer.prototype.parse = function() {
  153. for (; this._index < this._buffer.length; this._index++)
  154. this[this._state](this._buffer[this._index]);
  155. return this.res;
  156. };
  157. module.exports = CssHandler;