-
-
Notifications
You must be signed in to change notification settings - Fork 111
Expand file tree
/
Copy pathrender.js
More file actions
88 lines (79 loc) · 2.87 KB
/
render.js
File metadata and controls
88 lines (79 loc) · 2.87 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
'use strict';
const {Map, WeakMap} = require('../shared/poorlyfills.js');
const {UIDC, VOID_ELEMENTS} = require('../shared/constants.js');
const Updates = (m => m.__esModule ? m.default : m)(require('../objects/Updates.js'));
const {
createFragment,
importNode,
unique
} = require('../shared/utils.js');
const {selfClosing: SC_RE} = require('../shared/re.js');
// a weak collection of contexts that
// are already known to hyperHTML
const bewitched = new WeakMap;
// the collection of all template literals
// since these are unique and immutable
// for the whole application life-cycle
const templates = new Map;
// 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 adopt = render.adopt;
const info = templates.get(template) ||
createTemplate.call(this, template);
let fragment, updates;
if (adopt) {
updates = Updates.create(this, info.paths, adopt);
} else {
fragment = importNode(this.ownerDocument, info.fragment);
updates = Updates.create(fragment, info.paths, adopt);
}
bewitched.set(this, {template, updates});
update.apply(updates, arguments);
if (!adopt) {
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_PLACE = ($0, $1, $2) => {
return VOID_ELEMENTS.test($1) ? $0 : ('<' + $1 + $2 + '></' + $1 + '>');
};
Object.defineProperty(exports, '__esModule', {value: true}).default = render;