UNPKG

11.3 kBJavaScriptView Raw
1"use strict";
2var vnode_1 = require("./vnode");
3var is = require("./is");
4var htmldomapi_1 = require("./htmldomapi");
5function isUndef(s) { return s === undefined; }
6function isDef(s) { return s !== undefined; }
7var emptyNode = vnode_1.default('', {}, [], undefined, undefined);
8function sameVnode(vnode1, vnode2) {
9 return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel;
10}
11function isVnode(vnode) {
12 return vnode.sel !== undefined;
13}
14function createKeyToOldIdx(children, beginIdx, endIdx) {
15 var i, map = {}, key;
16 for (i = beginIdx; i <= endIdx; ++i) {
17 key = children[i].key;
18 if (key !== undefined)
19 map[key] = i;
20 }
21 return map;
22}
23var hooks = ['create', 'update', 'remove', 'destroy', 'pre', 'post'];
24var h_1 = require("./h");
25exports.h = h_1.h;
26var thunk_1 = require("./thunk");
27exports.thunk = thunk_1.thunk;
28function init(modules, domApi) {
29 var i, j, cbs = {};
30 var api = domApi !== undefined ? domApi : htmldomapi_1.default;
31 for (i = 0; i < hooks.length; ++i) {
32 cbs[hooks[i]] = [];
33 for (j = 0; j < modules.length; ++j) {
34 if (modules[j][hooks[i]] !== undefined)
35 cbs[hooks[i]].push(modules[j][hooks[i]]);
36 }
37 }
38 function emptyNodeAt(elm) {
39 var id = elm.id ? '#' + elm.id : '';
40 var c = elm.className ? '.' + elm.className.split(' ').join('.') : '';
41 return vnode_1.default(api.tagName(elm).toLowerCase() + id + c, {}, [], undefined, elm);
42 }
43 function createRmCb(childElm, listeners) {
44 return function rmCb() {
45 if (--listeners === 0) {
46 var parent_1 = api.parentNode(childElm);
47 api.removeChild(parent_1, childElm);
48 }
49 };
50 }
51 function createElm(vnode, insertedVnodeQueue) {
52 var i, data = vnode.data;
53 if (data !== undefined) {
54 if (isDef(i = data.hook) && isDef(i = i.init)) {
55 i(vnode);
56 data = vnode.data;
57 }
58 }
59 var children = vnode.children, sel = vnode.sel;
60 if (sel !== undefined) {
61 // Parse selector
62 var hashIdx = sel.indexOf('#');
63 var dotIdx = sel.indexOf('.', hashIdx);
64 var hash = hashIdx > 0 ? hashIdx : sel.length;
65 var dot = dotIdx > 0 ? dotIdx : sel.length;
66 var tag = hashIdx !== -1 || dotIdx !== -1 ? sel.slice(0, Math.min(hash, dot)) : sel;
67 var elm = vnode.elm = isDef(data) && isDef(i = data.ns) ? api.createElementNS(i, tag)
68 : api.createElement(tag);
69 if (hash < dot)
70 elm.id = sel.slice(hash + 1, dot);
71 if (dotIdx > 0)
72 elm.className = sel.slice(dot + 1).replace(/\./g, ' ');
73 if (is.array(children)) {
74 for (i = 0; i < children.length; ++i) {
75 api.appendChild(elm, createElm(children[i], insertedVnodeQueue));
76 }
77 }
78 else if (is.primitive(vnode.text)) {
79 api.appendChild(elm, api.createTextNode(vnode.text));
80 }
81 for (i = 0; i < cbs.create.length; ++i)
82 cbs.create[i](emptyNode, vnode);
83 i = vnode.data.hook; // Reuse variable
84 if (isDef(i)) {
85 if (i.create)
86 i.create(emptyNode, vnode);
87 if (i.insert)
88 insertedVnodeQueue.push(vnode);
89 }
90 }
91 else {
92 vnode.elm = api.createTextNode(vnode.text);
93 }
94 return vnode.elm;
95 }
96 function addVnodes(parentElm, before, vnodes, startIdx, endIdx, insertedVnodeQueue) {
97 for (; startIdx <= endIdx; ++startIdx) {
98 api.insertBefore(parentElm, createElm(vnodes[startIdx], insertedVnodeQueue), before);
99 }
100 }
101 function invokeDestroyHook(vnode) {
102 var i, j, data = vnode.data;
103 if (data !== undefined) {
104 if (isDef(i = data.hook) && isDef(i = i.destroy))
105 i(vnode);
106 for (i = 0; i < cbs.destroy.length; ++i)
107 cbs.destroy[i](vnode);
108 if (vnode.children !== undefined) {
109 for (j = 0; j < vnode.children.length; ++j) {
110 i = vnode.children[j];
111 if (typeof i !== "string") {
112 invokeDestroyHook(i);
113 }
114 }
115 }
116 }
117 }
118 function removeVnodes(parentElm, vnodes, startIdx, endIdx) {
119 for (; startIdx <= endIdx; ++startIdx) {
120 var i_1 = void 0, listeners = void 0, rm = void 0, ch = vnodes[startIdx];
121 if (isDef(ch)) {
122 if (isDef(ch.sel)) {
123 invokeDestroyHook(ch);
124 listeners = cbs.remove.length + 1;
125 rm = createRmCb(ch.elm, listeners);
126 for (i_1 = 0; i_1 < cbs.remove.length; ++i_1)
127 cbs.remove[i_1](ch, rm);
128 if (isDef(i_1 = ch.data) && isDef(i_1 = i_1.hook) && isDef(i_1 = i_1.remove)) {
129 i_1(ch, rm);
130 }
131 else {
132 rm();
133 }
134 }
135 else {
136 api.removeChild(parentElm, ch.elm);
137 }
138 }
139 }
140 }
141 function updateChildren(parentElm, oldCh, newCh, insertedVnodeQueue) {
142 var oldStartIdx = 0, newStartIdx = 0;
143 var oldEndIdx = oldCh.length - 1;
144 var oldStartVnode = oldCh[0];
145 var oldEndVnode = oldCh[oldEndIdx];
146 var newEndIdx = newCh.length - 1;
147 var newStartVnode = newCh[0];
148 var newEndVnode = newCh[newEndIdx];
149 var oldKeyToIdx;
150 var idxInOld;
151 var elmToMove;
152 var before;
153 while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
154 if (isUndef(oldStartVnode)) {
155 oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
156 }
157 else if (isUndef(oldEndVnode)) {
158 oldEndVnode = oldCh[--oldEndIdx];
159 }
160 else if (sameVnode(oldStartVnode, newStartVnode)) {
161 patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue);
162 oldStartVnode = oldCh[++oldStartIdx];
163 newStartVnode = newCh[++newStartIdx];
164 }
165 else if (sameVnode(oldEndVnode, newEndVnode)) {
166 patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue);
167 oldEndVnode = oldCh[--oldEndIdx];
168 newEndVnode = newCh[--newEndIdx];
169 }
170 else if (sameVnode(oldStartVnode, newEndVnode)) {
171 patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue);
172 api.insertBefore(parentElm, oldStartVnode.elm, api.nextSibling(oldEndVnode.elm));
173 oldStartVnode = oldCh[++oldStartIdx];
174 newEndVnode = newCh[--newEndIdx];
175 }
176 else if (sameVnode(oldEndVnode, newStartVnode)) {
177 patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue);
178 api.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
179 oldEndVnode = oldCh[--oldEndIdx];
180 newStartVnode = newCh[++newStartIdx];
181 }
182 else {
183 if (oldKeyToIdx === undefined) {
184 oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx);
185 }
186 idxInOld = oldKeyToIdx[newStartVnode.key];
187 if (isUndef(idxInOld)) {
188 api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm);
189 newStartVnode = newCh[++newStartIdx];
190 }
191 else {
192 elmToMove = oldCh[idxInOld];
193 if (elmToMove.sel !== newStartVnode.sel) {
194 api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm);
195 }
196 else {
197 patchVnode(elmToMove, newStartVnode, insertedVnodeQueue);
198 oldCh[idxInOld] = undefined;
199 api.insertBefore(parentElm, elmToMove.elm, oldStartVnode.elm);
200 }
201 newStartVnode = newCh[++newStartIdx];
202 }
203 }
204 }
205 if (oldStartIdx > oldEndIdx) {
206 before = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
207 addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
208 }
209 else if (newStartIdx > newEndIdx) {
210 removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
211 }
212 }
213 function patchVnode(oldVnode, vnode, insertedVnodeQueue) {
214 var i, hook;
215 if (isDef(i = vnode.data) && isDef(hook = i.hook) && isDef(i = hook.prepatch)) {
216 i(oldVnode, vnode);
217 }
218 var elm = vnode.elm = oldVnode.elm, oldCh = oldVnode.children, ch = vnode.children;
219 if (oldVnode === vnode)
220 return;
221 if (isDef(vnode.data)) {
222 for (i = 0; i < cbs.update.length; ++i)
223 cbs.update[i](oldVnode, vnode);
224 i = vnode.data.hook;
225 if (isDef(i) && isDef(i = i.update))
226 i(oldVnode, vnode);
227 }
228 if (isUndef(vnode.text)) {
229 if (isDef(oldCh) && isDef(ch)) {
230 if (oldCh !== ch)
231 updateChildren(elm, oldCh, ch, insertedVnodeQueue);
232 }
233 else if (isDef(ch)) {
234 if (isDef(oldVnode.text))
235 api.setTextContent(elm, '');
236 addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
237 }
238 else if (isDef(oldCh)) {
239 removeVnodes(elm, oldCh, 0, oldCh.length - 1);
240 }
241 else if (isDef(oldVnode.text)) {
242 api.setTextContent(elm, '');
243 }
244 }
245 else if (oldVnode.text !== vnode.text) {
246 api.setTextContent(elm, vnode.text);
247 }
248 if (isDef(hook) && isDef(i = hook.postpatch)) {
249 i(oldVnode, vnode);
250 }
251 }
252 return function patch(oldVnode, vnode) {
253 var i, elm, parent;
254 var insertedVnodeQueue = [];
255 for (i = 0; i < cbs.pre.length; ++i)
256 cbs.pre[i]();
257 if (!isVnode(oldVnode)) {
258 oldVnode = emptyNodeAt(oldVnode);
259 }
260 if (sameVnode(oldVnode, vnode)) {
261 patchVnode(oldVnode, vnode, insertedVnodeQueue);
262 }
263 else {
264 elm = oldVnode.elm;
265 parent = api.parentNode(elm);
266 createElm(vnode, insertedVnodeQueue);
267 if (parent !== null) {
268 api.insertBefore(parent, vnode.elm, api.nextSibling(elm));
269 removeVnodes(parent, [oldVnode], 0, 0);
270 }
271 }
272 for (i = 0; i < insertedVnodeQueue.length; ++i) {
273 insertedVnodeQueue[i].data.hook.insert(insertedVnodeQueue[i]);
274 }
275 for (i = 0; i < cbs.post.length; ++i)
276 cbs.post[i]();
277 return vnode;
278 };
279}
280exports.init = init;
281//# sourceMappingURL=snabbdom.js.map
\No newline at end of file