maquette 3.5.3 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,910 +4,930 @@
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.maquette = {}));
5
5
  })(this, (function (exports) { 'use strict';
6
6
 
7
- var NAMESPACE_W3 = "http://www.w3.org/";
8
- var NAMESPACE_SVG = "".concat(NAMESPACE_W3, "2000/svg");
9
- var NAMESPACE_XLINK = "".concat(NAMESPACE_W3, "1999/xlink");
10
- var emptyArray = [];
11
- var extend = function (base, overrides) {
12
- var result = {};
13
- Object.keys(base).forEach(function (key) {
14
- result[key] = base[key];
15
- });
16
- if (overrides) {
17
- Object.keys(overrides).forEach(function (key) {
18
- result[key] = overrides[key];
19
- });
20
- }
21
- return result;
22
- };
23
- var same = function (vnode1, vnode2) {
24
- if (vnode1.vnodeSelector !== vnode2.vnodeSelector) {
25
- return false;
26
- }
27
- if (vnode1.properties && vnode2.properties) {
28
- if (vnode1.properties.key !== vnode2.properties.key) {
29
- return false;
30
- }
31
- return vnode1.properties.bind === vnode2.properties.bind;
32
- }
33
- return !vnode1.properties && !vnode2.properties;
34
- };
35
- var checkStyleValue = function (styleValue) {
36
- if (typeof styleValue !== "string") {
37
- throw new Error("Style values must be strings");
38
- }
39
- };
40
- var findIndexOfChild = function (children, sameAs, start) {
41
- if (sameAs.vnodeSelector !== "") {
42
- // Never scan for text-nodes
43
- for (var i = start; i < children.length; i++) {
44
- if (same(children[i], sameAs)) {
45
- return i;
46
- }
47
- }
48
- }
49
- return -1;
50
- };
51
- var checkDistinguishable = function (childNodes, indexToCheck, parentVNode, operation) {
52
- var childNode = childNodes[indexToCheck];
53
- if (childNode.vnodeSelector === "") {
54
- return; // Text nodes need not be distinguishable
55
- }
56
- var properties = childNode.properties;
57
- var key = properties
58
- ? properties.key === undefined
59
- ? properties.bind
60
- : properties.key
61
- : undefined;
62
- if (!key) {
63
- // A key is just assumed to be unique
64
- for (var i = 0; i < childNodes.length; i++) {
65
- if (i !== indexToCheck) {
66
- var node = childNodes[i];
67
- if (same(node, childNode)) {
68
- throw {
69
- error: new Error("".concat(parentVNode.vnodeSelector, " had a ").concat(childNode.vnodeSelector, " child ").concat(operation === "added" ? operation : "removed", ", but there is now more than one. You must add unique key properties to make them distinguishable.")),
70
- parentNode: parentVNode,
71
- childNode: childNode,
72
- };
73
- }
74
- }
75
- }
76
- }
77
- };
78
- var nodeAdded = function (vNode) {
79
- if (vNode.properties) {
80
- var enterAnimation = vNode.properties.enterAnimation;
81
- if (enterAnimation) {
82
- enterAnimation(vNode.domNode, vNode.properties);
83
- }
84
- }
85
- };
86
- var removedNodes = [];
87
- var requestedIdleCallback = false;
88
- var visitRemovedNode = function (node) {
89
- (node.children || []).forEach(visitRemovedNode);
90
- if (node.properties && node.properties.afterRemoved) {
91
- node.properties.afterRemoved.apply(node.properties.bind || node.properties, [
92
- node.domNode,
93
- ]);
94
- }
95
- };
96
- var processPendingNodeRemovals = function () {
97
- requestedIdleCallback = false;
98
- removedNodes.forEach(visitRemovedNode);
99
- removedNodes.length = 0;
100
- };
101
- var scheduleNodeRemoval = function (vNode) {
102
- removedNodes.push(vNode);
103
- if (!requestedIdleCallback) {
104
- requestedIdleCallback = true;
105
- if (typeof window !== "undefined" && "requestIdleCallback" in window) {
106
- window.requestIdleCallback(processPendingNodeRemovals, { timeout: 16 });
107
- }
108
- else {
109
- setTimeout(processPendingNodeRemovals, 16);
110
- }
111
- }
112
- };
113
- var nodeToRemove = function (vNode) {
114
- var domNode = vNode.domNode;
115
- if (vNode.properties) {
116
- var exitAnimation = vNode.properties.exitAnimation;
117
- if (exitAnimation) {
118
- domNode.style.pointerEvents = "none";
119
- var removeDomNode = function () {
120
- if (domNode.parentNode) {
121
- domNode.parentNode.removeChild(domNode);
122
- scheduleNodeRemoval(vNode);
123
- }
124
- };
125
- exitAnimation(domNode, removeDomNode, vNode.properties);
126
- return;
127
- }
128
- }
129
- if (domNode.parentNode) {
130
- domNode.parentNode.removeChild(domNode);
131
- scheduleNodeRemoval(vNode);
132
- }
133
- };
134
- var setProperties = function (domNode, properties, projectionOptions) {
135
- if (!properties) {
136
- return;
137
- }
138
- var eventHandlerInterceptor = projectionOptions.eventHandlerInterceptor;
139
- var propNames = Object.keys(properties);
140
- var propCount = propNames.length;
141
- var _loop_1 = function (i) {
142
- var propName = propNames[i];
143
- var propValue = properties[propName];
144
- if (propName === "className") {
145
- throw new Error('Property "className" is not supported, use "class".');
146
- }
147
- else if (propName === "class") {
148
- toggleClasses(domNode, propValue, true);
149
- }
150
- else if (propName === "classes") {
151
- // object with string keys and boolean values
152
- var classNames = Object.keys(propValue);
153
- var classNameCount = classNames.length;
154
- for (var j = 0; j < classNameCount; j++) {
155
- var className = classNames[j];
156
- if (propValue[className]) {
157
- domNode.classList.add(className);
158
- }
159
- }
160
- }
161
- else if (propName === "styles") {
162
- // object with string keys and string (!) values
163
- var styleNames = Object.keys(propValue);
164
- var styleCount = styleNames.length;
165
- for (var j = 0; j < styleCount; j++) {
166
- var styleName = styleNames[j];
167
- var styleValue = propValue[styleName];
168
- if (styleValue) {
169
- checkStyleValue(styleValue);
170
- projectionOptions.styleApplyer(domNode, styleName, styleValue);
171
- }
172
- }
173
- }
174
- else if (propName !== "key" && propValue !== null && propValue !== undefined) {
175
- var type = typeof propValue;
176
- if (type === "function") {
177
- if (propName.lastIndexOf("on", 0) === 0) {
178
- // lastIndexOf(,0)===0 -> startsWith
179
- if (eventHandlerInterceptor) {
180
- propValue = eventHandlerInterceptor(propName, propValue, domNode, properties); // intercept eventhandlers
181
- }
182
- if (propName === "oninput") {
183
- (function () {
184
- // record the evt.target.value, because IE and Edge sometimes do a requestAnimationFrame between changing value and running oninput
185
- var oldPropValue = propValue;
186
- propValue = function (evt) {
187
- oldPropValue.apply(this, [evt]);
188
- evt.target["oninput-value"] = evt.target.value; // may be HTMLTextAreaElement as well
189
- };
190
- })();
191
- }
192
- }
193
- domNode[propName] = propValue;
194
- }
195
- else if (projectionOptions.namespace === NAMESPACE_SVG) {
196
- if (propName === "href") {
197
- domNode.setAttributeNS(NAMESPACE_XLINK, propName, propValue);
198
- }
199
- else {
200
- // all SVG attributes are read-only in DOM, so...
201
- domNode.setAttribute(propName, propValue);
202
- }
203
- }
204
- else if (type === "string" && propName !== "value" && propName !== "innerHTML") {
205
- domNode.setAttribute(propName, propValue);
206
- }
207
- else {
208
- domNode[propName] = propValue;
209
- }
210
- }
211
- };
212
- for (var i = 0; i < propCount; i++) {
213
- _loop_1(i);
214
- }
215
- };
216
- var addChildren = function (domNode, children, projectionOptions) {
217
- if (!children) {
218
- return;
219
- }
220
- for (var _i = 0, children_1 = children; _i < children_1.length; _i++) {
221
- var child = children_1[_i];
222
- createDom(child, domNode, undefined, projectionOptions);
223
- }
224
- };
225
- var initPropertiesAndChildren = function (domNode, vnode, projectionOptions) {
226
- addChildren(domNode, vnode.children, projectionOptions); // children before properties, needed for value property of <select>.
227
- if (vnode.text) {
228
- domNode.textContent = vnode.text;
229
- }
230
- setProperties(domNode, vnode.properties, projectionOptions);
231
- if (vnode.properties && vnode.properties.afterCreate) {
232
- vnode.properties.afterCreate.apply(vnode.properties.bind || vnode.properties, [
233
- domNode,
234
- projectionOptions,
235
- vnode.vnodeSelector,
236
- vnode.properties,
237
- vnode.children,
238
- ]);
239
- }
240
- };
241
- var createDom = function (vnode, parentNode, insertBefore, projectionOptions) {
242
- var domNode;
243
- var start = 0;
244
- var vnodeSelector = vnode.vnodeSelector;
245
- var doc = parentNode.ownerDocument;
246
- if (vnodeSelector === "") {
247
- if (vnode.domNode) {
248
- vnode.domNode.nodeValue = vnode.text;
249
- }
250
- else {
251
- domNode = vnode.domNode = doc.createTextNode(vnode.text);
252
- if (insertBefore !== undefined) {
253
- parentNode.insertBefore(domNode, insertBefore);
254
- }
255
- else {
256
- parentNode.appendChild(domNode);
257
- }
258
- }
259
- }
260
- else {
261
- for (var i = 0; i <= vnodeSelector.length; ++i) {
262
- var c = vnodeSelector.charAt(i);
263
- if (i === vnodeSelector.length || c === "." || c === "#") {
264
- var type = vnodeSelector.charAt(start - 1);
265
- var found = vnodeSelector.slice(start, i);
266
- if (type === ".") {
267
- domNode.classList.add(found);
268
- }
269
- else if (type === "#") {
270
- domNode.id = found;
271
- }
272
- else {
273
- if (found === "svg") {
274
- projectionOptions = extend(projectionOptions, {
275
- namespace: NAMESPACE_SVG,
276
- });
277
- }
278
- if (projectionOptions.namespace !== undefined) {
279
- domNode = vnode.domNode = doc.createElementNS(projectionOptions.namespace, found);
280
- }
281
- else {
282
- domNode = vnode.domNode = vnode.domNode || doc.createElement(found);
283
- if (found === "input" && vnode.properties && vnode.properties.type !== undefined) {
284
- // IE8 and older don't support setting input type after the DOM Node has been added to the document
285
- domNode.setAttribute("type", vnode.properties.type);
286
- }
287
- }
288
- if (insertBefore !== undefined) {
289
- parentNode.insertBefore(domNode, insertBefore);
290
- }
291
- else if (domNode.parentNode !== parentNode) {
292
- parentNode.appendChild(domNode);
293
- }
294
- }
295
- start = i + 1;
296
- }
297
- }
298
- initPropertiesAndChildren(domNode, vnode, projectionOptions);
299
- }
300
- };
301
- var updateDom;
302
- /**
303
- * Adds or removes classes from an Element
304
- * @param domNode the element
305
- * @param classes a string separated list of classes
306
- * @param on true means add classes, false means remove
307
- */
308
- var toggleClasses = function (domNode, classes, on) {
309
- if (!classes) {
310
- return;
311
- }
312
- classes.split(" ").forEach(function (classToToggle) {
313
- if (classToToggle) {
314
- domNode.classList.toggle(classToToggle, on);
315
- }
316
- });
317
- };
318
- var updateProperties = function (domNode, previousProperties, properties, projectionOptions) {
319
- if (!properties) {
320
- return;
321
- }
322
- var propertiesUpdated = false;
323
- var propNames = Object.keys(properties);
324
- var propCount = propNames.length;
325
- for (var i = 0; i < propCount; i++) {
326
- var propName = propNames[i];
327
- // assuming that properties will be nullified instead of missing is by design
328
- var propValue = properties[propName];
329
- var previousValue = previousProperties[propName];
330
- if (propName === "class") {
331
- if (previousValue !== propValue) {
332
- toggleClasses(domNode, previousValue, false);
333
- toggleClasses(domNode, propValue, true);
334
- }
335
- }
336
- else if (propName === "classes") {
337
- var classList = domNode.classList;
338
- var classNames = Object.keys(propValue);
339
- var classNameCount = classNames.length;
340
- for (var j = 0; j < classNameCount; j++) {
341
- var className = classNames[j];
342
- var on = !!propValue[className];
343
- var previousOn = !!previousValue[className];
344
- if (on === previousOn) {
345
- continue;
346
- }
347
- propertiesUpdated = true;
348
- if (on) {
349
- classList.add(className);
350
- }
351
- else {
352
- classList.remove(className);
353
- }
354
- }
355
- }
356
- else if (propName === "styles") {
357
- var styleNames = Object.keys(propValue);
358
- var styleCount = styleNames.length;
359
- for (var j = 0; j < styleCount; j++) {
360
- var styleName = styleNames[j];
361
- var newStyleValue = propValue[styleName];
362
- var oldStyleValue = previousValue[styleName];
363
- if (newStyleValue === oldStyleValue) {
364
- continue;
365
- }
366
- propertiesUpdated = true;
367
- if (newStyleValue) {
368
- checkStyleValue(newStyleValue);
369
- projectionOptions.styleApplyer(domNode, styleName, newStyleValue);
370
- }
371
- else {
372
- projectionOptions.styleApplyer(domNode, styleName, "");
373
- }
374
- }
375
- }
376
- else {
377
- if (!propValue && typeof previousValue === "string") {
378
- propValue = "";
379
- }
380
- if (propName === "value") {
381
- // value can be manipulated by the user directly and using event.preventDefault() is not an option
382
- var domValue = domNode[propName];
383
- if (domValue !== propValue && // The 'value' in the DOM tree !== newValue
384
- (domNode["oninput-value"]
385
- ? domValue === domNode["oninput-value"] // If the last reported value to 'oninput' does not match domValue, do nothing and wait for oninput
386
- : propValue !== previousValue) // Only update the value if the vdom changed
387
- ) {
388
- // The edge cases are described in the tests
389
- domNode[propName] = propValue; // Reset the value, even if the virtual DOM did not change
390
- domNode["oninput-value"] = undefined;
391
- } // else do not update the domNode, otherwise the cursor position would be changed
392
- if (propValue !== previousValue) {
393
- propertiesUpdated = true;
394
- }
395
- }
396
- else if (propValue !== previousValue) {
397
- var type = typeof propValue;
398
- if (type !== "function" || !projectionOptions.eventHandlerInterceptor) {
399
- // Function updates are expected to be handled by the EventHandlerInterceptor
400
- if (projectionOptions.namespace === NAMESPACE_SVG) {
401
- if (propName === "href") {
402
- domNode.setAttributeNS(NAMESPACE_XLINK, propName, propValue);
403
- }
404
- else {
405
- // all SVG attributes are read-only in DOM, so...
406
- domNode.setAttribute(propName, propValue);
407
- }
408
- }
409
- else if (type === "string" && propName !== "innerHTML") {
410
- if (propName === "role" && propValue === "") {
411
- domNode.removeAttribute(propName);
412
- }
413
- else {
414
- domNode.setAttribute(propName, propValue);
415
- }
416
- }
417
- else if (domNode[propName] !== propValue) {
418
- // Comparison is here for side-effects in Edge with scrollLeft and scrollTop
419
- domNode[propName] = propValue;
420
- }
421
- propertiesUpdated = true;
422
- }
423
- }
424
- }
425
- }
426
- return propertiesUpdated;
427
- };
428
- var updateChildren = function (vnode, domNode, oldChildren, newChildren, projectionOptions) {
429
- if (oldChildren === newChildren) {
430
- return false;
431
- }
432
- oldChildren = oldChildren || emptyArray;
433
- newChildren = newChildren || emptyArray;
434
- var oldChildrenLength = oldChildren.length;
435
- var newChildrenLength = newChildren.length;
436
- var oldIndex = 0;
437
- var newIndex = 0;
438
- var i;
439
- var textUpdated = false;
440
- while (newIndex < newChildrenLength) {
441
- var oldChild = oldIndex < oldChildrenLength ? oldChildren[oldIndex] : undefined;
442
- var newChild = newChildren[newIndex];
443
- if (oldChild !== undefined && same(oldChild, newChild)) {
444
- textUpdated = updateDom(oldChild, newChild, projectionOptions) || textUpdated;
445
- oldIndex++;
446
- }
447
- else {
448
- var findOldIndex = findIndexOfChild(oldChildren, newChild, oldIndex + 1);
449
- if (findOldIndex >= 0) {
450
- // Remove preceding missing children
451
- for (i = oldIndex; i < findOldIndex; i++) {
452
- nodeToRemove(oldChildren[i]);
453
- checkDistinguishable(oldChildren, i, vnode, "removed");
454
- }
455
- textUpdated =
456
- updateDom(oldChildren[findOldIndex], newChild, projectionOptions) || textUpdated;
457
- oldIndex = findOldIndex + 1;
458
- }
459
- else {
460
- // New child
461
- createDom(newChild, domNode, oldIndex < oldChildrenLength ? oldChildren[oldIndex].domNode : undefined, projectionOptions);
462
- nodeAdded(newChild);
463
- checkDistinguishable(newChildren, newIndex, vnode, "added");
464
- }
465
- }
466
- newIndex++;
467
- }
468
- if (oldChildrenLength > oldIndex) {
469
- // Remove child fragments
470
- for (i = oldIndex; i < oldChildrenLength; i++) {
471
- nodeToRemove(oldChildren[i]);
472
- checkDistinguishable(oldChildren, i, vnode, "removed");
473
- }
474
- }
475
- return textUpdated;
476
- };
477
- updateDom = function (previous, vnode, projectionOptions) {
478
- var domNode = previous.domNode;
479
- var textUpdated = false;
480
- if (previous === vnode) {
481
- return false; // By contract, VNode objects may not be modified anymore after passing them to maquette
482
- }
483
- var updated = false;
484
- if (vnode.vnodeSelector === "") {
485
- if (vnode.text !== previous.text) {
486
- var newTextNode = domNode.ownerDocument.createTextNode(vnode.text);
487
- domNode.parentNode.replaceChild(newTextNode, domNode);
488
- vnode.domNode = newTextNode;
489
- textUpdated = true;
490
- return textUpdated;
491
- }
492
- vnode.domNode = domNode;
493
- }
494
- else {
495
- if (vnode.vnodeSelector.lastIndexOf("svg", 0) === 0) {
496
- // lastIndexOf(needle,0)===0 means StartsWith
497
- projectionOptions = extend(projectionOptions, {
498
- namespace: NAMESPACE_SVG,
499
- });
500
- }
501
- if (previous.text !== vnode.text) {
502
- updated = true;
503
- if (vnode.text === undefined) {
504
- domNode.removeChild(domNode.firstChild); // the only textnode presumably
505
- }
506
- else {
507
- domNode.textContent = vnode.text;
508
- }
509
- }
510
- vnode.domNode = domNode;
511
- updated =
512
- updateChildren(vnode, domNode, previous.children, vnode.children, projectionOptions) ||
513
- updated;
514
- updated =
515
- updateProperties(domNode, previous.properties, vnode.properties, projectionOptions) ||
516
- updated;
517
- if (vnode.properties && vnode.properties.afterUpdate) {
518
- vnode.properties.afterUpdate.apply(vnode.properties.bind || vnode.properties, [
519
- domNode,
520
- projectionOptions,
521
- vnode.vnodeSelector,
522
- vnode.properties,
523
- vnode.children,
524
- ]);
525
- }
526
- }
527
- if (updated && vnode.properties && vnode.properties.updateAnimation) {
528
- vnode.properties.updateAnimation(domNode, vnode.properties, previous.properties);
529
- }
530
- return textUpdated;
531
- };
532
- var createProjection = function (vnode, projectionOptions) {
533
- return {
534
- getLastRender: function () { return vnode; },
535
- update: function (updatedVnode) {
536
- if (vnode.vnodeSelector !== updatedVnode.vnodeSelector) {
537
- throw new Error("The selector for the root VNode may not be changed. (consider using dom.merge and add one extra level to the virtual DOM)");
538
- }
539
- var previousVNode = vnode;
540
- vnode = updatedVnode;
541
- updateDom(previousVNode, updatedVnode, projectionOptions);
542
- },
543
- domNode: vnode.domNode,
544
- };
7
+ var NAMESPACE_W3 = "http://www.w3.org/";
8
+ var NAMESPACE_SVG = "".concat(NAMESPACE_W3, "2000/svg");
9
+ var NAMESPACE_XLINK = "".concat(NAMESPACE_W3, "1999/xlink");
10
+ var emptyArray = [];
11
+ var extend = function (base, overrides) {
12
+ var result = {};
13
+ Object.keys(base).forEach(function (key) {
14
+ result[key] = base[key];
15
+ });
16
+ if (overrides) {
17
+ Object.keys(overrides).forEach(function (key) {
18
+ result[key] = overrides[key];
19
+ });
20
+ }
21
+ return result;
22
+ };
23
+ var same = function (vnode1, vnode2) {
24
+ if (vnode1.vnodeSelector !== vnode2.vnodeSelector) {
25
+ return false;
26
+ }
27
+ if (vnode1.properties && vnode2.properties) {
28
+ if (vnode1.properties.key !== vnode2.properties.key) {
29
+ return false;
30
+ }
31
+ return vnode1.properties.bind === vnode2.properties.bind;
32
+ }
33
+ return !vnode1.properties && !vnode2.properties;
34
+ };
35
+ var checkStyleValue = function (styleValue) {
36
+ if (typeof styleValue !== "string") {
37
+ throw new Error("Style values must be strings");
38
+ }
39
+ };
40
+ var findIndexOfChild = function (children, sameAs, start) {
41
+ if (sameAs.vnodeSelector !== "") {
42
+ // Never scan for text-nodes
43
+ for (var i = start; i < children.length; i++) {
44
+ if (same(children[i], sameAs)) {
45
+ return i;
46
+ }
47
+ }
48
+ }
49
+ return -1;
50
+ };
51
+ var checkDistinguishable = function (childNodes, indexToCheck, parentVNode, operation) {
52
+ var childNode = childNodes[indexToCheck];
53
+ if (childNode.vnodeSelector === "") {
54
+ return; // Text nodes need not be distinguishable
55
+ }
56
+ var properties = childNode.properties;
57
+ var key = properties
58
+ ? properties.key === undefined
59
+ ? properties.bind
60
+ : properties.key
61
+ : undefined;
62
+ if (!key) {
63
+ // A key is just assumed to be unique
64
+ for (var i = 0; i < childNodes.length; i++) {
65
+ if (i !== indexToCheck) {
66
+ var node = childNodes[i];
67
+ if (same(node, childNode)) {
68
+ throw {
69
+ error: new Error("".concat(parentVNode.vnodeSelector, " had a ").concat(childNode.vnodeSelector, " child ").concat(operation === "added" ? operation : "removed", ", but there is now more than one. You must add unique key properties to make them distinguishable.")),
70
+ parentNode: parentVNode,
71
+ childNode: childNode,
72
+ };
73
+ }
74
+ }
75
+ }
76
+ }
77
+ };
78
+ var nodeAdded = function (vNode) {
79
+ if (vNode.properties) {
80
+ var enterAnimation = vNode.properties.enterAnimation;
81
+ if (enterAnimation) {
82
+ enterAnimation(vNode.domNode, vNode.properties);
83
+ }
84
+ }
85
+ };
86
+ var removedNodes = [];
87
+ var requestedIdleCallback = false;
88
+ var visitRemovedNode = function (node) {
89
+ (node.children || []).forEach(visitRemovedNode);
90
+ if (node.properties && node.properties.afterRemoved) {
91
+ node.properties.afterRemoved.apply(node.properties.bind || node.properties, [
92
+ node.domNode,
93
+ ]);
94
+ }
95
+ };
96
+ var processPendingNodeRemovals = function () {
97
+ requestedIdleCallback = false;
98
+ removedNodes.forEach(visitRemovedNode);
99
+ removedNodes.length = 0;
100
+ };
101
+ var scheduleNodeRemoval = function (vNode) {
102
+ removedNodes.push(vNode);
103
+ if (!requestedIdleCallback) {
104
+ requestedIdleCallback = true;
105
+ if (typeof window !== "undefined" && "requestIdleCallback" in window) {
106
+ window.requestIdleCallback(processPendingNodeRemovals, { timeout: 16 });
107
+ }
108
+ else {
109
+ setTimeout(processPendingNodeRemovals, 16);
110
+ }
111
+ }
112
+ };
113
+ var nodeToRemove = function (vNode) {
114
+ var domNode = vNode.domNode;
115
+ if (vNode.properties) {
116
+ var exitAnimation = vNode.properties.exitAnimation;
117
+ if (exitAnimation) {
118
+ domNode.style.pointerEvents = "none";
119
+ var removeDomNode = function () {
120
+ if (domNode.parentNode) {
121
+ domNode.parentNode.removeChild(domNode);
122
+ scheduleNodeRemoval(vNode);
123
+ }
124
+ };
125
+ exitAnimation(domNode, removeDomNode, vNode.properties);
126
+ return;
127
+ }
128
+ }
129
+ if (domNode.parentNode) {
130
+ domNode.parentNode.removeChild(domNode);
131
+ scheduleNodeRemoval(vNode);
132
+ }
133
+ };
134
+ var setProperties = function (domNode, properties, projectionOptions) {
135
+ if (!properties) {
136
+ return;
137
+ }
138
+ var eventHandlerInterceptor = projectionOptions.eventHandlerInterceptor;
139
+ var propNames = Object.keys(properties);
140
+ var propCount = propNames.length;
141
+ var _loop_1 = function (i) {
142
+ var propName = propNames[i];
143
+ var propValue = properties[propName];
144
+ if (propName === "className") {
145
+ throw new Error('Property "className" is not supported, use "class".');
146
+ }
147
+ else if (propName === "class") {
148
+ toggleClasses(domNode, propValue, true);
149
+ }
150
+ else if (propName === "classes") {
151
+ // object with string keys and boolean values
152
+ var classNames = Object.keys(propValue);
153
+ var classNameCount = classNames.length;
154
+ for (var j = 0; j < classNameCount; j++) {
155
+ var className = classNames[j];
156
+ if (propValue[className]) {
157
+ domNode.classList.add(className);
158
+ }
159
+ }
160
+ }
161
+ else if (propName === "styles") {
162
+ // object with string keys and string (!) values
163
+ var styleNames = Object.keys(propValue);
164
+ var styleCount = styleNames.length;
165
+ for (var j = 0; j < styleCount; j++) {
166
+ var styleName = styleNames[j];
167
+ var styleValue = propValue[styleName];
168
+ if (styleValue) {
169
+ checkStyleValue(styleValue);
170
+ projectionOptions.styleApplyer(domNode, styleName, styleValue);
171
+ }
172
+ }
173
+ }
174
+ else if (propName === "on" && propValue) {
175
+ // object with string keys and function values
176
+ for (var _i = 0, _a = Object.entries(properties.on); _i < _a.length; _i++) {
177
+ var _b = _a[_i], key = _b[0], handler = _b[1];
178
+ var listener = typeof handler === "function" ? handler : handler.listener;
179
+ if (eventHandlerInterceptor) {
180
+ listener = eventHandlerInterceptor(key, listener, domNode, properties);
181
+ }
182
+ if (listener) {
183
+ domNode.addEventListener(key, listener, typeof handler === "function" ? undefined : handler.options);
184
+ }
185
+ }
186
+ }
187
+ else if (propName !== "key" && propValue !== null && propValue !== undefined) {
188
+ var type = typeof propValue;
189
+ if (type === "function") {
190
+ if (propName.lastIndexOf("on", 0) === 0) {
191
+ // lastIndexOf(,0)===0 -> startsWith
192
+ if (eventHandlerInterceptor) {
193
+ propValue = eventHandlerInterceptor(propName, propValue, domNode, properties); // intercept eventhandlers
194
+ }
195
+ if (propName === "oninput") {
196
+ (function () {
197
+ // record the evt.target.value, because IE and Edge sometimes do a requestAnimationFrame between changing value and running oninput
198
+ var oldPropValue = propValue;
199
+ propValue = function (evt) {
200
+ oldPropValue.apply(this, [evt]);
201
+ evt.target["oninput-value"] = evt.target.value; // may be HTMLTextAreaElement as well
202
+ };
203
+ })();
204
+ }
205
+ }
206
+ domNode[propName] = propValue;
207
+ }
208
+ else if (projectionOptions.namespace === NAMESPACE_SVG) {
209
+ if (propName === "href") {
210
+ domNode.setAttributeNS(NAMESPACE_XLINK, propName, propValue);
211
+ }
212
+ else {
213
+ // all SVG attributes are read-only in DOM, so...
214
+ domNode.setAttribute(propName, propValue);
215
+ }
216
+ }
217
+ else if (type === "string" && propName !== "value" && propName !== "innerHTML") {
218
+ domNode.setAttribute(propName, propValue);
219
+ }
220
+ else {
221
+ domNode[propName] = propValue;
222
+ }
223
+ }
224
+ };
225
+ for (var i = 0; i < propCount; i++) {
226
+ _loop_1(i);
227
+ }
228
+ };
229
+ var addChildren = function (domNode, children, projectionOptions) {
230
+ if (!children) {
231
+ return;
232
+ }
233
+ for (var _i = 0, children_1 = children; _i < children_1.length; _i++) {
234
+ var child = children_1[_i];
235
+ createDom(child, domNode, undefined, projectionOptions);
236
+ }
237
+ };
238
+ var initPropertiesAndChildren = function (domNode, vnode, projectionOptions) {
239
+ addChildren(domNode, vnode.children, projectionOptions); // children before properties, needed for value property of <select>.
240
+ if (vnode.text) {
241
+ domNode.textContent = vnode.text;
242
+ }
243
+ setProperties(domNode, vnode.properties, projectionOptions);
244
+ if (vnode.properties && vnode.properties.afterCreate) {
245
+ vnode.properties.afterCreate.apply(vnode.properties.bind || vnode.properties, [
246
+ domNode,
247
+ projectionOptions,
248
+ vnode.vnodeSelector,
249
+ vnode.properties,
250
+ vnode.children,
251
+ ]);
252
+ }
253
+ };
254
+ var createDom = function (vnode, parentNode, insertBefore, projectionOptions) {
255
+ var _a;
256
+ var domNode;
257
+ var start = 0;
258
+ var vnodeSelector = vnode.vnodeSelector;
259
+ var doc = parentNode.ownerDocument;
260
+ if (vnodeSelector === "") {
261
+ if (vnode.domNode) {
262
+ vnode.domNode.nodeValue = vnode.text;
263
+ }
264
+ else {
265
+ domNode = vnode.domNode = doc.createTextNode(vnode.text);
266
+ if (insertBefore !== undefined) {
267
+ parentNode.insertBefore(domNode, insertBefore);
268
+ }
269
+ else {
270
+ parentNode.appendChild(domNode);
271
+ }
272
+ }
273
+ }
274
+ else {
275
+ for (var i = 0; i <= vnodeSelector.length; ++i) {
276
+ var c = vnodeSelector.charAt(i);
277
+ if (i === vnodeSelector.length || c === "." || c === "#") {
278
+ var type = vnodeSelector.charAt(start - 1);
279
+ var found = vnodeSelector.slice(start, i);
280
+ if (type === ".") {
281
+ domNode.classList.add(found);
282
+ }
283
+ else if (type === "#") {
284
+ domNode.id = found;
285
+ }
286
+ else {
287
+ if (found === "svg") {
288
+ projectionOptions = extend(projectionOptions, {
289
+ namespace: NAMESPACE_SVG,
290
+ });
291
+ }
292
+ if (projectionOptions.namespace !== undefined) {
293
+ domNode = vnode.domNode = doc.createElementNS(projectionOptions.namespace, found);
294
+ }
295
+ else {
296
+ domNode = vnode.domNode =
297
+ vnode.domNode ||
298
+ (((_a = vnode.properties) === null || _a === void 0 ? void 0 : _a.is)
299
+ ? doc.createElement(found, { is: vnode.properties.is })
300
+ : doc.createElement(found));
301
+ if (found === "input" && vnode.properties && vnode.properties.type !== undefined) {
302
+ // IE8 and older don't support setting input type after the DOM Node has been added to the document
303
+ domNode.setAttribute("type", vnode.properties.type);
304
+ }
305
+ }
306
+ if (insertBefore !== undefined) {
307
+ parentNode.insertBefore(domNode, insertBefore);
308
+ }
309
+ else if (domNode.parentNode !== parentNode) {
310
+ parentNode.appendChild(domNode);
311
+ }
312
+ }
313
+ start = i + 1;
314
+ }
315
+ }
316
+ initPropertiesAndChildren(domNode, vnode, projectionOptions);
317
+ }
318
+ };
319
+ var updateDom;
320
+ /**
321
+ * Adds or removes classes from an Element
322
+ * @param domNode the element
323
+ * @param classes a string separated list of classes
324
+ * @param on true means add classes, false means remove
325
+ */
326
+ var toggleClasses = function (domNode, classes, on) {
327
+ if (!classes) {
328
+ return;
329
+ }
330
+ classes.split(" ").forEach(function (classToToggle) {
331
+ if (classToToggle) {
332
+ domNode.classList.toggle(classToToggle, on);
333
+ }
334
+ });
335
+ };
336
+ var updateProperties = function (domNode, previousProperties, properties, projectionOptions) {
337
+ if (!properties) {
338
+ return;
339
+ }
340
+ var propertiesUpdated = false;
341
+ var propNames = Object.keys(properties);
342
+ var propCount = propNames.length;
343
+ for (var i = 0; i < propCount; i++) {
344
+ var propName = propNames[i];
345
+ // assuming that properties will be nullified instead of missing is by design
346
+ var propValue = properties[propName];
347
+ var previousValue = previousProperties[propName];
348
+ if (propName === "class") {
349
+ if (previousValue !== propValue) {
350
+ toggleClasses(domNode, previousValue, false);
351
+ toggleClasses(domNode, propValue, true);
352
+ }
353
+ }
354
+ else if (propName === "classes") {
355
+ var classList = domNode.classList;
356
+ var classNames = Object.keys(propValue);
357
+ var classNameCount = classNames.length;
358
+ for (var j = 0; j < classNameCount; j++) {
359
+ var className = classNames[j];
360
+ var on = !!propValue[className];
361
+ var previousOn = !!previousValue[className];
362
+ if (on === previousOn) {
363
+ continue;
364
+ }
365
+ propertiesUpdated = true;
366
+ if (on) {
367
+ classList.add(className);
368
+ }
369
+ else {
370
+ classList.remove(className);
371
+ }
372
+ }
373
+ }
374
+ else if (propName === "styles") {
375
+ var styleNames = Object.keys(propValue);
376
+ var styleCount = styleNames.length;
377
+ for (var j = 0; j < styleCount; j++) {
378
+ var styleName = styleNames[j];
379
+ var newStyleValue = propValue[styleName];
380
+ var oldStyleValue = previousValue[styleName];
381
+ if (newStyleValue === oldStyleValue) {
382
+ continue;
383
+ }
384
+ propertiesUpdated = true;
385
+ if (newStyleValue) {
386
+ checkStyleValue(newStyleValue);
387
+ projectionOptions.styleApplyer(domNode, styleName, newStyleValue);
388
+ }
389
+ else {
390
+ projectionOptions.styleApplyer(domNode, styleName, "");
391
+ }
392
+ }
393
+ }
394
+ else {
395
+ if (!propValue && typeof previousValue === "string") {
396
+ propValue = "";
397
+ }
398
+ if (propName === "value") {
399
+ // value can be manipulated by the user directly and using event.preventDefault() is not an option
400
+ var domValue = domNode[propName];
401
+ if (domValue !== propValue && // The 'value' in the DOM tree !== newValue
402
+ (domNode["oninput-value"]
403
+ ? domValue === domNode["oninput-value"] // If the last reported value to 'oninput' does not match domValue, do nothing and wait for oninput
404
+ : propValue !== previousValue) // Only update the value if the vdom changed
405
+ ) {
406
+ // The edge cases are described in the tests
407
+ domNode[propName] = propValue; // Reset the value, even if the virtual DOM did not change
408
+ domNode["oninput-value"] = undefined;
409
+ } // else do not update the domNode, otherwise the cursor position would be changed
410
+ if (propValue !== previousValue) {
411
+ propertiesUpdated = true;
412
+ }
413
+ }
414
+ else if (propValue !== previousValue) {
415
+ var type = typeof propValue;
416
+ if (type !== "function" || !projectionOptions.eventHandlerInterceptor) {
417
+ // Function updates are expected to be handled by the EventHandlerInterceptor
418
+ if (projectionOptions.namespace === NAMESPACE_SVG) {
419
+ if (propName === "href") {
420
+ domNode.setAttributeNS(NAMESPACE_XLINK, propName, propValue);
421
+ }
422
+ else {
423
+ // all SVG attributes are read-only in DOM, so...
424
+ domNode.setAttribute(propName, propValue);
425
+ }
426
+ }
427
+ else if (type === "string" && propName !== "innerHTML") {
428
+ if (propName === "role" && propValue === "") {
429
+ domNode.removeAttribute(propName);
430
+ }
431
+ else {
432
+ domNode.setAttribute(propName, propValue);
433
+ }
434
+ }
435
+ else if (domNode[propName] !== propValue) {
436
+ // Comparison is here for side-effects in Edge with scrollLeft and scrollTop
437
+ domNode[propName] = propValue;
438
+ }
439
+ propertiesUpdated = true;
440
+ }
441
+ }
442
+ }
443
+ }
444
+ return propertiesUpdated;
445
+ };
446
+ var updateChildren = function (vnode, domNode, oldChildren, newChildren, projectionOptions) {
447
+ if (oldChildren === newChildren) {
448
+ return false;
449
+ }
450
+ oldChildren = oldChildren || emptyArray;
451
+ newChildren = newChildren || emptyArray;
452
+ var oldChildrenLength = oldChildren.length;
453
+ var newChildrenLength = newChildren.length;
454
+ var oldIndex = 0;
455
+ var newIndex = 0;
456
+ var i;
457
+ var textUpdated = false;
458
+ while (newIndex < newChildrenLength) {
459
+ var oldChild = oldIndex < oldChildrenLength ? oldChildren[oldIndex] : undefined;
460
+ var newChild = newChildren[newIndex];
461
+ if (oldChild !== undefined && same(oldChild, newChild)) {
462
+ textUpdated = updateDom(oldChild, newChild, projectionOptions) || textUpdated;
463
+ oldIndex++;
464
+ }
465
+ else {
466
+ var findOldIndex = findIndexOfChild(oldChildren, newChild, oldIndex + 1);
467
+ if (findOldIndex >= 0) {
468
+ // Remove preceding missing children
469
+ for (i = oldIndex; i < findOldIndex; i++) {
470
+ nodeToRemove(oldChildren[i]);
471
+ checkDistinguishable(oldChildren, i, vnode, "removed");
472
+ }
473
+ textUpdated =
474
+ updateDom(oldChildren[findOldIndex], newChild, projectionOptions) || textUpdated;
475
+ oldIndex = findOldIndex + 1;
476
+ }
477
+ else {
478
+ // New child
479
+ createDom(newChild, domNode, oldIndex < oldChildrenLength ? oldChildren[oldIndex].domNode : undefined, projectionOptions);
480
+ nodeAdded(newChild);
481
+ checkDistinguishable(newChildren, newIndex, vnode, "added");
482
+ }
483
+ }
484
+ newIndex++;
485
+ }
486
+ if (oldChildrenLength > oldIndex) {
487
+ // Remove child fragments
488
+ for (i = oldIndex; i < oldChildrenLength; i++) {
489
+ nodeToRemove(oldChildren[i]);
490
+ checkDistinguishable(oldChildren, i, vnode, "removed");
491
+ }
492
+ }
493
+ return textUpdated;
494
+ };
495
+ updateDom = function (previous, vnode, projectionOptions) {
496
+ var domNode = previous.domNode;
497
+ var textUpdated = false;
498
+ if (previous === vnode) {
499
+ return false; // By contract, VNode objects may not be modified anymore after passing them to maquette
500
+ }
501
+ var updated = false;
502
+ if (vnode.vnodeSelector === "") {
503
+ if (vnode.text !== previous.text) {
504
+ var newTextNode = domNode.ownerDocument.createTextNode(vnode.text);
505
+ domNode.parentNode.replaceChild(newTextNode, domNode);
506
+ vnode.domNode = newTextNode;
507
+ textUpdated = true;
508
+ return textUpdated;
509
+ }
510
+ vnode.domNode = domNode;
511
+ }
512
+ else {
513
+ if (vnode.vnodeSelector.lastIndexOf("svg", 0) === 0) {
514
+ // lastIndexOf(needle,0)===0 means StartsWith
515
+ projectionOptions = extend(projectionOptions, {
516
+ namespace: NAMESPACE_SVG,
517
+ });
518
+ }
519
+ if (previous.text !== vnode.text) {
520
+ updated = true;
521
+ if (vnode.text === undefined) {
522
+ domNode.removeChild(domNode.firstChild); // the only textnode presumably
523
+ }
524
+ else {
525
+ domNode.textContent = vnode.text;
526
+ }
527
+ }
528
+ vnode.domNode = domNode;
529
+ updated =
530
+ updateChildren(vnode, domNode, previous.children, vnode.children, projectionOptions) ||
531
+ updated;
532
+ updated =
533
+ updateProperties(domNode, previous.properties, vnode.properties, projectionOptions) ||
534
+ updated;
535
+ if (vnode.properties && vnode.properties.afterUpdate) {
536
+ vnode.properties.afterUpdate.apply(vnode.properties.bind || vnode.properties, [
537
+ domNode,
538
+ projectionOptions,
539
+ vnode.vnodeSelector,
540
+ vnode.properties,
541
+ vnode.children,
542
+ ]);
543
+ }
544
+ }
545
+ if (updated && vnode.properties && vnode.properties.updateAnimation) {
546
+ vnode.properties.updateAnimation(domNode, vnode.properties, previous.properties);
547
+ }
548
+ return textUpdated;
549
+ };
550
+ var createProjection = function (vnode, projectionOptions) {
551
+ return {
552
+ getLastRender: function () { return vnode; },
553
+ update: function (updatedVnode) {
554
+ if (vnode.vnodeSelector !== updatedVnode.vnodeSelector) {
555
+ throw new Error("The selector for the root VNode may not be changed. (consider using dom.merge and add one extra level to the virtual DOM)");
556
+ }
557
+ var previousVNode = vnode;
558
+ vnode = updatedVnode;
559
+ updateDom(previousVNode, updatedVnode, projectionOptions);
560
+ },
561
+ domNode: vnode.domNode,
562
+ };
545
563
  };
546
564
 
547
- var DEFAULT_PROJECTION_OPTIONS = {
548
- namespace: undefined,
549
- performanceLogger: function () { return undefined; },
550
- eventHandlerInterceptor: undefined,
551
- styleApplyer: function (domNode, styleName, value) {
552
- if (styleName.charAt(0) === "-") {
553
- // CSS variables must be set using setProperty
554
- domNode.style.setProperty(styleName, value);
555
- }
556
- else {
557
- // properties like 'backgroundColor' must be set as a js-property
558
- domNode.style[styleName] = value;
559
- }
560
- },
561
- };
562
- var applyDefaultProjectionOptions = function (projectorOptions) {
563
- return extend(DEFAULT_PROJECTION_OPTIONS, projectorOptions);
564
- };
565
- var dom = {
566
- /**
567
- * Creates a real DOM tree from `vnode`. The [[Projection]] object returned will contain the resulting DOM Node in
568
- * its [[Projection.domNode|domNode]] property.
569
- * This is a low-level method. Users will typically use a [[Projector]] instead.
570
- * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]]
571
- * objects may only be rendered once.
572
- * @param projectionOptions - Options to be used to create and update the projection.
573
- * @returns The [[Projection]] which also contains the DOM Node that was created.
574
- */
575
- create: function (vnode, projectionOptions) {
576
- projectionOptions = applyDefaultProjectionOptions(projectionOptions);
577
- createDom(vnode, document.createElement("div"), undefined, projectionOptions);
578
- return createProjection(vnode, projectionOptions);
579
- },
580
- /**
581
- * Appends a new child node to the DOM which is generated from a [[VNode]].
582
- * This is a low-level method. Users will typically use a [[Projector]] instead.
583
- * @param parentNode - The parent node for the new child node.
584
- * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]]
585
- * objects may only be rendered once.
586
- * @param projectionOptions - Options to be used to create and update the [[Projection]].
587
- * @returns The [[Projection]] that was created.
588
- */
589
- append: function (parentNode, vnode, projectionOptions) {
590
- projectionOptions = applyDefaultProjectionOptions(projectionOptions);
591
- createDom(vnode, parentNode, undefined, projectionOptions);
592
- return createProjection(vnode, projectionOptions);
593
- },
594
- /**
595
- * Inserts a new DOM node which is generated from a [[VNode]].
596
- * This is a low-level method. Users wil typically use a [[Projector]] instead.
597
- * @param beforeNode - The node that the DOM Node is inserted before.
598
- * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function.
599
- * NOTE: [[VNode]] objects may only be rendered once.
600
- * @param projectionOptions - Options to be used to create and update the projection, see [[createProjector]].
601
- * @returns The [[Projection]] that was created.
602
- */
603
- insertBefore: function (beforeNode, vnode, projectionOptions) {
604
- projectionOptions = applyDefaultProjectionOptions(projectionOptions);
605
- createDom(vnode, beforeNode.parentNode, beforeNode, projectionOptions);
606
- return createProjection(vnode, projectionOptions);
607
- },
608
- /**
609
- * Merges a new DOM node which is generated from a [[VNode]] with an existing DOM Node.
610
- * This means that the virtual DOM and the real DOM will have one overlapping element.
611
- * Therefore the selector for the root [[VNode]] will be ignored, but its properties and children will be applied to the Element provided.
612
- * This is a low-level method. Users wil typically use a [[Projector]] instead.
613
- * @param element - The existing element to adopt as the root of the new virtual DOM. Existing attributes and child nodes are preserved.
614
- * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]] objects
615
- * may only be rendered once.
616
- * @param projectionOptions - Options to be used to create and update the projection, see [[createProjector]].
617
- * @returns The [[Projection]] that was created.
618
- */
619
- merge: function (element, vnode, projectionOptions) {
620
- projectionOptions = applyDefaultProjectionOptions(projectionOptions);
621
- vnode.domNode = element;
622
- initPropertiesAndChildren(element, vnode, projectionOptions);
623
- return createProjection(vnode, projectionOptions);
624
- },
625
- /**
626
- * Replaces an existing DOM node with a node generated from a [[VNode]].
627
- * This is a low-level method. Users will typically use a [[Projector]] instead.
628
- * @param element - The node for the [[VNode]] to replace.
629
- * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]]
630
- * objects may only be rendered once.
631
- * @param projectionOptions - Options to be used to create and update the [[Projection]].
632
- * @returns The [[Projection]] that was created.
633
- */
634
- replace: function (element, vnode, projectionOptions) {
635
- projectionOptions = applyDefaultProjectionOptions(projectionOptions);
636
- createDom(vnode, element.parentNode, element, projectionOptions);
637
- element.parentNode.removeChild(element);
638
- return createProjection(vnode, projectionOptions);
639
- },
565
+ var DEFAULT_PROJECTION_OPTIONS = {
566
+ namespace: undefined,
567
+ performanceLogger: function () { return undefined; },
568
+ eventHandlerInterceptor: undefined,
569
+ styleApplyer: function (domNode, styleName, value) {
570
+ if (styleName.charAt(0) === "-") {
571
+ // CSS variables must be set using setProperty
572
+ domNode.style.setProperty(styleName, value);
573
+ }
574
+ else {
575
+ // properties like 'backgroundColor' must be set as a js-property
576
+ domNode.style[styleName] = value;
577
+ }
578
+ },
579
+ };
580
+ var applyDefaultProjectionOptions = function (projectorOptions) {
581
+ return extend(DEFAULT_PROJECTION_OPTIONS, projectorOptions);
582
+ };
583
+ var dom = {
584
+ /**
585
+ * Creates a real DOM tree from `vnode`. The [[Projection]] object returned will contain the resulting DOM Node in
586
+ * its [[Projection.domNode|domNode]] property.
587
+ * This is a low-level method. Users will typically use a [[Projector]] instead.
588
+ * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]]
589
+ * objects may only be rendered once.
590
+ * @param projectionOptions - Options to be used to create and update the projection.
591
+ * @returns The [[Projection]] which also contains the DOM Node that was created.
592
+ */
593
+ create: function (vnode, projectionOptions) {
594
+ projectionOptions = applyDefaultProjectionOptions(projectionOptions);
595
+ createDom(vnode, document.createElement("div"), undefined, projectionOptions);
596
+ return createProjection(vnode, projectionOptions);
597
+ },
598
+ /**
599
+ * Appends a new child node to the DOM which is generated from a [[VNode]].
600
+ * This is a low-level method. Users will typically use a [[Projector]] instead.
601
+ * @param parentNode - The parent node for the new child node.
602
+ * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]]
603
+ * objects may only be rendered once.
604
+ * @param projectionOptions - Options to be used to create and update the [[Projection]].
605
+ * @returns The [[Projection]] that was created.
606
+ */
607
+ append: function (parentNode, vnode, projectionOptions) {
608
+ projectionOptions = applyDefaultProjectionOptions(projectionOptions);
609
+ createDom(vnode, parentNode, undefined, projectionOptions);
610
+ return createProjection(vnode, projectionOptions);
611
+ },
612
+ /**
613
+ * Inserts a new DOM node which is generated from a [[VNode]].
614
+ * This is a low-level method. Users wil typically use a [[Projector]] instead.
615
+ * @param beforeNode - The node that the DOM Node is inserted before.
616
+ * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function.
617
+ * NOTE: [[VNode]] objects may only be rendered once.
618
+ * @param projectionOptions - Options to be used to create and update the projection, see [[createProjector]].
619
+ * @returns The [[Projection]] that was created.
620
+ */
621
+ insertBefore: function (beforeNode, vnode, projectionOptions) {
622
+ projectionOptions = applyDefaultProjectionOptions(projectionOptions);
623
+ createDom(vnode, beforeNode.parentNode, beforeNode, projectionOptions);
624
+ return createProjection(vnode, projectionOptions);
625
+ },
626
+ /**
627
+ * Merges a new DOM node which is generated from a [[VNode]] with an existing DOM Node.
628
+ * This means that the virtual DOM and the real DOM will have one overlapping element.
629
+ * Therefore the selector for the root [[VNode]] will be ignored, but its properties and children will be applied to the Element provided.
630
+ * This is a low-level method. Users wil typically use a [[Projector]] instead.
631
+ * @param element - The existing element to adopt as the root of the new virtual DOM. Existing attributes and child nodes are preserved.
632
+ * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]] objects
633
+ * may only be rendered once.
634
+ * @param projectionOptions - Options to be used to create and update the projection, see [[createProjector]].
635
+ * @returns The [[Projection]] that was created.
636
+ */
637
+ merge: function (element, vnode, projectionOptions) {
638
+ projectionOptions = applyDefaultProjectionOptions(projectionOptions);
639
+ vnode.domNode = element;
640
+ initPropertiesAndChildren(element, vnode, projectionOptions);
641
+ return createProjection(vnode, projectionOptions);
642
+ },
643
+ /**
644
+ * Replaces an existing DOM node with a node generated from a [[VNode]].
645
+ * This is a low-level method. Users will typically use a [[Projector]] instead.
646
+ * @param element - The node for the [[VNode]] to replace.
647
+ * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]]
648
+ * objects may only be rendered once.
649
+ * @param projectionOptions - Options to be used to create and update the [[Projection]].
650
+ * @returns The [[Projection]] that was created.
651
+ */
652
+ replace: function (element, vnode, projectionOptions) {
653
+ projectionOptions = applyDefaultProjectionOptions(projectionOptions);
654
+ createDom(vnode, element.parentNode, element, projectionOptions);
655
+ element.parentNode.removeChild(element);
656
+ return createProjection(vnode, projectionOptions);
657
+ },
640
658
  };
641
659
 
642
- var toTextVNode = function (data) {
643
- return {
644
- vnodeSelector: "",
645
- properties: undefined,
646
- children: undefined,
647
- text: data.toString(),
648
- domNode: null,
649
- };
650
- };
651
- var appendChildren = function (parentSelector, insertions, main) {
652
- for (var i = 0, length_1 = insertions.length; i < length_1; i++) {
653
- var item = insertions[i];
654
- if (Array.isArray(item)) {
655
- appendChildren(parentSelector, item, main);
656
- }
657
- else {
658
- if (item !== null && item !== undefined && item !== false) {
659
- if (typeof item === "string") {
660
- item = toTextVNode(item);
661
- }
662
- main.push(item);
663
- }
664
- }
665
- }
666
- };
667
- function h(selector, properties, children) {
668
- if (Array.isArray(properties)) {
669
- children = properties;
670
- properties = undefined;
671
- }
672
- else if ((properties && (typeof properties === "string" || properties.vnodeSelector)) ||
673
- (children && (typeof children === "string" || children.vnodeSelector))) {
674
- throw new Error("h called with invalid arguments");
675
- }
676
- var text;
677
- var flattenedChildren;
678
- // Recognize a common special case where there is only a single text node
679
- if (children && children.length === 1 && typeof children[0] === "string") {
680
- text = children[0];
681
- }
682
- else if (children) {
683
- flattenedChildren = [];
684
- appendChildren(selector, children, flattenedChildren);
685
- if (flattenedChildren.length === 0) {
686
- flattenedChildren = undefined;
687
- }
688
- }
689
- return {
690
- vnodeSelector: selector,
691
- properties: properties,
692
- children: flattenedChildren,
693
- text: text === "" ? undefined : text,
694
- domNode: null,
695
- };
660
+ var toTextVNode = function (data) {
661
+ return {
662
+ vnodeSelector: "",
663
+ properties: undefined,
664
+ children: undefined,
665
+ text: data.toString(),
666
+ domNode: null,
667
+ };
668
+ };
669
+ var appendChildren = function (parentSelector, insertions, main) {
670
+ for (var i = 0, length_1 = insertions.length; i < length_1; i++) {
671
+ var item = insertions[i];
672
+ if (Array.isArray(item)) {
673
+ appendChildren(parentSelector, item, main);
674
+ }
675
+ else {
676
+ if (item !== null && item !== undefined && item !== false) {
677
+ if (typeof item === "string") {
678
+ item = toTextVNode(item);
679
+ }
680
+ main.push(item);
681
+ }
682
+ }
683
+ }
684
+ };
685
+ function h(selector, properties, children) {
686
+ if (Array.isArray(properties)) {
687
+ children = properties;
688
+ properties = undefined;
689
+ }
690
+ else if ((properties && (typeof properties === "string" || properties.vnodeSelector)) ||
691
+ (children && (typeof children === "string" || children.vnodeSelector))) {
692
+ throw new Error("h called with invalid arguments");
693
+ }
694
+ var text;
695
+ var flattenedChildren;
696
+ // Recognize a common special case where there is only a single text node
697
+ if (children && children.length === 1 && typeof children[0] === "string") {
698
+ text = children[0];
699
+ }
700
+ else if (children) {
701
+ flattenedChildren = [];
702
+ appendChildren(selector, children, flattenedChildren);
703
+ if (flattenedChildren.length === 0) {
704
+ flattenedChildren = undefined;
705
+ }
706
+ }
707
+ return {
708
+ vnodeSelector: selector,
709
+ properties: properties,
710
+ children: flattenedChildren,
711
+ text: text === "" ? undefined : text,
712
+ domNode: null,
713
+ };
696
714
  }
697
715
 
698
- var createParentNodePath = function (node, rootNode) {
699
- var parentNodePath = [];
700
- while (node && node !== rootNode) {
701
- parentNodePath.push(node);
702
- node = node.parentNode;
703
- }
704
- return parentNodePath;
705
- };
706
- var find;
707
- if (Array.prototype.find) {
708
- find = function (items, predicate) { return items.find(predicate); };
709
- }
710
- else {
711
- find = function (items, predicate) { return items.filter(predicate)[0]; };
712
- }
713
- var findVNodeByParentNodePath = function (vnode, parentNodePath) {
714
- var result = vnode;
715
- parentNodePath.forEach(function (node) {
716
- result =
717
- result && result.children
718
- ? find(result.children, function (child) { return child.domNode === node; })
719
- : undefined;
720
- });
721
- return result;
722
- };
723
- var createEventHandlerInterceptor = function (projector, getProjection, performanceLogger) {
724
- return function (propertyName, eventHandler, domNode, properties) { return modifiedEventHandler; };
725
- function modifiedEventHandler(evt) {
726
- performanceLogger("domEvent", evt);
727
- var projection = getProjection();
728
- var parentNodePath = createParentNodePath(evt.currentTarget, projection.domNode);
729
- parentNodePath.reverse();
730
- var matchingVNode = findVNodeByParentNodePath(projection.getLastRender(), parentNodePath);
731
- projector.scheduleRender();
732
- var result;
733
- if (matchingVNode) {
734
- /* eslint-disable prefer-rest-params */
735
- result = matchingVNode.properties["on".concat(evt.type)].apply(matchingVNode.properties.bind || this, arguments);
736
- /* eslint-enable prefer-rest-params */
737
- }
738
- performanceLogger("domEventProcessed", evt);
739
- return result;
740
- }
741
- };
742
- /**
743
- * Creates a [[Projector]] instance using the provided projectionOptions.
744
- *
745
- * For more information, see [[Projector]].
746
- *
747
- * @param projectorOptions Options that influence how the DOM is rendered and updated.
748
- */
749
- var createProjector = function (projectorOptions) {
750
- var projector;
751
- var projectionOptions = applyDefaultProjectionOptions(projectorOptions);
752
- var performanceLogger = projectionOptions.performanceLogger;
753
- var renderCompleted = true;
754
- var scheduled;
755
- var stopped = false;
756
- var projections = [];
757
- var renderFunctions = []; // matches the projections array
758
- var addProjection = function (
759
- /* one of: dom.append, dom.insertBefore, dom.replace, dom.merge */
760
- domFunction,
761
- /* the parameter of the domFunction */
762
- node, renderFunction) {
763
- var projection;
764
- var getProjection = function () { return projection; };
765
- projectionOptions.eventHandlerInterceptor = createEventHandlerInterceptor(projector, getProjection, performanceLogger);
766
- projection = domFunction(node, renderFunction(), projectionOptions);
767
- projections.push(projection);
768
- renderFunctions.push(renderFunction);
769
- };
770
- var doRender = function () {
771
- scheduled = undefined;
772
- if (!renderCompleted) {
773
- return; // The last render threw an error, it should have been logged in the browser console.
774
- }
775
- renderCompleted = false;
776
- performanceLogger("renderStart", undefined);
777
- for (var i = 0; i < projections.length; i++) {
778
- var updatedVnode = renderFunctions[i]();
779
- performanceLogger("rendered", undefined);
780
- projections[i].update(updatedVnode);
781
- performanceLogger("patched", undefined);
782
- }
783
- performanceLogger("renderDone", undefined);
784
- renderCompleted = true;
785
- };
786
- projector = {
787
- renderNow: doRender,
788
- scheduleRender: function () {
789
- if (!scheduled && !stopped) {
790
- scheduled = requestAnimationFrame(doRender);
791
- }
792
- },
793
- stop: function () {
794
- if (scheduled) {
795
- cancelAnimationFrame(scheduled);
796
- scheduled = undefined;
797
- }
798
- stopped = true;
799
- },
800
- resume: function () {
801
- stopped = false;
802
- renderCompleted = true;
803
- projector.scheduleRender();
804
- },
805
- append: function (parentNode, renderFunction) {
806
- addProjection(dom.append, parentNode, renderFunction);
807
- },
808
- insertBefore: function (beforeNode, renderFunction) {
809
- addProjection(dom.insertBefore, beforeNode, renderFunction);
810
- },
811
- merge: function (domNode, renderFunction) {
812
- addProjection(dom.merge, domNode, renderFunction);
813
- },
814
- replace: function (domNode, renderFunction) {
815
- addProjection(dom.replace, domNode, renderFunction);
816
- },
817
- detach: function (renderFunction) {
818
- for (var i = 0; i < renderFunctions.length; i++) {
819
- if (renderFunctions[i] === renderFunction) {
820
- renderFunctions.splice(i, 1);
821
- return projections.splice(i, 1)[0];
822
- }
823
- }
824
- throw new Error("renderFunction was not found");
825
- },
826
- };
827
- return projector;
716
+ var createParentNodePath = function (node, rootNode) {
717
+ var parentNodePath = [];
718
+ while (node && node !== rootNode) {
719
+ parentNodePath.push(node);
720
+ node = node.parentNode;
721
+ }
722
+ return parentNodePath;
723
+ };
724
+ var find;
725
+ if (Array.prototype.find) {
726
+ find = function (items, predicate) { return items.find(predicate); };
727
+ }
728
+ else {
729
+ find = function (items, predicate) { return items.filter(predicate)[0]; };
730
+ }
731
+ var findVNodeByParentNodePath = function (vnode, parentNodePath) {
732
+ var result = vnode;
733
+ parentNodePath.forEach(function (node) {
734
+ result =
735
+ result && result.children
736
+ ? find(result.children, function (child) { return child.domNode === node; })
737
+ : undefined;
738
+ });
739
+ return result;
740
+ };
741
+ var createEventHandlerInterceptor = function (projector, getProjection, performanceLogger) {
742
+ return function (propertyName, eventHandler, domNode, properties) { return modifiedEventHandler; };
743
+ function modifiedEventHandler(evt) {
744
+ var _a, _b;
745
+ performanceLogger("domEvent", evt);
746
+ var projection = getProjection();
747
+ var parentNodePath = createParentNodePath(evt.currentTarget, projection.domNode);
748
+ parentNodePath.reverse();
749
+ var matchingVNode = findVNodeByParentNodePath(projection.getLastRender(), parentNodePath);
750
+ projector.scheduleRender();
751
+ var result;
752
+ if (matchingVNode) {
753
+ /* eslint-disable prefer-rest-params */
754
+ var listener = (_b = (_a = matchingVNode.properties["on".concat(evt.type)]) !== null && _a !== void 0 ? _a : matchingVNode.properties.on[evt.type].listener) !== null && _b !== void 0 ? _b : matchingVNode.properties.on[evt.type];
755
+ result = listener.apply(matchingVNode.properties.bind || this, arguments);
756
+ /* eslint-enable prefer-rest-params */
757
+ }
758
+ performanceLogger("domEventProcessed", evt);
759
+ return result;
760
+ }
761
+ };
762
+ /**
763
+ * Creates a [[Projector]] instance using the provided projectionOptions.
764
+ *
765
+ * For more information, see [[Projector]].
766
+ *
767
+ * @param projectorOptions Options that influence how the DOM is rendered and updated.
768
+ */
769
+ var createProjector = function (projectorOptions) {
770
+ var projector;
771
+ var projectionOptions = applyDefaultProjectionOptions(projectorOptions);
772
+ var performanceLogger = projectionOptions.performanceLogger;
773
+ var renderCompleted = true;
774
+ var scheduled;
775
+ var stopped = false;
776
+ var projections = [];
777
+ var renderFunctions = []; // matches the projections array
778
+ var addProjection = function (
779
+ /* one of: dom.append, dom.insertBefore, dom.replace, dom.merge */
780
+ domFunction,
781
+ /* the parameter of the domFunction */
782
+ node, renderFunction) {
783
+ var projection;
784
+ var getProjection = function () { return projection; };
785
+ projectionOptions.eventHandlerInterceptor = createEventHandlerInterceptor(projector, getProjection, performanceLogger);
786
+ projection = domFunction(node, renderFunction(), projectionOptions);
787
+ projections.push(projection);
788
+ renderFunctions.push(renderFunction);
789
+ };
790
+ var doRender = function () {
791
+ scheduled = undefined;
792
+ if (!renderCompleted) {
793
+ return; // The last render threw an error, it should have been logged in the browser console.
794
+ }
795
+ renderCompleted = false;
796
+ performanceLogger("renderStart", undefined);
797
+ for (var i = 0; i < projections.length; i++) {
798
+ var updatedVnode = renderFunctions[i]();
799
+ performanceLogger("rendered", undefined);
800
+ projections[i].update(updatedVnode);
801
+ performanceLogger("patched", undefined);
802
+ }
803
+ performanceLogger("renderDone", undefined);
804
+ renderCompleted = true;
805
+ };
806
+ projector = {
807
+ renderNow: doRender,
808
+ scheduleRender: function () {
809
+ if (!scheduled && !stopped) {
810
+ scheduled = requestAnimationFrame(doRender);
811
+ }
812
+ },
813
+ stop: function () {
814
+ if (scheduled) {
815
+ cancelAnimationFrame(scheduled);
816
+ scheduled = undefined;
817
+ }
818
+ stopped = true;
819
+ },
820
+ resume: function () {
821
+ stopped = false;
822
+ renderCompleted = true;
823
+ projector.scheduleRender();
824
+ },
825
+ append: function (parentNode, renderFunction) {
826
+ addProjection(dom.append, parentNode, renderFunction);
827
+ },
828
+ insertBefore: function (beforeNode, renderFunction) {
829
+ addProjection(dom.insertBefore, beforeNode, renderFunction);
830
+ },
831
+ merge: function (domNode, renderFunction) {
832
+ addProjection(dom.merge, domNode, renderFunction);
833
+ },
834
+ replace: function (domNode, renderFunction) {
835
+ addProjection(dom.replace, domNode, renderFunction);
836
+ },
837
+ detach: function (renderFunction) {
838
+ for (var i = 0; i < renderFunctions.length; i++) {
839
+ if (renderFunctions[i] === renderFunction) {
840
+ renderFunctions.splice(i, 1);
841
+ return projections.splice(i, 1)[0];
842
+ }
843
+ }
844
+ throw new Error("renderFunction was not found");
845
+ },
846
+ };
847
+ return projector;
828
848
  };
829
849
 
830
- /**
831
- * Creates a [[CalculationCache]] object, useful for caching [[VNode]] trees.
832
- * In practice, caching of [[VNode]] trees is not needed, because achieving 60 frames per second is almost never a problem.
833
- * For more information, see [[CalculationCache]].
834
- *
835
- * @param <Result> The type of the value that is cached.
836
- */
837
- var createCache = function () {
838
- var cachedInputs;
839
- var cachedOutcome;
840
- return {
841
- invalidate: function () {
842
- cachedOutcome = undefined;
843
- cachedInputs = undefined;
844
- },
845
- result: function (inputs, calculation) {
846
- if (cachedInputs) {
847
- for (var i = 0; i < inputs.length; i++) {
848
- if (cachedInputs[i] !== inputs[i]) {
849
- cachedOutcome = undefined;
850
- }
851
- }
852
- }
853
- if (!cachedOutcome) {
854
- cachedOutcome = calculation();
855
- cachedInputs = inputs;
856
- }
857
- return cachedOutcome;
858
- },
859
- };
850
+ /**
851
+ * Creates a [[CalculationCache]] object, useful for caching [[VNode]] trees.
852
+ * In practice, caching of [[VNode]] trees is not needed, because achieving 60 frames per second is almost never a problem.
853
+ * For more information, see [[CalculationCache]].
854
+ *
855
+ * @param <Result> The type of the value that is cached.
856
+ */
857
+ var createCache = function () {
858
+ var cachedInputs;
859
+ var cachedOutcome;
860
+ return {
861
+ invalidate: function () {
862
+ cachedOutcome = undefined;
863
+ cachedInputs = undefined;
864
+ },
865
+ result: function (inputs, calculation) {
866
+ if (cachedInputs) {
867
+ for (var i = 0; i < inputs.length; i++) {
868
+ if (cachedInputs[i] !== inputs[i]) {
869
+ cachedOutcome = undefined;
870
+ }
871
+ }
872
+ }
873
+ if (!cachedOutcome) {
874
+ cachedOutcome = calculation();
875
+ cachedInputs = inputs;
876
+ }
877
+ return cachedOutcome;
878
+ },
879
+ };
860
880
  };
861
881
 
862
- /**
863
- * Creates a {@link Mapping} instance that keeps an array of result objects synchronized with an array of source objects.
864
- * See {@link http://maquettejs.org/docs/arrays.html|Working with arrays}.
865
- *
866
- * @param <Source> The type of source items. A database-record for instance.
867
- * @param <Target> The type of target items. A [[MaquetteComponent]] for instance.
868
- * @param getSourceKey `function(source)` that must return a key to identify each source object. The result must either be a string or a number.
869
- * @param createResult `function(source, index)` that must create a new result object from a given source. This function is identical
870
- * to the `callback` argument in `Array.map(callback)`.
871
- * @param updateResult `function(source, target, index)` that updates a result to an updated source.
872
- */
873
- var createMapping = function (getSourceKey, createResult, updateResult) {
874
- var keys = [];
875
- var results = [];
876
- return {
877
- results: results,
878
- map: function (newSources) {
879
- var newKeys = newSources.map(getSourceKey);
880
- var oldTargets = results.slice();
881
- var oldIndex = 0;
882
- for (var i = 0; i < newSources.length; i++) {
883
- var source = newSources[i];
884
- var sourceKey = newKeys[i];
885
- if (sourceKey === keys[oldIndex]) {
886
- results[i] = oldTargets[oldIndex];
887
- updateResult(source, oldTargets[oldIndex], i);
888
- oldIndex++;
889
- }
890
- else {
891
- var found = false;
892
- for (var j = 1; j < keys.length + 1; j++) {
893
- var searchIndex = (oldIndex + j) % keys.length;
894
- if (keys[searchIndex] === sourceKey) {
895
- results[i] = oldTargets[searchIndex];
896
- updateResult(newSources[i], oldTargets[searchIndex], i);
897
- oldIndex = searchIndex + 1;
898
- found = true;
899
- break;
900
- }
901
- }
902
- if (!found) {
903
- results[i] = createResult(source, i);
904
- }
905
- }
906
- }
907
- results.length = newSources.length;
908
- keys = newKeys;
909
- },
910
- };
882
+ /**
883
+ * Creates a {@link Mapping} instance that keeps an array of result objects synchronized with an array of source objects.
884
+ * See {@link http://maquettejs.org/docs/arrays.html Working with arrays}.
885
+ *
886
+ * @param <Source> The type of source items. A database-record for instance.
887
+ * @param <Target> The type of target items. A [[MaquetteComponent]] for instance.
888
+ * @param getSourceKey `function(source)` that must return a key to identify each source object. The result must either be a string or a number.
889
+ * @param createResult `function(source, index)` that must create a new result object from a given source. This function is identical
890
+ * to the `callback` argument in `Array.map(callback)`.
891
+ * @param updateResult `function(source, target, index)` that updates a result to an updated source.
892
+ */
893
+ var createMapping = function (getSourceKey, createResult, updateResult) {
894
+ var keys = [];
895
+ var results = [];
896
+ return {
897
+ results: results,
898
+ map: function (newSources) {
899
+ var newKeys = newSources.map(getSourceKey);
900
+ var oldTargets = results.slice();
901
+ var oldIndex = 0;
902
+ for (var i = 0; i < newSources.length; i++) {
903
+ var source = newSources[i];
904
+ var sourceKey = newKeys[i];
905
+ if (sourceKey === keys[oldIndex]) {
906
+ results[i] = oldTargets[oldIndex];
907
+ updateResult(source, oldTargets[oldIndex], i);
908
+ oldIndex++;
909
+ }
910
+ else {
911
+ var found = false;
912
+ for (var j = 1; j < keys.length + 1; j++) {
913
+ var searchIndex = (oldIndex + j) % keys.length;
914
+ if (keys[searchIndex] === sourceKey) {
915
+ results[i] = oldTargets[searchIndex];
916
+ updateResult(newSources[i], oldTargets[searchIndex], i);
917
+ oldIndex = searchIndex + 1;
918
+ found = true;
919
+ break;
920
+ }
921
+ }
922
+ if (!found) {
923
+ results[i] = createResult(source, i);
924
+ }
925
+ }
926
+ }
927
+ results.length = newSources.length;
928
+ keys = newKeys;
929
+ },
930
+ };
911
931
  };
912
932
 
913
933
  exports.createCache = createCache;
@@ -916,6 +936,4 @@
916
936
  exports.dom = dom;
917
937
  exports.h = h;
918
938
 
919
- Object.defineProperty(exports, '__esModule', { value: true });
920
-
921
939
  }));