You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

inline-css.js 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. const parseCSS = require('css-rules');
  2. const cheerio = require('cheerio');
  3. const pseudoCheck = require('./pseudoCheck');
  4. const handleRule = require('./handleRule');
  5. const flatten = require('flat-util');
  6. const setStyleAttrs = require('./setStyleAttrs');
  7. const setWidthAttrs = require('./setWidthAttrs');
  8. const removeClassId = require('./removeClassId');
  9. const setTableAttrs = require('./setTableAttrs');
  10. const pick = require('pick-util');
  11. function replaceCodeBlock(html, re, block) {
  12. return html.replace(re, () => block);
  13. }
  14. module.exports = (html, css, options) => {
  15. const opts = options || {};
  16. let rules;
  17. let editedElements = [];
  18. const codeBlockLookup = [];
  19. const encodeCodeBlocks = _html => {
  20. let __html = _html;
  21. const blocks = opts.codeBlocks;
  22. Object.keys(blocks).forEach(key => {
  23. const re = new RegExp(`${blocks[key].start}([\\S\\s]*?)${blocks[key].end}`, 'g');
  24. __html = __html.replace(re, match => {
  25. codeBlockLookup.push(match);
  26. return `EXCS_CODE_BLOCK_${codeBlockLookup.length - 1}_`;
  27. });
  28. });
  29. return __html;
  30. };
  31. const decodeCodeBlocks = _html => {
  32. let index;
  33. let re;
  34. let __html = _html;
  35. for (index = 0; index < codeBlockLookup.length; index++) {
  36. re = new RegExp(`EXCS_CODE_BLOCK_${index}_(="")?`, 'gi');
  37. __html = replaceCodeBlock(__html, re, codeBlockLookup[index]);
  38. }
  39. return __html;
  40. };
  41. const encodeEntities = _html => encodeCodeBlocks(_html);
  42. const decodeEntities = _html => decodeCodeBlocks(_html);
  43. let $;
  44. $ = cheerio.load(encodeEntities(html), pick(opts, [
  45. 'xmlMode',
  46. 'decodeEntities',
  47. 'lowerCaseTags',
  48. 'lowerCaseAttributeNames',
  49. 'recognizeCDATA',
  50. 'recognizeSelfClosing'
  51. ]));
  52. try {
  53. rules = parseCSS(css);
  54. } catch (err) {
  55. throw new Error(err);
  56. }
  57. rules.forEach(rule => {
  58. let el;
  59. let ignoredPseudos;
  60. ignoredPseudos = pseudoCheck(rule);
  61. if (ignoredPseudos) {
  62. return false;
  63. }
  64. try {
  65. el = handleRule(rule, $);
  66. editedElements.push(el);
  67. } catch (err) {
  68. // skip invalid selector
  69. return false;
  70. }
  71. });
  72. // flatten array if nested
  73. editedElements = flatten(editedElements);
  74. editedElements.forEach(el => {
  75. setStyleAttrs(el, $);
  76. if (opts.applyWidthAttributes) {
  77. setWidthAttrs(el, $);
  78. }
  79. if (opts.removeHtmlSelectors) {
  80. removeClassId(el, $);
  81. }
  82. });
  83. if (opts.applyTableAttributes) {
  84. $('table').each((index, el) => {
  85. setTableAttrs(el, $);
  86. });
  87. }
  88. return decodeEntities($.html());
  89. };