-
Notifications
You must be signed in to change notification settings - Fork 66
Expand file tree
/
Copy pathprepareHtmlForWeb.ts
More file actions
100 lines (86 loc) · 2.35 KB
/
Copy pathprepareHtmlForWeb.ts
File metadata and controls
100 lines (86 loc) · 2.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { normalizeHtml } from './htmlNormalizer';
export function prepareHtmlForWeb(
html: string,
useHtmlNormalizer: boolean | undefined
): string {
if (useHtmlNormalizer) {
html = normalizeHtml(html);
}
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
wrapBareLiContentInParagraph(doc);
checkboxHtmlToWeb(doc);
return doc.body.innerHTML;
}
/*
* Native list format:
* <ul>
* <li>foo</li>
* <li></li>
* </ul>
*
* Web-native, with <p> wrappers to display the content correctly:
* <ul>
* <li>
* <p>foo</p>
* </li>
* <li>
* <p></p>
* </li>
* </ul>
*/
function wrapBareLiContentInParagraph(doc: Document) {
// Target only standard lists (ignore checkbox lists, as they get wrapped in <label> later)
const listItems = doc.querySelectorAll(
'ul:not([data-type="checkbox"]) > li, ol > li'
);
listItems.forEach((li) => {
if (li.firstElementChild?.tagName.toUpperCase() === 'P') return;
const nodesToWrap: Node[] = [];
const childNodes = Array.from(li.childNodes);
for (const node of childNodes) {
if (
node.nodeType === Node.ELEMENT_NODE &&
['UL', 'OL'].includes((node as Element).tagName.toUpperCase())
) {
break;
}
nodesToWrap.push(node);
}
if (nodesToWrap.length === 0 && childNodes.length > 0) return;
const p = doc.createElement('p');
li.insertBefore(p, childNodes[0] || null);
nodesToWrap.forEach((node) => p.appendChild(node));
});
}
/*
* Native checkbox format (as produced by the editor):
* <ul data-type="checkbox">
* <li checked>foo</li>
* <li>bar</li>
* </ul>
*
* Web-native, display-only format:
* <ul data-type="checkbox">
* <li>
* <input type="checkbox" checked>
* <label>foo</label>
* </li>
* <li>
* <input type="checkbox">
* <label>bar</label>
* </li>
* </ul>
*/
function checkboxHtmlToWeb(doc: Document) {
doc.querySelectorAll('ul[data-type="checkbox"]').forEach((ul) => {
ul.querySelectorAll('li').forEach((li) => {
const checked = li.hasAttribute('checked');
const labelContent = li.innerHTML;
li.removeAttribute('checked');
li.innerHTML =
`<input type="checkbox"${checked ? ' checked' : ''}>` +
`<label>${labelContent}</label>`;
});
});
}