neo.mjs 9.16.0 → 10.0.0-alpha.2

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.
Files changed (73) hide show
  1. package/README.md +127 -121
  2. package/ServiceWorker.mjs +2 -2
  3. package/apps/email/view/Viewport.mjs +2 -2
  4. package/apps/form/view/Viewport.mjs +1 -1
  5. package/apps/portal/index.html +1 -1
  6. package/apps/portal/view/examples/List.mjs +1 -1
  7. package/apps/portal/view/home/FooterContainer.mjs +1 -1
  8. package/apps/realworld2/view/HomeContainer.mjs +1 -1
  9. package/apps/route/view/center/CardAdministration.mjs +3 -3
  10. package/apps/route/view/center/CardAdministrationDenied.mjs +2 -2
  11. package/apps/route/view/center/CardContact.mjs +2 -2
  12. package/apps/route/view/center/CardHome.mjs +2 -2
  13. package/apps/route/view/center/CardSection1.mjs +2 -2
  14. package/apps/route/view/center/CardSection2.mjs +2 -2
  15. package/buildScripts/createApp.mjs +2 -2
  16. package/docs/app/view/classdetails/HeaderComponent.mjs +3 -3
  17. package/docs/app/view/classdetails/MembersList.mjs +43 -46
  18. package/docs/app/view/classdetails/SourceViewComponent.mjs +1 -1
  19. package/docs/app/view/classdetails/TutorialComponent.mjs +1 -1
  20. package/examples/component/toast/MainContainer.mjs +16 -16
  21. package/examples/component/wrapper/googleMaps/MarkerDialog.mjs +4 -4
  22. package/examples/fields/MainContainer.mjs +1 -1
  23. package/examples/panel/MainContainer.mjs +2 -2
  24. package/examples/tab/container/MainContainer.mjs +3 -3
  25. package/examples/tabs/MainContainer.mjs +2 -2
  26. package/examples/tabs/MainContainer2.mjs +3 -3
  27. package/examples/viewport/MainContainer.mjs +2 -2
  28. package/package.json +33 -5
  29. package/resources/data/deck/learnneo/pages/benefits/FourEnvironments.md +1 -1
  30. package/resources/data/deck/learnneo/pages/benefits/Introduction.md +4 -3
  31. package/resources/data/deck/learnneo/pages/guides/events/DomEvents.md +5 -5
  32. package/resources/data/deck/training/pages/2022-12-27T21-55-23-144Z.md +2 -2
  33. package/resources/data/deck/training/pages/2022-12-29T18-36-08-226Z.md +1 -1
  34. package/resources/data/deck/training/pages/2022-12-29T18-36-56-893Z.md +2 -2
  35. package/resources/data/deck/training/pages/2022-12-29T20-37-08-919Z.md +2 -2
  36. package/resources/data/deck/training/pages/2022-12-29T20-37-20-344Z.md +2 -2
  37. package/resources/data/deck/training/pages/2023-01-13T21-48-17-258Z.md +2 -2
  38. package/resources/data/deck/training/pages/2023-02-05T17-44-53-815Z.md +9 -9
  39. package/resources/data/deck/training/pages/2023-10-14T19-25-08-153Z.md +1 -1
  40. package/src/DefaultConfig.mjs +14 -2
  41. package/src/Main.mjs +15 -6
  42. package/src/button/Base.mjs +1 -1
  43. package/src/calendar/view/calendars/List.mjs +1 -1
  44. package/src/component/Base.mjs +11 -11
  45. package/src/component/Chip.mjs +1 -1
  46. package/src/component/Helix.mjs +3 -3
  47. package/src/component/Process.mjs +2 -2
  48. package/src/component/StatusBadge.mjs +2 -2
  49. package/src/component/Timer.mjs +1 -1
  50. package/src/component/Toast.mjs +2 -2
  51. package/src/container/Base.mjs +1 -1
  52. package/src/form/field/CheckBox.mjs +2 -2
  53. package/src/form/field/FileUpload.mjs +14 -14
  54. package/src/form/field/Range.mjs +1 -1
  55. package/src/form/field/Text.mjs +1 -1
  56. package/src/form/field/trigger/Base.mjs +2 -2
  57. package/src/form/field/trigger/SpinUpDown.mjs +2 -2
  58. package/src/grid/View.mjs +1 -1
  59. package/src/main/DeltaUpdates.mjs +442 -0
  60. package/src/main/DomAccess.mjs +13 -95
  61. package/src/main/render/DomApiRenderer.mjs +138 -0
  62. package/src/main/render/StringBasedRenderer.mjs +58 -0
  63. package/src/table/View.mjs +1 -1
  64. package/src/table/plugin/CellEditing.mjs +1 -1
  65. package/src/tree/Accordion.mjs +11 -11
  66. package/src/tree/List.mjs +12 -5
  67. package/src/vdom/Helper.mjs +179 -309
  68. package/src/vdom/VNode.mjs +47 -11
  69. package/src/vdom/domConstants.mjs +65 -0
  70. package/src/vdom/util/DomApiVnodeCreator.mjs +51 -0
  71. package/src/vdom/util/StringFromVnode.mjs +123 -0
  72. package/src/worker/mixin/RemoteMethodAccess.mjs +13 -1
  73. package/src/main/mixin/DeltaUpdates.mjs +0 -352
@@ -0,0 +1,442 @@
1
+ import Base from '../core/Base.mjs';
2
+ import DomAccess from './DomAccess.mjs';
3
+ import {voidAttributes} from '../vdom/domConstants.mjs';
4
+
5
+ const NeoConfig = Neo.config;
6
+
7
+ /**
8
+ * Logic to apply the deltas generated by vdom.Helper to the real DOM
9
+ * @class Neo.main.DeltaUpdates
10
+ * @extends Neo.core.Base
11
+ * @singleton
12
+ */
13
+ class DeltaUpdates extends Base {
14
+ static config = {
15
+ /**
16
+ * @member {String} className='Neo.main.DeltaUpdates'
17
+ * @protected
18
+ */
19
+ className: 'Neo.main.DeltaUpdates',
20
+ /**
21
+ * @member {Number} countDeltas=0
22
+ * @protected
23
+ */
24
+ countDeltas: 0,
25
+ /**
26
+ * @member {Number} countDeltasPer250ms=0
27
+ * @protected
28
+ */
29
+ countDeltasPer250ms: 0,
30
+ /**
31
+ * @member {Number} countUpdates=0
32
+ * @protected
33
+ */
34
+ countUpdates: 0,
35
+ /**
36
+ * @member {Boolean} renderCountDeltas_=false
37
+ * @protected
38
+ */
39
+ renderCountDeltas_: false,
40
+ /**
41
+ * @member {Boolean} singleton=true
42
+ */
43
+ singleton: true
44
+ }
45
+
46
+ /**
47
+ * @member {Number} logDeltasIntervalId=0
48
+ * @protected
49
+ */
50
+ logDeltasIntervalId = 0
51
+ /**
52
+ * Private property to store the dynamically loaded renderer module.
53
+ * @member {Neo.main.render.DomApiRenderer|Neo.main.render.DomApiRenderer|null} #renderer=null
54
+ * @private
55
+ */
56
+ #renderer = null
57
+
58
+ /**
59
+ * Private property to signal that the renderer module has been loaded.
60
+ * This will be a Promise that resolves when the module is ready.
61
+ * @private
62
+ * @member {Promise<void>|null} #_readyPromise
63
+ */
64
+ #_readyPromise = null
65
+
66
+ /**
67
+ * @param {Object} config
68
+ */
69
+ construct(config) {
70
+ super.construct(config);
71
+
72
+ let me = this;
73
+
74
+ if (Neo.config.renderCountDeltas) {
75
+ me.renderCountDeltas = true
76
+ }
77
+
78
+ // Initiate the asynchronous loading of the renderer here.
79
+ me.#_readyPromise = (async () => {
80
+ try {
81
+ let module;
82
+
83
+ if (NeoConfig.useStringBasedMounting) {
84
+ module = await import('./render/StringBasedRenderer.mjs')
85
+ } else {
86
+ module = await import('./render/DomApiRenderer.mjs')
87
+ }
88
+
89
+ me.#renderer = module.default
90
+ } catch (err) {
91
+ console.error('DeltaUpdates: Failed to load renderer module:', err);
92
+ throw err // Re-throw to propagate initialization failures
93
+ }
94
+ })()
95
+ }
96
+
97
+ /**
98
+ * Triggered after the renderCountDeltas config got changed
99
+ * @param {Boolean} value
100
+ * @param {Boolean} oldValue
101
+ * @protected
102
+ */
103
+ afterSetRenderCountDeltas(value, oldValue) {
104
+ let me = this,
105
+ {logDeltasIntervalId} = me,
106
+ node;
107
+
108
+ if (value) {
109
+ if (logDeltasIntervalId === 0) {
110
+ me.logDeltasIntervalId = setInterval(() => {
111
+ node = document.getElementById('neo-delta-updates');
112
+
113
+ if (node) {
114
+ node.innerHTML = String(me.countDeltasPer250ms * 4)
115
+ }
116
+
117
+ me.countDeltasPer250ms = 0
118
+ }, 250)
119
+ }
120
+ } else {
121
+ logDeltasIntervalId && clearInterval(logDeltasIntervalId);
122
+ me.logDeltasInterval = 0
123
+ }
124
+ }
125
+
126
+ /**
127
+ * @param {HTMLElement} node
128
+ * @param {String} nodeName
129
+ */
130
+ changeNodeName(node, nodeName) {
131
+ let {attributes} = node,
132
+ clone = document.createElement(nodeName),
133
+ i = 0,
134
+ len = attributes.length,
135
+ attribute;
136
+
137
+ if (node) {
138
+ for (; i < len; i++) {
139
+ attribute = attributes.item(i);
140
+ clone.setAttribute(attribute.nodeName, attribute.nodeValue)
141
+ }
142
+
143
+ clone.innerHTML= node.innerHTML;
144
+
145
+ node.parentNode.replaceChild(clone, node)
146
+ }
147
+ }
148
+
149
+ /**
150
+ * @param {Object} delta
151
+ * @param {String} delta.id
152
+ */
153
+ focusNode({id}) {
154
+ DomAccess.getElement(id)?.focus()
155
+ }
156
+
157
+ /**
158
+ * Inserts a new node into the DOM tree based on delta updates.
159
+ * This method handles both string-based (outerHTML) and direct DOM API (vnode) mounting.
160
+ * It ensures the node is inserted at the correct index within the parent.
161
+ *
162
+ * Implementation Details & Considerations:
163
+ * - `parentNode.children` contains only element nodes (tags).
164
+ * - `parentNode.childNodes` contains all nodes, including text and comment nodes.
165
+ * - Since every `vtype:'text'` is wrapped inside a comment block (as an ID),
166
+ * calculating a "realIndex" is necessary for string-based insertions to
167
+ * correctly account for non-element nodes.
168
+ * - `insertAdjacentHTML()` is generally faster than creating a node via template,
169
+ * but it's only available for manipulating children (elements), not `childNodes` (all nodes).
170
+ * - For performance, in cases where there are no comment nodes (i.e., no wrapped text nodes),
171
+ * the method prioritizes `insertAdjacentHTML()` when `useStringBasedMounting` is true.
172
+ *
173
+ * @param {Object} delta
174
+ * @param {Boolean} delta.hasLeadingTextChildren Flag to honor leading comments, which require special treatment.
175
+ * @param {Number} delta.index The index at which to insert the new node within its parent.
176
+ * @param {String} [delta.outerHTML] The string representation of the new node (for string-based mounting).
177
+ * @param {String} delta.parentId The ID of the parent DOM node.
178
+ * @param {Neo.vdom.VNode} [delta.vnode] The VNode representation of the new node (for direct DOM API mounting).
179
+ */
180
+ insertNode({hasLeadingTextChildren, index, outerHTML, parentId, vnode}) {
181
+ // This method is synchronous and *expects* the renderer to be loaded
182
+ if (!this.#renderer) {
183
+ console.error('DeltaUpdates renderer not ready during insertNode!');
184
+ return
185
+ }
186
+
187
+ const parentNode = DomAccess.getElementOrBody(parentId);
188
+
189
+ if (parentNode) {
190
+ if (!NeoConfig.useStringBasedMounting) {
191
+ this.#renderer.createDomTree({index, isRoot: true, parentNode, vnode})
192
+ } else {
193
+ this.#renderer.insertNodeAsString({hasLeadingTextChildren, index, outerHTML, parentNode})
194
+ }
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Moves an existing DOM node to a new position within its parent
200
+ * or to a new parent.
201
+ * This method directly manipulates the DOM using the pre-calculated physical index.
202
+ *
203
+ * @param {Object} delta
204
+ * @param {String} delta.id The ID of the DOM node to move.
205
+ * @param {Number} delta.index The physical index at which to insert the node
206
+ * @param {String} delta.parentId The ID of the target parent DOM node.
207
+ */
208
+ moveNode({id, index, parentId}) {
209
+ let node = DomAccess.getElement(id),
210
+ parentNode = DomAccess.getElement(parentId);
211
+
212
+ if (node && parentNode) {
213
+ // If the target index is at or beyond the end of the parent's current childNodes, append the node.
214
+ if (index >= parentNode.childNodes.length) {
215
+ parentNode.appendChild(node)
216
+ } else {
217
+ // Get the reference node at the target physical index.
218
+ let referenceNode = parentNode.childNodes[index];
219
+
220
+ // Only proceed if the node is not already at its target position.
221
+ if (node !== referenceNode) {
222
+ // Perform a direct swap operation if immediate element siblings.
223
+ if (node.nodeType === 1 && node === referenceNode.nextElementSibling) {
224
+ node.replaceWith(referenceNode)
225
+ }
226
+
227
+ parentNode.insertBefore(node, referenceNode)
228
+ }
229
+ }
230
+ }
231
+ }
232
+
233
+ /**
234
+ * @param {Object} delta
235
+ * @param {String} delta.parentId
236
+ */
237
+ removeAll({parentId}) {
238
+ let node = DomAccess.getElement(parentId);
239
+
240
+ if (node) {
241
+ node.innerHTML = ''
242
+ }
243
+ }
244
+
245
+ /**
246
+ * @param {Object} delta
247
+ * @param {String} delta.id
248
+ * @param {String} delta.parentId
249
+ */
250
+ removeNode({id, parentId}) {
251
+ const node = DomAccess.getElement(id);
252
+
253
+ if (node) {
254
+ node.remove();
255
+ }
256
+ // Potentially a vtype: 'text' node (wrapped between 2 comments)
257
+ else if (parentId) {
258
+ const
259
+ parentNode = DomAccess.getElementOrBody(parentId),
260
+ isComment = Node.COMMENT_NODE;
261
+
262
+ if (parentNode) {
263
+ // Find the starting comment node using its id marker
264
+ const startComment = Array.from(parentNode.childNodes).find(n =>
265
+ n.nodeType === isComment && n.nodeValue.includes(` ${id} `)
266
+ );
267
+
268
+ if (startComment) {
269
+ const
270
+ textNode = startComment.nextSibling,
271
+ // Ensure endComment is a comment node before attempting to remove
272
+ endComment = textNode?.nextSibling?.nodeType === isComment ? textNode.nextSibling : null;
273
+
274
+ // Remove the three parts: start comment, text node, end comment
275
+ startComment.remove();
276
+ textNode?.remove();
277
+ endComment?.remove()
278
+ }
279
+ }
280
+ }
281
+ }
282
+
283
+ /**
284
+ * @param {Object} delta
285
+ * @param {String} delta.fromId
286
+ * @param {String} delta.parentId
287
+ * @param {String} delta.toId
288
+ */
289
+ replaceChild({fromId, parentId, toId}) {
290
+ let node = DomAccess.getElement(parentId);
291
+
292
+ node?.replaceChild(DomAccess.getElement(toId), DomAccess.getElement(fromId))
293
+ }
294
+
295
+ /**
296
+ * @param {Object} delta
297
+ * @param {String} [delta.id]
298
+ * @param {String} [delta.value
299
+ */
300
+ setTextContent({id, value}) {
301
+ let node = DomAccess.getElement(id);
302
+
303
+ if (node) {
304
+ node.textContent = value
305
+ }
306
+ }
307
+
308
+ /**
309
+ * @param {Object} delta
310
+ * @param {Object} [delta.attributes]
311
+ * @param {String} [delta.cls]
312
+ * @param {String} [delta.id]
313
+ * @param {String} [delta.innerHTML]
314
+ * @param {String} [delta.outerHTML]
315
+ * @param {Object} [delta.style]
316
+ */
317
+ updateNode(delta) {
318
+ let me = this,
319
+ node = DomAccess.getElementOrBody(delta.id);
320
+
321
+ if (!node) {
322
+ console.log('node not found', delta.id);
323
+ }
324
+
325
+ if (node) {
326
+ Object.entries(delta).forEach(([prop, value]) => {
327
+ switch(prop) {
328
+ case 'attributes':
329
+ Object.entries(value).forEach(([key, val]) => {
330
+ if (voidAttributes.has(key)) {
331
+ node[key] = val === 'true' // vnode attribute values get converted into strings
332
+ } else if (val === null || val === '') {
333
+ if (key === 'value') {
334
+ node[key] = '' // input fields => pseudo attribute can not be removed
335
+ } else {
336
+ node.removeAttribute(key)
337
+ }
338
+ } else if (key === 'id') {
339
+ node[NeoConfig.useDomIds ? 'id' : 'data-neo-id'] = val
340
+ } else if (key === 'spellcheck' && val === 'false') {
341
+ // see https://github.com/neomjs/neo/issues/1922
342
+ node[key] = false
343
+ } else {
344
+ if (key === 'value') {
345
+ node[key] = val
346
+ } else {
347
+ node.setAttribute(key, val)
348
+ }
349
+ }
350
+ });
351
+ break
352
+ case 'cls':
353
+ value.add && node.classList.add(...value.add);
354
+ value.remove && node.classList.remove(...value.remove);
355
+ break
356
+ case 'innerHTML':
357
+ node.innerHTML = value || '';
358
+ break
359
+ case 'nodeName':
360
+ me.changeNodeName(node, value);
361
+ break
362
+ case 'outerHTML':
363
+ node.outerHTML = value || '';
364
+ break
365
+ case 'style':
366
+ if (Neo.isObject(value)) {
367
+ Object.entries(value).forEach(([key, val]) => {
368
+ let important;
369
+
370
+ if (Neo.isString(val) && val.includes('!important')) {
371
+ val = val.replace('!important', '').trim();
372
+ important = 'important'
373
+ }
374
+
375
+ node.style.setProperty(Neo.decamel(key), val, important)
376
+ })
377
+ }
378
+ break
379
+ }
380
+ })
381
+ }
382
+ }
383
+
384
+ /**
385
+ * @param {Object} delta
386
+ * @param {String} delta.id
387
+ * @param {String} delta.parentId
388
+ * @param {String} delta.value
389
+ */
390
+ updateVtext({id, parentId, value}) {
391
+ let node = DomAccess.getElement(parentId),
392
+ innerHTML = node.innerHTML,
393
+ startTag = `<!-- ${id} -->`,
394
+ reg = new RegExp(startTag + '[\\s\\S]*?<!-- \/neo-vtext -->');
395
+
396
+ node.innerHTML = innerHTML.replace(reg, value)
397
+ }
398
+
399
+ /**
400
+ * @param {Object} data
401
+ * @param {Object|Object[]} data.deltas
402
+ * @param {String} data.id
403
+ * @param {String} [data.origin='app']
404
+ */
405
+ update(data) {
406
+ // This method is synchronous and *expects* the renderer to be loaded
407
+ if (!this.#renderer) {
408
+ console.error('DeltaUpdates renderer not ready during insertNode!');
409
+ return
410
+ }
411
+
412
+ let me = this,
413
+ {deltas} = data,
414
+ i = 0,
415
+ len;
416
+
417
+ deltas = Array.isArray(deltas) ? deltas : [deltas];
418
+ len = deltas.length;
419
+
420
+ if (NeoConfig.logDeltaUpdates && len > 0) {
421
+ me.countDeltas += len;
422
+ me.countUpdates++;
423
+ console.log('update ' + me.countUpdates, 'total deltas ', me.countDeltas, Neo.clone(data, true))
424
+ }
425
+
426
+ if (NeoConfig.renderCountDeltas && len > 0) {
427
+ me.countDeltasPer250ms += len
428
+ }
429
+
430
+ for (; i < len; i++) {
431
+ me[deltas[i].action || 'updateNode'](deltas[i])
432
+ }
433
+
434
+ Neo.worker.Manager.sendMessage(data.origin || 'app', {
435
+ action : 'reply',
436
+ replyId: data.id,
437
+ success: true
438
+ })
439
+ }
440
+ }
441
+
442
+ export default Neo.setupClass(DeltaUpdates);
@@ -1,9 +1,7 @@
1
- import Base from '../core/Base.mjs';
2
- import DeltaUpdates from './mixin/DeltaUpdates.mjs';
3
- import DomUtils from './DomUtils.mjs';
4
- import Observable from '../core/Observable.mjs';
5
- import Rectangle from '../util/Rectangle.mjs';
6
- import StringUtil from '../util/String.mjs';
1
+ import Base from '../core/Base.mjs';
2
+ import DomUtils from './DomUtils.mjs';
3
+ import Rectangle from '../util/Rectangle.mjs';
4
+ import StringUtil from '../util/String.mjs';
7
5
 
8
6
  const
9
7
  doPreventDefault = e => e.preventDefault(),
@@ -43,34 +41,19 @@ const
43
41
  * @singleton
44
42
  */
45
43
  class DomAccess extends Base {
44
+ /**
45
+ * True automatically applies the core.Observable mixin
46
+ * @member {Boolean} observable=true
47
+ * @static
48
+ */
49
+ static observable = true
50
+
46
51
  static config = {
47
52
  /**
48
53
  * @member {String} className='Neo.main.DomAccess'
49
54
  * @protected
50
55
  */
51
56
  className: 'Neo.main.DomAccess',
52
- /**
53
- * @member {Number} countDeltas=0
54
- * @protected
55
- */
56
- countDeltas: 0,
57
- /**
58
- * @member {Number} countDeltasPer250ms=0
59
- * @protected
60
- */
61
- countDeltasPer250ms: 0,
62
- /**
63
- * @member {Number} countUpdates=0
64
- * @protected
65
- */
66
- countUpdates: 0,
67
- /**
68
- * @member {Array} mixins=[DeltaUpdates, Observable]
69
- */
70
- mixins: [
71
- DeltaUpdates,
72
- Observable
73
- ],
74
57
  /**
75
58
  * Remote method access for other workers
76
59
  * @member {Object} remote
@@ -104,33 +87,13 @@ class DomAccess extends Base {
104
87
  'windowScrollTo'
105
88
  ]
106
89
  },
107
- /**
108
- * @member {Boolean} renderCountDeltas_=false
109
- * @protected
110
- */
111
- renderCountDeltas_: false,
112
90
  /**
113
91
  * @member {Boolean} singleton=true
114
92
  * @protected
115
93
  */
116
- singleton: true,
117
- /**
118
- * Void attributes inside html tags
119
- * @member {String[]} voidAttributes
120
- * @protected
121
- */
122
- voidAttributes: [
123
- 'checked',
124
- 'required'
125
- ]
94
+ singleton: true
126
95
  }
127
96
 
128
- /**
129
- * @member {Number} logDeltasIntervalId=0
130
- * @protected
131
- */
132
- logDeltasIntervalId = 0
133
-
134
97
  /**
135
98
  * @returns {HTMLElement}
136
99
  */
@@ -154,10 +117,6 @@ class DomAccess extends Base {
154
117
 
155
118
  let me = this;
156
119
 
157
- if (Neo.config.renderCountDeltas) {
158
- me.renderCountDeltas = true
159
- }
160
-
161
120
  me.initGlobalListeners();
162
121
 
163
122
  // Set up our aligning callback which is called when things change which may
@@ -229,35 +188,6 @@ class DomAccess extends Base {
229
188
  document.head.appendChild(script)
230
189
  }
231
190
 
232
- /**
233
- * Triggered after the renderCountDeltas config got changed
234
- * @param {Boolean} value
235
- * @param {Boolean} oldValue
236
- * @protected
237
- */
238
- afterSetRenderCountDeltas(value, oldValue) {
239
- let me = this,
240
- {logDeltasIntervalId} = me,
241
- node;
242
-
243
- if (value) {
244
- if (logDeltasIntervalId === 0) {
245
- me.logDeltasIntervalId = setInterval(() => {
246
- node = document.getElementById('neo-delta-updates');
247
-
248
- if (node) {
249
- node.innerHTML = String(me.countDeltasPer250ms * 4)
250
- }
251
-
252
- me.countDeltasPer250ms = 0
253
- }, 250)
254
- }
255
- } else {
256
- logDeltasIntervalId && clearInterval(logDeltasIntervalId);
257
- me.logDeltasInterval = 0
258
- }
259
- }
260
-
261
191
  /**
262
192
  * @param {Object} data
263
193
  * @returns {Promise<void>}
@@ -865,7 +795,7 @@ class DomAccess extends Base {
865
795
  * @protected
866
796
  */
867
797
  read(data) {
868
- typeof data === 'function' && data()
798
+ Neo.isFunction(data) && data()
869
799
  }
870
800
 
871
801
  /**
@@ -1160,18 +1090,6 @@ class DomAccess extends Base {
1160
1090
  top : data.top || 0
1161
1091
  })
1162
1092
  }
1163
-
1164
- /**
1165
- * @param {Object} data
1166
- * @protected
1167
- */
1168
- write(data) {
1169
- this.du_insertNode({
1170
- index : data.parentIndex,
1171
- outerHTML: data.html || data.outerHTML,
1172
- parentId : data.parentId
1173
- })
1174
- }
1175
1093
  }
1176
1094
 
1177
1095
  export default Neo.setupClass(DomAccess);