git ssb

1+

Matt McKegg / mutant



Tree: 4ae9282d39a3f4b2b43760e4c33d0408c400aa04

Files: 4ae9282d39a3f4b2b43760e4c33d0408c400aa04 / html-element.js

3793 bytesRaw
1var applyProperties = require('./lib/apply-properties')
2var isObservable = require('./is-observable')
3var parseTag = require('./lib/parse-tag')
4var caches = new global.WeakMap()
5
6module.exports = function (tag, attributes, children) {
7 return Element(global.document, null, tag, attributes, children)
8}
9
10module.exports.forDocument = function (document, namespace) {
11 return Element.bind(this, document, namespace)
12}
13
14module.exports.destroy = function (node) {
15 var data = caches.get(node)
16 if (data) {
17 Array.from(data.releases.values()).forEach(tryInvoke)
18 caches.delete(node)
19 }
20 applyProperties.destroy(node)
21}
22
23function Element (document, namespace, tagName, properties, children) {
24 if (!children && (Array.isArray(properties) || isText(properties))) {
25 children = properties
26 properties = null
27 }
28
29 properties = properties || {}
30
31 var tag = parseTag(tagName, properties, namespace)
32 var node = namespace
33 ? document.createElementNS(namespace, tag.tagName)
34 : document.createElement(tag.tagName)
35
36 if (!namespace) {
37 if (tag.id) {
38 node.id = tag.id
39 }
40 if (tag.classes && tag.classes.length) {
41 node.className = tag.classes.join(' ')
42 }
43 }
44
45 var data = {
46 targets: new Map(),
47 releases: new Map()
48 }
49
50 caches.set(node, data)
51 applyProperties(node, properties, namespace)
52 if (children != null) {
53 appendChild(document, node, data, children)
54 }
55
56 return node
57}
58
59function appendChild (document, target, data, node) {
60 if (Array.isArray(node)) {
61 node.forEach(function (child) {
62 appendChild(document, target, data, child)
63 })
64 } else if (isObservable(node)) {
65 var nodes = getNodes(document, resolve(node))
66 nodes.forEach(append, target)
67 data.targets.set(node, nodes)
68 data.releases.set(node, bind(document, node, data))
69 } else {
70 target.appendChild(getNode(document, node))
71 }
72}
73
74function append (child) {
75 this.appendChild(child)
76}
77
78function bind (document, obs, data) {
79 return obs(function (value) {
80 var oldNodes = data.targets.get(obs)
81 var newNodes = getNodes(document, value)
82 if (oldNodes) {
83 replace(oldNodes, newNodes)
84 data.targets.set(obs, newNodes)
85 }
86 })
87}
88
89function replace (oldNodes, newNodes) {
90 var parent = oldNodes[oldNodes.length - 1].parentNode
91 var marker = oldNodes[oldNodes.length - 1].nextSibling
92 oldNodes.filter(function (node) {
93 return !~newNodes.indexOf(node)
94 }).forEach(function (node) {
95 parent.removeChild(node)
96 })
97 if (marker) {
98 newNodes.forEach(function (node) {
99 parent.insertBefore(node, marker)
100 })
101 } else {
102 newNodes.forEach(function (node) {
103 parent.appendChild(node)
104 })
105 }
106}
107
108function isText (value) {
109 return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean'
110}
111
112function getNode (document, nodeOrText) {
113 if (nodeOrText == null) {
114 return document.createTextNode('')
115 } else if (isText(nodeOrText)) {
116 return document.createTextNode(nodeOrText.toString())
117 } else {
118 return nodeOrText
119 }
120}
121
122function getNodes (document, nodeOrNodes) {
123 if (Array.isArray(nodeOrNodes)) {
124 if (nodeOrNodes.length) {
125 var result = []
126 nodeOrNodes.forEach(function (item) {
127 if (Array.isArray(item)) {
128 getNodes(document, item).forEach(push, result)
129 } else {
130 result.push(getNode(document, item))
131 }
132 })
133 return result.map(getNode.bind(this, document))
134 } else {
135 return [getNode(document, null)]
136 }
137 } else {
138 return [getNode(document, nodeOrNodes)]
139 }
140}
141
142function push (item) {
143 this.push(item)
144}
145
146function resolve (source) {
147 return typeof source === 'function' ? source() : source
148}
149
150function tryInvoke (func) {
151 if (typeof func === 'function') {
152 func()
153 }
154}
155

Built with git-ssb-web