UNPKG

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