-
-
Notifications
You must be signed in to change notification settings - Fork 111
Expand file tree
/
Copy pathwire.js
More file actions
98 lines (92 loc) · 3.55 KB
/
wire.js
File metadata and controls
98 lines (92 loc) · 3.55 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
'use strict';
const {ELEMENT_NODE, SVG_NAMESPACE} = require('../shared/constants.js');
const {WeakMap, trim} = require('../shared/poorlyfills.js');
const {fragment} = require('../shared/easy-dom.js');
const {append, slice, unique} = require('../shared/utils.js');
const Wire = (m => m.__esModule ? m.default : m)(require('../classes/Wire.js'));
const render = (m => m.__esModule ? m.default : m)(require('./render.js'));
// all wires used per each context
const wires = new WeakMap;
// A wire is a callback used as tag function
// to lazily relate a generic object to a template literal.
// hyper.wire(user)`<div id=user>${user.name}</div>`; => the div#user
// This provides the ability to have a unique DOM structure
// related to a unique JS object through a reusable template literal.
// A wire can specify a type, as svg or html, and also an id
// via html:id or :id convention. Such :id allows same JS objects
// to be associated to different DOM structures accordingly with
// the used template literal without losing previously rendered parts.
const wire = (obj, type) => obj == null ?
content(type || 'html') :
weakly(obj, type || 'html');
// A wire content is a virtual reference to one or more nodes.
// It's represented by either a DOM node, or an Array.
// In both cases, the wire content role is to simply update
// all nodes through the list of related callbacks.
// In few words, a wire content is like an invisible parent node
// in charge of updating its content like a bound element would do.
const content = type => {
let wire, container, content, template, updates;
return function (statics) {
statics = unique(statics);
let setup = template !== statics;
if (setup) {
template = statics;
content = fragment(document);
container = type === 'svg' ?
document.createElementNS(SVG_NAMESPACE, 'svg') :
content;
updates = render.bind(container);
}
updates.apply(null, arguments);
if (setup) {
if (type === 'svg') {
append(content, slice.call(container.childNodes));
}
wire = wireContent(content);
}
return wire;
};
};
// wires are weakly created through objects.
// Each object can have multiple wires associated
// and this is thanks to the type + :id feature.
const weakly = (obj, type) => {
const i = type.indexOf(':');
let wire = wires.get(obj);
let id = type;
if (-1 < i) {
id = type.slice(i + 1);
type = type.slice(0, i) || 'html';
}
if (!wire) wires.set(obj, wire = {});
return wire[id] || (wire[id] = content(type));
};
// a document fragment loses its nodes as soon
// as it's appended into another node.
// This would easily lose wired content
// so that on a second render call, the parent
// node wouldn't know which node was there
// associated to the interpolation.
// To prevent hyperHTML to forget about wired nodes,
// these are either returned as Array or, if there's ony one entry,
// as single referenced node that won't disappear from the fragment.
// The initial fragment, at this point, would be used as unique reference.
const wireContent = node => {
const childNodes = node.childNodes;
const length = childNodes.length;
const wireNodes = [];
for (let i = 0; i < length; i++) {
let child = childNodes[i];
if (
child.nodeType === ELEMENT_NODE ||
trim.call(child.textContent).length !== 0
) {
wireNodes.push(child);
}
}
return wireNodes.length === 1 ? wireNodes[0] : new Wire(wireNodes);
};
exports.content = content;
exports.weakly = weakly;
Object.defineProperty(exports, '__esModule', {value: true}).default = wire;