1 | 'use strict';
|
2 |
|
3 | var 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 |
|
14 | function replaceCodeBlock(html, re, block) {
|
15 | return html.replace(re, function () {
|
16 | return block;
|
17 | });
|
18 | }
|
19 |
|
20 | module.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 |
|
88 | return false;
|
89 | }
|
90 | });
|
91 |
|
92 |
|
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 | };
|