1 |
|
2 | const ELEMENT_NODE = 1;
|
3 | const types = {
|
4 | ELEMENT_NODE,
|
5 | ATTRIBUTE_NODE: 2,
|
6 | TEXT_NODE: 3,
|
7 | COMMENT_NODE: 8,
|
8 | DOCUMENT_NODE: 9,
|
9 | DOCUMENT_TYPE_NODE: 10,
|
10 | DOCUMENT_FRAGMENT_NODE: 11
|
11 | };
|
12 |
|
13 |
|
14 | const VOID_ELEMENT = /^area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr$/i;
|
15 | const VOID_ELEMENTS = new RegExp(`<(${VOID_ELEMENT.source})([^>]*?)>`, 'gi');
|
16 | const VOID_SANITIZER = (_, $1, $2) => `<${$1}${$2}${/\/$/.test($2) ? '' : ' /'}>`;
|
17 |
|
18 |
|
19 | const connect = (parentNode, child) => {
|
20 | if (
|
21 | child.nodeType === ELEMENT_NODE &&
|
22 | child.isCustomElement && 'connectedCallback' in child &&
|
23 | parentNode && parentNode.nodeType !== types.DOCUMENT_FRAGMENT_NODE
|
24 | ) {
|
25 | child.connectedCallback();
|
26 | }
|
27 | };
|
28 |
|
29 | const disconnect = (parentNode, child) => {
|
30 | if (
|
31 | child.nodeType === ELEMENT_NODE &&
|
32 | child.isCustomElement && 'disconnectedCallback' in child &&
|
33 | parentNode && parentNode.nodeType !== types.DOCUMENT_FRAGMENT_NODE
|
34 | ) {
|
35 | child.disconnectedCallback();
|
36 | }
|
37 | };
|
38 |
|
39 | const notifyAttributeChanged = (el, name, oldValue, newValue) => {
|
40 | if (
|
41 | el.isCustomElement &&
|
42 | 'attributeChangedCallback' in el &&
|
43 | (el.constructor.observedAttributes || []).includes(name)
|
44 | ) {
|
45 | el.attributeChangedCallback(name, oldValue, newValue);
|
46 | }
|
47 | };
|
48 |
|
49 | const CSS_SPLITTER = /\s*,\s*/;
|
50 | function findBySelector(css) {
|
51 | switch (css[0]) {
|
52 | case '#':
|
53 | return this.ownerDocument.getElementById(css.slice(1));
|
54 | case '.':
|
55 | return this.getElementsByClassName(css.slice(1));
|
56 | case '[':
|
57 | return findBAttributeName(this, css.replace(/[\[\]]/g, ''), []);
|
58 | default:
|
59 | return this.getElementsByTagName(css);
|
60 | }
|
61 | }
|
62 |
|
63 | module.exports = {
|
64 | VOID_ELEMENT,
|
65 | connect,
|
66 | disconnect,
|
67 | notifyAttributeChanged,
|
68 | types,
|
69 | querySelectorAll(css) {
|
70 | return [].concat(...('' + css).split(CSS_SPLITTER).map(findBySelector, this));
|
71 | },
|
72 | voidSanitizer: html => html.replace(VOID_ELEMENTS, VOID_SANITIZER)
|
73 | };
|
74 |
|
75 | function findBAttributeName(node, name, all) {
|
76 | for (let children = node.children, {length} = children, i = 0; i < length; i++) {
|
77 | const child = children[i];
|
78 | if (child.hasAttribute(name))
|
79 | all.push(child);
|
80 | findBAttributeName(child, name, all);
|
81 | }
|
82 | return all;
|
83 | }
|