-
-
Notifications
You must be signed in to change notification settings - Fork 111
Expand file tree
/
Copy pathrender.js
More file actions
79 lines (70 loc) · 2.54 KB
/
Copy pathrender.js
File metadata and controls
79 lines (70 loc) · 2.54 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
import {Map, WeakMap} from '../shared/poorlyfills.js';
import {G, UIDC, VOID_ELEMENTS} from '../shared/constants.js';
import Updates from '../objects/Updates.js';
import {
createFragment,
importNode,
unique,
TemplateMap
} from '../shared/utils.js';
import {selfClosing} from '../shared/re.js';
// a weak collection of contexts that
// are already known to hyperHTML
const bewitched = new WeakMap;
// all unique template literals
const templates = TemplateMap();
// better known as hyper.bind(node), the render is
// the main tag function in charge of fully upgrading
// or simply updating, contexts used as hyperHTML targets.
// The `this` context is either a regular DOM node or a fragment.
function render(template) {
const wicked = bewitched.get(this);
if (wicked && wicked.template === unique(template)) {
update.apply(wicked.updates, arguments);
} else {
upgrade.apply(this, arguments);
}
return this;
}
// an upgrade is in charge of collecting template info,
// parse it once, if unknown, to map all interpolations
// as single DOM callbacks, relate such template
// to the current context, and render it after cleaning the context up
function upgrade(template) {
template = unique(template);
const info = templates.get(template) ||
createTemplate.call(this, template);
const fragment = importNode(this.ownerDocument, info.fragment);
const updates = Updates.create(fragment, info.paths);
bewitched.set(this, {template, updates});
update.apply(updates, arguments);
this.textContent = '';
this.appendChild(fragment);
}
// an update simply loops over all mapped DOM operations
function update() {
const length = arguments.length;
for (let i = 1; i < length; i++) {
this[i - 1](arguments[i]);
}
}
// a template can be used to create a document fragment
// aware of all interpolations and with a list
// of paths used to find once those nodes that need updates,
// no matter if these are attributes, text nodes, or regular one
function createTemplate(template) {
const paths = [];
const html = template.join(UIDC).replace(SC_RE, SC_PLACE);
const fragment = createFragment(this, html);
Updates.find(fragment, paths, template.slice());
const info = {fragment, paths};
templates.set(template, info);
return info;
}
// some node could be special though, like a custom element
// with a self closing tag, which should work through these changes.
const SC_RE = selfClosing;
const SC_PLACE = ($0, $1, $2) => {
return VOID_ELEMENTS.test($1) ? $0 : ('<' + $1 + $2 + '></' + $1 + '>');
};
export default render;