neo.mjs 10.0.0-beta.1 → 10.0.0-beta.3
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.
- package/ServiceWorker.mjs +2 -2
- package/apps/colors/view/GridContainer.mjs +1 -1
- package/apps/covid/view/AttributionComponent.mjs +1 -1
- package/apps/covid/view/HeaderContainer.mjs +6 -6
- package/apps/covid/view/MainContainerController.mjs +5 -5
- package/apps/covid/view/TableContainerController.mjs +1 -1
- package/apps/covid/view/country/Gallery.mjs +13 -13
- package/apps/covid/view/country/Helix.mjs +13 -13
- package/apps/covid/view/country/HistoricalDataTable.mjs +1 -1
- package/apps/email/view/Viewport.mjs +2 -2
- package/apps/form/view/FormPageContainer.mjs +2 -3
- package/apps/form/view/SideNavList.mjs +1 -1
- package/apps/portal/index.html +1 -1
- package/apps/portal/resources/data/examples_dist_esm.json +1 -1
- package/apps/portal/resources/data/examples_dist_prod.json +2 -2
- package/apps/portal/view/HeaderToolbar.mjs +3 -3
- package/apps/portal/view/about/Container.mjs +2 -2
- package/apps/portal/view/about/MemberContainer.mjs +3 -3
- package/apps/portal/view/blog/List.mjs +7 -7
- package/apps/portal/view/examples/List.mjs +4 -4
- package/apps/portal/view/home/ContentBox.mjs +2 -2
- package/apps/portal/view/home/FeatureSection.mjs +3 -3
- package/apps/portal/view/home/FooterContainer.mjs +7 -7
- package/apps/portal/view/home/parts/AfterMath.mjs +3 -3
- package/apps/portal/view/home/parts/MainNeo.mjs +3 -3
- package/apps/portal/view/home/parts/References.mjs +6 -6
- package/apps/portal/view/learn/ContentComponent.mjs +18 -11
- package/apps/portal/view/learn/PageSectionsContainer.mjs +1 -1
- package/apps/portal/view/learn/PageSectionsList.mjs +2 -2
- package/apps/portal/view/services/Component.mjs +16 -16
- package/apps/realworld/view/FooterComponent.mjs +1 -1
- package/apps/realworld/view/HeaderComponent.mjs +8 -8
- package/apps/realworld/view/HomeComponent.mjs +6 -6
- package/apps/realworld/view/article/CommentComponent.mjs +4 -4
- package/apps/realworld/view/article/Component.mjs +14 -14
- package/apps/realworld/view/article/CreateCommentComponent.mjs +3 -3
- package/apps/realworld/view/article/CreateComponent.mjs +3 -3
- package/apps/realworld/view/article/PreviewComponent.mjs +1 -1
- package/apps/realworld/view/article/TagListComponent.mjs +2 -2
- package/apps/realworld/view/user/ProfileComponent.mjs +8 -8
- package/apps/realworld/view/user/SettingsComponent.mjs +4 -4
- package/apps/realworld/view/user/SignUpComponent.mjs +4 -4
- package/apps/realworld2/view/FooterComponent.mjs +1 -1
- package/apps/realworld2/view/HomeContainer.mjs +3 -3
- package/apps/realworld2/view/article/DetailsContainer.mjs +1 -1
- package/apps/realworld2/view/article/PreviewComponent.mjs +7 -7
- package/apps/realworld2/view/article/TagListComponent.mjs +2 -2
- package/apps/realworld2/view/user/ProfileContainer.mjs +1 -1
- package/apps/route/view/center/CardAdministration.mjs +2 -2
- package/apps/route/view/center/CardAdministrationDenied.mjs +1 -1
- package/apps/route/view/center/CardContact.mjs +2 -2
- package/apps/route/view/center/CardHome.mjs +1 -1
- package/apps/route/view/center/CardSection1.mjs +1 -1
- package/apps/route/view/center/CardSection2.mjs +1 -1
- package/apps/sharedcovid/view/AttributionComponent.mjs +1 -1
- package/apps/sharedcovid/view/HeaderContainer.mjs +6 -6
- package/apps/sharedcovid/view/MainContainerController.mjs +5 -5
- package/apps/sharedcovid/view/TableContainerController.mjs +1 -1
- package/apps/sharedcovid/view/country/Gallery.mjs +13 -13
- package/apps/sharedcovid/view/country/Helix.mjs +13 -13
- package/apps/sharedcovid/view/country/HistoricalDataTable.mjs +1 -1
- package/apps/shareddialog/childapps/shareddialog2/view/MainContainer.mjs +1 -1
- package/apps/shareddialog/view/MainContainer.mjs +1 -1
- package/buildScripts/createApp.mjs +2 -2
- package/learn/Glossary.md +261 -0
- package/learn/README.md +9 -14
- package/learn/benefits/ConfigSystem.md +536 -26
- package/learn/benefits/Effort.md +47 -2
- package/learn/benefits/Features.md +50 -32
- package/learn/benefits/FormsEngine.md +54 -24
- package/learn/benefits/MultiWindow.md +31 -5
- package/learn/benefits/Quick.md +45 -12
- package/learn/benefits/RPCLayer.md +75 -0
- package/learn/benefits/Speed.md +17 -12
- package/learn/guides/Collections.md +436 -0
- package/learn/guides/ConfigSystemDeepDive.md +280 -0
- package/learn/guides/CustomComponents.md +256 -14
- package/learn/guides/DeclarativeComponentTreesVsImperativeVdom.md +17 -17
- package/learn/guides/ExtendingNeoClasses.md +331 -0
- package/learn/guides/Forms.md +449 -1
- package/learn/guides/InstanceLifecycle.md +295 -1
- package/learn/guides/Layouts.md +246 -1
- package/learn/guides/MainThreadAddons.md +475 -0
- package/learn/guides/Records.md +286 -0
- package/learn/guides/WorkingWithVDom.md +14 -14
- package/learn/guides/form_fields/ComboBox.md +241 -0
- package/learn/tree.json +57 -51
- package/package.json +2 -2
- package/resources/scss/src/apps/portal/learn/ContentComponent.scss +9 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/Main.mjs +8 -7
- package/src/Neo.mjs +16 -2
- package/src/button/Base.mjs +2 -2
- package/src/calendar/view/SettingsContainer.mjs +2 -2
- package/src/calendar/view/YearComponent.mjs +9 -9
- package/src/calendar/view/calendars/ColorsList.mjs +1 -1
- package/src/calendar/view/calendars/List.mjs +1 -1
- package/src/calendar/view/month/Component.mjs +15 -15
- package/src/calendar/view/week/Component.mjs +12 -12
- package/src/calendar/view/week/EventDragZone.mjs +4 -4
- package/src/calendar/view/week/TimeAxisComponent.mjs +3 -3
- package/src/component/Base.mjs +17 -2
- package/src/component/Carousel.mjs +2 -2
- package/src/component/Chip.mjs +3 -3
- package/src/component/Circle.mjs +2 -2
- package/src/component/DateSelector.mjs +8 -8
- package/src/component/Helix.mjs +1 -1
- package/src/component/Label.mjs +3 -18
- package/src/component/Legend.mjs +3 -3
- package/src/component/MagicMoveText.mjs +6 -14
- package/src/component/Process.mjs +3 -3
- package/src/component/Progress.mjs +1 -1
- package/src/component/StatusBadge.mjs +2 -2
- package/src/component/Timer.mjs +2 -2
- package/src/component/Toast.mjs +5 -3
- package/src/container/AccordionItem.mjs +2 -2
- package/src/container/Base.mjs +1 -1
- package/src/core/Base.mjs +18 -2
- package/src/date/DayViewComponent.mjs +2 -2
- package/src/date/SelectorContainer.mjs +1 -1
- package/src/form/field/CheckBox.mjs +4 -4
- package/src/form/field/ComboBox.mjs +6 -1
- package/src/form/field/FileUpload.mjs +25 -39
- package/src/form/field/Range.mjs +1 -1
- package/src/form/field/Text.mjs +3 -3
- package/src/form/field/TextArea.mjs +2 -3
- package/src/grid/Body.mjs +6 -2
- package/src/list/Color.mjs +2 -2
- package/src/main/DeltaUpdates.mjs +157 -98
- package/src/main/addon/AmCharts.mjs +53 -73
- package/src/main/addon/Base.mjs +11 -0
- package/src/main/addon/MonacoEditor.mjs +31 -58
- package/src/manager/ClassHierarchy.mjs +114 -0
- package/src/menu/List.mjs +1 -1
- package/src/plugin/Popover.mjs +2 -2
- package/src/sitemap/Component.mjs +1 -1
- package/src/table/Body.mjs +6 -2
- package/src/tooltip/Base.mjs +1 -6
- package/src/tree/Accordion.mjs +3 -3
- package/src/vdom/Helper.mjs +21 -19
- package/src/worker/App.mjs +1 -2
- package/src/worker/Base.mjs +6 -4
- package/src/worker/Canvas.mjs +2 -3
- package/src/worker/Data.mjs +5 -7
- package/src/worker/Task.mjs +2 -3
- package/src/worker/VDom.mjs +3 -4
- package/src/worker/mixin/RemoteMethodAccess.mjs +4 -1
- package/learn/guides/MainThreadAddonExample.md +0 -15
- package/learn/guides/MainThreadAddonIntro.md +0 -44
package/src/grid/Body.mjs
CHANGED
@@ -460,7 +460,7 @@ class GridBody extends Component {
|
|
460
460
|
|
461
461
|
switch (Neo.typeOf(rendererOutput)) {
|
462
462
|
case 'Object': {
|
463
|
-
if (rendererOutput.html) {
|
463
|
+
if (rendererOutput.html || rendererOutput.text) {
|
464
464
|
rendererOutput.cls && cellCls.push(...rendererOutput.cls);
|
465
465
|
} else {
|
466
466
|
rendererOutput = [rendererOutput];
|
@@ -521,7 +521,11 @@ class GridBody extends Component {
|
|
521
521
|
}
|
522
522
|
|
523
523
|
if (Neo.typeOf(rendererOutput) === 'Object') {
|
524
|
-
|
524
|
+
if (Object.hasOwn(rendererOutput, 'html')) {
|
525
|
+
cellConfig.html = rendererOutput.html || ''
|
526
|
+
} else {
|
527
|
+
cellConfig.text = rendererOutput.text || ''
|
528
|
+
}
|
525
529
|
} else {
|
526
530
|
cellConfig.cn = rendererOutput
|
527
531
|
}
|
package/src/list/Color.mjs
CHANGED
@@ -5,7 +5,13 @@ import {voidAttributes} from '../vdom/domConstants.mjs';
|
|
5
5
|
const NeoConfig = Neo.config;
|
6
6
|
|
7
7
|
/**
|
8
|
-
*
|
8
|
+
* Manages and applies the Virtual DOM (VDom) delta updates generated by `Neo.vdom.Helper` to the real browser DOM.
|
9
|
+
* This class acts as the bridge between the VDom worker's calculated changes and the actual rendering on the main thread.
|
10
|
+
* It orchestrates various DOM manipulation operations such as node insertions, removals, moves, attribute updates,
|
11
|
+
* and handles dynamic renderer switching based on `Neo.config.useDomApiRenderer`.
|
12
|
+
*
|
13
|
+
* As a singleton per browser window, it provides a centralized and efficient mechanism for synchronized DOM updates,
|
14
|
+
* ensuring the UI accurately reflects the application state.
|
9
15
|
* @class Neo.main.DeltaUpdates
|
10
16
|
* @extends Neo.core.Base
|
11
17
|
* @singleton
|
@@ -48,19 +54,6 @@ class DeltaUpdates extends Base {
|
|
48
54
|
* @protected
|
49
55
|
*/
|
50
56
|
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
|
-
* Private property to signal that the renderer module has been loaded.
|
59
|
-
* This will be a Promise that resolves when the module is ready.
|
60
|
-
* @private
|
61
|
-
* @member {Promise<void>|null} #_readyPromise
|
62
|
-
*/
|
63
|
-
#_readyPromise = null
|
64
57
|
|
65
58
|
/**
|
66
59
|
* @param {Object} config
|
@@ -68,11 +61,10 @@ class DeltaUpdates extends Base {
|
|
68
61
|
construct(config) {
|
69
62
|
super.construct(config);
|
70
63
|
|
71
|
-
let
|
72
|
-
{environment} = NeoConfig;
|
64
|
+
let {environment} = NeoConfig;
|
73
65
|
|
74
66
|
if (NeoConfig.renderCountDeltas) {
|
75
|
-
|
67
|
+
this.renderCountDeltas = true
|
76
68
|
}
|
77
69
|
|
78
70
|
// We need different publicPath values for the main thread inside the webpack based dist envs,
|
@@ -80,24 +72,6 @@ class DeltaUpdates extends Base {
|
|
80
72
|
if (environment === 'dist/development' || environment === 'dist/production') {
|
81
73
|
__webpack_require__.p = NeoConfig.basePath.substring(6)
|
82
74
|
}
|
83
|
-
|
84
|
-
// Initiate the asynchronous loading of the renderer here.
|
85
|
-
me.#_readyPromise = (async () => {
|
86
|
-
try {
|
87
|
-
let module;
|
88
|
-
|
89
|
-
if (NeoConfig.useDomApiRenderer) {
|
90
|
-
module = await import('./render/DomApiRenderer.mjs')
|
91
|
-
} else {
|
92
|
-
module = await import('./render/StringBasedRenderer.mjs')
|
93
|
-
}
|
94
|
-
|
95
|
-
me.#renderer = module.default
|
96
|
-
} catch (err) {
|
97
|
-
console.error('DeltaUpdates: Failed to load renderer module:', err);
|
98
|
-
throw err // Re-throw to propagate initialization failures
|
99
|
-
}
|
100
|
-
})()
|
101
75
|
}
|
102
76
|
|
103
77
|
/**
|
@@ -130,8 +104,13 @@ class DeltaUpdates extends Base {
|
|
130
104
|
}
|
131
105
|
|
132
106
|
/**
|
133
|
-
*
|
134
|
-
*
|
107
|
+
* Changes the tag name (nodeName) of an existing HTMLElement in the DOM.
|
108
|
+
* This operation is performed by creating a new HTML element with the desired `nodeName`,
|
109
|
+
* meticulously copying all attributes and the `innerHTML` from the original `node` to the new one,
|
110
|
+
* and then seamlessly replacing the original `node` with the newly created element within its parent.
|
111
|
+
*
|
112
|
+
* @param {HTMLElement} node The existing DOM HTMLElement whose tag name needs to be changed.
|
113
|
+
* @param {String} nodeName The new tag name (e.g., 'div', 'span', 'p') for the element.
|
135
114
|
*/
|
136
115
|
changeNodeName(node, nodeName) {
|
137
116
|
let {attributes} = node,
|
@@ -160,21 +139,49 @@ class DeltaUpdates extends Base {
|
|
160
139
|
DomAccess.getElement(id)?.focus()
|
161
140
|
}
|
162
141
|
|
142
|
+
/**
|
143
|
+
* Imports either (if not already imported):
|
144
|
+
* `Neo.main.render.DomApiRenderer` if Neo.config.useDomApiRenderer === true
|
145
|
+
* `Neo.main.render.StringBasedRenderer` if Neo.config.useDomApiRenderer === false
|
146
|
+
* @returns {Promise<void>}
|
147
|
+
* @protected
|
148
|
+
*/
|
149
|
+
async importRenderer() {
|
150
|
+
const {render} = Neo.main;
|
151
|
+
|
152
|
+
if (NeoConfig.useDomApiRenderer) {
|
153
|
+
if (!render?.DomApiRenderer) {
|
154
|
+
await import('./render/DomApiRenderer.mjs')
|
155
|
+
}
|
156
|
+
} else {
|
157
|
+
if (!render?.StringBasedRenderer) {
|
158
|
+
await import('./render/StringBasedRenderer.mjs')
|
159
|
+
}
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
/**
|
164
|
+
* @returns {Promise<void>}
|
165
|
+
*/
|
166
|
+
async initAsync() {
|
167
|
+
super.initAsync();
|
168
|
+
|
169
|
+
let me = this;
|
170
|
+
|
171
|
+
// Subscribe to global Neo.config changes for dynamic renderer switching.
|
172
|
+
Neo.worker.Manager.on({
|
173
|
+
neoConfigChange: me.onNeoConfigChange,
|
174
|
+
scope : me
|
175
|
+
});
|
176
|
+
|
177
|
+
await me.importRenderer()
|
178
|
+
}
|
179
|
+
|
163
180
|
/**
|
164
181
|
* Inserts a new node into the DOM tree based on delta updates.
|
165
182
|
* This method handles both string-based (outerHTML) and direct DOM API (vnode) mounting.
|
166
183
|
* It ensures the node is inserted at the correct index within the parent.
|
167
|
-
*
|
168
|
-
* Implementation Details & Considerations:
|
169
|
-
* - `parentNode.children` contains only element nodes (tags).
|
170
|
-
* - `parentNode.childNodes` contains all nodes, including text and comment nodes.
|
171
|
-
* - Since every `vtype:'text'` is wrapped inside a comment block (as an ID),
|
172
|
-
* calculating a "realIndex" is necessary for string-based insertions to
|
173
|
-
* correctly account for non-element nodes.
|
174
|
-
* - `insertAdjacentHTML()` is generally faster than creating a node via template,
|
175
|
-
* but it's only available for manipulating children (elements), not `childNodes` (all nodes).
|
176
|
-
* - For performance, in cases where there are no comment nodes (i.e., no wrapped text nodes),
|
177
|
-
* the method prioritizes `insertAdjacentHTML()` when `useDomApiRenderer` is false.
|
184
|
+
* This method is synchronous and *expects* the appropriate renderer (DomApiRenderer or StringBasedRenderer) to be already loaded.
|
178
185
|
*
|
179
186
|
* @param {Object} delta
|
180
187
|
* @param {Boolean} delta.hasLeadingTextChildren Flag to honor leading comments, which require special treatment.
|
@@ -184,33 +191,47 @@ class DeltaUpdates extends Base {
|
|
184
191
|
* @param {Neo.vdom.VNode} [delta.vnode] The VNode representation of the new node (for direct DOM API mounting).
|
185
192
|
*/
|
186
193
|
insertNode({hasLeadingTextChildren, index, outerHTML, parentId, vnode}) {
|
187
|
-
|
188
|
-
|
189
|
-
// This method is synchronous and *expects* the renderer to be loaded
|
190
|
-
if (!me.#renderer) {
|
191
|
-
console.error('DeltaUpdates renderer not ready during insertNode!');
|
192
|
-
return
|
193
|
-
}
|
194
|
+
this.checkRendererAvailability();
|
194
195
|
|
195
|
-
|
196
|
+
let {render} = Neo.main,
|
197
|
+
parentNode = DomAccess.getElementOrBody(parentId);
|
196
198
|
|
197
199
|
if (parentNode) {
|
198
200
|
if (NeoConfig.useDomApiRenderer) {
|
199
|
-
|
201
|
+
render.DomApiRenderer.createDomTree({index, isRoot: true, parentNode, vnode})
|
200
202
|
} else {
|
201
|
-
|
203
|
+
render.StringBasedRenderer.insertNodeAsString({hasLeadingTextChildren, index, outerHTML, parentNode})
|
204
|
+
}
|
205
|
+
}
|
206
|
+
}
|
207
|
+
|
208
|
+
/**
|
209
|
+
*
|
210
|
+
*/
|
211
|
+
checkRendererAvailability() {
|
212
|
+
const {render} = Neo.main;
|
213
|
+
|
214
|
+
if (NeoConfig.useDomApiRenderer) {
|
215
|
+
if (!render?.DomApiRenderer) {
|
216
|
+
throw new Error('Neo.main.DeltaUpdates: DomApiRenderer is not loaded yet!')
|
217
|
+
}
|
218
|
+
} else {
|
219
|
+
if (!render?.StringBasedRenderer) {
|
220
|
+
throw new Error('Neo.main.DeltaUpdates: StringBasedRenderer is not loaded yet!')
|
202
221
|
}
|
203
222
|
}
|
204
223
|
}
|
205
224
|
|
206
225
|
/**
|
207
|
-
* Moves an existing DOM node to a new position within its parent
|
208
|
-
*
|
209
|
-
*
|
226
|
+
* Moves an existing DOM node to a new position within its parent or to a new parent.
|
227
|
+
* This method directly manipulates the DOM using the pre-calculated physical index,
|
228
|
+
* accounting for potential text nodes wrapped in comments.
|
229
|
+
* It performs a direct sibling swap when an element is immediately followed by its target position,
|
230
|
+
* which is necessary to prevent attempting to replace a node with itself.
|
210
231
|
*
|
211
232
|
* @param {Object} delta
|
212
233
|
* @param {String} delta.id The ID of the DOM node to move.
|
213
|
-
* @param {Number} delta.index The physical index at which to insert the node
|
234
|
+
* @param {Number} delta.index The physical index at which to insert the node within the target parent's childNodes.
|
214
235
|
* @param {String} delta.parentId The ID of the target parent DOM node.
|
215
236
|
*/
|
216
237
|
moveNode({id, index, parentId}) {
|
@@ -239,8 +260,25 @@ class DeltaUpdates extends Base {
|
|
239
260
|
}
|
240
261
|
|
241
262
|
/**
|
263
|
+
* Handler for global Neo.config changes.
|
264
|
+
* If the `Neo.config.useDomApiRenderer` value changes, this method dynamically loads the renderer.
|
265
|
+
* @param {Object} config
|
266
|
+
* @return {Promise<void>}
|
267
|
+
*/
|
268
|
+
async onNeoConfigChange(config) {
|
269
|
+
if (Object.hasOwn(config, 'useDomApiRenderer')) {
|
270
|
+
await this.importRenderer()
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
274
|
+
/**
|
275
|
+
* Clears all child nodes of a given parent DOM node.
|
276
|
+
* This is achieved by setting its `innerHTML` property to an empty string,
|
277
|
+
* which is generally considered the fastest and most efficient way to remove
|
278
|
+
* all children from a DOM element in modern browsers.
|
279
|
+
*
|
242
280
|
* @param {Object} delta
|
243
|
-
* @param {String} delta.parentId
|
281
|
+
* @param {String} delta.parentId The ID of the parent DOM node whose children will be removed.
|
244
282
|
*/
|
245
283
|
removeAll({parentId}) {
|
246
284
|
let node = DomAccess.getElement(parentId);
|
@@ -251,9 +289,13 @@ class DeltaUpdates extends Base {
|
|
251
289
|
}
|
252
290
|
|
253
291
|
/**
|
292
|
+
* Removes a DOM node from its parent.
|
293
|
+
* This method handles both standard HTML elements and virtual text nodes,
|
294
|
+
* which are typically wrapped within comment nodes in the DOM.
|
295
|
+
*
|
254
296
|
* @param {Object} delta
|
255
|
-
* @param {String} delta.id
|
256
|
-
* @param {String} delta.parentId
|
297
|
+
* @param {String} delta.id The ID of the DOM node to remove.
|
298
|
+
* @param {String} delta.parentId The ID of the parent DOM node (required for text node removal).
|
257
299
|
*/
|
258
300
|
removeNode({id, parentId}) {
|
259
301
|
const node = DomAccess.getElement(id);
|
@@ -289,10 +331,17 @@ class DeltaUpdates extends Base {
|
|
289
331
|
}
|
290
332
|
|
291
333
|
/**
|
334
|
+
* Replaces an existing child DOM node (`fromId`) with a new DOM node (`toId`)
|
335
|
+
* within a specified parent DOM node (`parentId`).
|
336
|
+
* This operation directly invokes the native `Node.replaceChild()` API,
|
337
|
+
* performing an atomic swap of the elements in the DOM tree.
|
338
|
+
* It is typically used when a specific DOM element needs to be completely
|
339
|
+
* exchanged for a different one at the same position.
|
340
|
+
*
|
292
341
|
* @param {Object} delta
|
293
|
-
* @param {String} delta.fromId
|
294
|
-
* @param {String} delta.parentId
|
295
|
-
* @param {String} delta.toId
|
342
|
+
* @param {String} delta.fromId The ID of the existing child DOM node to be replaced.
|
343
|
+
* @param {String} delta.parentId The ID of the parent DOM node containing the child to be replaced.
|
344
|
+
* @param {String} delta.toId The ID of the new DOM node that will replace the old one.
|
296
345
|
*/
|
297
346
|
replaceChild({fromId, parentId, toId}) {
|
298
347
|
let node = DomAccess.getElement(parentId);
|
@@ -301,26 +350,20 @@ class DeltaUpdates extends Base {
|
|
301
350
|
}
|
302
351
|
|
303
352
|
/**
|
353
|
+
* Updates various properties of an existing DOM node based on the provided delta.
|
354
|
+
* This includes updating attributes, class names, inner HTML, node name, and inline styles.
|
355
|
+
* It handles specific cases for attribute types (e.g., boolean attributes, 'value')
|
356
|
+
* and style properties (e.g., '!important').
|
357
|
+
*
|
304
358
|
* @param {Object} delta
|
305
|
-
* @param {String}
|
306
|
-
* @param {
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
}
|
314
|
-
}
|
315
|
-
|
316
|
-
/**
|
317
|
-
* @param {Object} delta
|
318
|
-
* @param {Object} [delta.attributes]
|
319
|
-
* @param {String} [delta.cls]
|
320
|
-
* @param {String} [delta.id]
|
321
|
-
* @param {String} [delta.innerHTML]
|
322
|
-
* @param {String} [delta.outerHTML]
|
323
|
-
* @param {Object} [delta.style]
|
359
|
+
* @param {String} delta.id The ID of the DOM node to update.
|
360
|
+
* @param {Object} [delta.attributes] An object containing attribute key-value pairs to update or remove (if value is null/empty).
|
361
|
+
* @param {Object} [delta.cls] An object containing 'add' and/or 'remove' arrays for CSS classes.
|
362
|
+
* @param {String} [delta.innerHTML] The new inner HTML content for the node.
|
363
|
+
* @param {String} [delta.nodeName] The new tag name for the node (will trigger a node replacement).
|
364
|
+
* @param {String} [delta.outerHTML] The new outer HTML content for the node (will trigger a node replacement).
|
365
|
+
* @param {Object} [delta.style] An object containing CSS style properties to update. Values can include '!important'.
|
366
|
+
* @param {String} [delta.textContent] The new text content for the node (replaces innerHTML if present).
|
324
367
|
*/
|
325
368
|
updateNode(delta) {
|
326
369
|
let me = this,
|
@@ -384,16 +427,25 @@ class DeltaUpdates extends Base {
|
|
384
427
|
})
|
385
428
|
}
|
386
429
|
break
|
430
|
+
case 'textContent':
|
431
|
+
node.textContent = value;
|
432
|
+
break
|
387
433
|
}
|
388
434
|
})
|
389
435
|
}
|
390
436
|
}
|
391
437
|
|
392
438
|
/**
|
439
|
+
* Updates the text content of a virtual text node within the DOM.
|
440
|
+
* Virtual text nodes are rendered within the DOM as a pair of HTML comments,
|
441
|
+
* with their content embedded between them. This method locates the specific
|
442
|
+
* text node by its ID (embedded in the start comment tag) within its parent's
|
443
|
+
* innerHTML and replaces its content using a regular expression.
|
444
|
+
*
|
393
445
|
* @param {Object} delta
|
394
|
-
* @param {String} delta.id
|
395
|
-
* @param {String} delta.parentId
|
396
|
-
* @param {String} delta.value
|
446
|
+
* @param {String} delta.id The unique ID of the virtual text node, which is embedded in its opening comment tag.
|
447
|
+
* @param {String} delta.parentId The ID of the parent DOM node whose `innerHTML` contains the virtual text node.
|
448
|
+
* @param {String} delta.value The new text content to be applied to the virtual text node.
|
397
449
|
*/
|
398
450
|
updateVtext({id, parentId, value}) {
|
399
451
|
let node = DomAccess.getElement(parentId),
|
@@ -405,17 +457,24 @@ class DeltaUpdates extends Base {
|
|
405
457
|
}
|
406
458
|
|
407
459
|
/**
|
460
|
+
* Applies a set of VDom delta updates to the real DOM.
|
461
|
+
* This method is the core entry point for rendering changes initiated from the VDom worker.
|
462
|
+
* It iterates through the provided deltas and dispatches them to specific DOM manipulation
|
463
|
+
* methods (e.g., insertNode, removeNode, updateNode) based on their `action` property.
|
464
|
+
* This method expects the appropriate renderer (DomApiRenderer or StringBasedRenderer)
|
465
|
+
* to be loaded based on `Neo.config.useDomApiRenderer`.
|
466
|
+
*
|
408
467
|
* @param {Object} data
|
409
|
-
* @param {Object|Object[]} data.deltas
|
410
|
-
*
|
411
|
-
*
|
468
|
+
* @param {Object|Object[]} data.deltas An array of delta objects, or a single delta object,
|
469
|
+
* representing changes to be applied to the DOM.
|
470
|
+
* Each delta object contains an `action` property
|
471
|
+
* (e.g., 'insertNode', 'removeNode', 'updateNode', 'moveNode')
|
472
|
+
* and additional properties relevant to the specific action.
|
473
|
+
* @param {String} data.id The unique ID of the request, used for sending a reply back to the origin.
|
474
|
+
* @param {String} [data.origin='app'] The origin of the message (e.g., 'app'), used for sending replies.
|
412
475
|
*/
|
413
476
|
update(data) {
|
414
|
-
|
415
|
-
if (!this.#renderer) {
|
416
|
-
console.error('DeltaUpdates renderer not ready during insertNode!');
|
417
|
-
return
|
418
|
-
}
|
477
|
+
this.checkRendererAvailability();
|
419
478
|
|
420
479
|
let me = this,
|
421
480
|
{deltas} = data,
|
@@ -37,6 +37,18 @@ class AmCharts extends Base {
|
|
37
37
|
* @protected
|
38
38
|
*/
|
39
39
|
fallbackPath: 'https://raw.githubusercontent.com/neomjs/pages/main/resources_pub/amCharts/',
|
40
|
+
/**
|
41
|
+
* List methods which must get cached until the addon reaches its `isReady` state
|
42
|
+
* @member {String[]} interceptRemotes
|
43
|
+
*/
|
44
|
+
interceptRemotes: [
|
45
|
+
'callMethod',
|
46
|
+
'create',
|
47
|
+
'destroy',
|
48
|
+
'setProperties',
|
49
|
+
'setProperty',
|
50
|
+
'updateData'
|
51
|
+
],
|
40
52
|
/**
|
41
53
|
* Remote method access for other workers
|
42
54
|
* @member {Object} remote
|
@@ -91,19 +103,15 @@ class AmCharts extends Base {
|
|
91
103
|
callMethod(data) {
|
92
104
|
let me = this;
|
93
105
|
|
94
|
-
if (
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
pathArray = data.path.split('.'),
|
100
|
-
methodName = pathArray.pop(),
|
101
|
-
scope = pathArray.length < 1 ? chart: Neo.ns(pathArray.join('.'), false, chart);
|
106
|
+
if (me.hasChart(data.id)) {
|
107
|
+
let chart = me.charts[data.id],
|
108
|
+
pathArray = data.path.split('.'),
|
109
|
+
methodName = pathArray.pop(),
|
110
|
+
scope = pathArray.length < 1 ? chart: Neo.ns(pathArray.join('.'), false, chart);
|
102
111
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
}
|
112
|
+
scope[methodName].call(scope, ...data.params || [])
|
113
|
+
} else {
|
114
|
+
// todo
|
107
115
|
}
|
108
116
|
}
|
109
117
|
|
@@ -137,29 +145,25 @@ class AmCharts extends Base {
|
|
137
145
|
create(data) {
|
138
146
|
let me = this;
|
139
147
|
|
140
|
-
if
|
141
|
-
|
142
|
-
} else {
|
143
|
-
// todo: check if globalThis[data.package] exists, if not load it and call create afterwards
|
144
|
-
am4core.useTheme(am4themes_dark);
|
148
|
+
// todo: check if globalThis[data.package] exists, if not load it and call create afterwards
|
149
|
+
am4core.useTheme(am4themes_dark);
|
145
150
|
|
146
|
-
|
151
|
+
me.charts[data.id] = am4core.createFromConfig(data.config, data.id, globalThis[data.package][data.type || 'XYChart']);
|
147
152
|
|
148
|
-
|
149
|
-
|
150
|
-
|
153
|
+
if (data.combineSeriesTooltip) {
|
154
|
+
me.combineSeriesTooltip(me.charts[data.id])
|
155
|
+
}
|
151
156
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
}
|
157
|
+
// in case data has arrived before the chart got created, apply it now
|
158
|
+
if (data.data) {
|
159
|
+
me.updateData({
|
160
|
+
data : data.data,
|
161
|
+
dataPath: data.dataPath,
|
162
|
+
id : data.id
|
163
|
+
})
|
164
|
+
} else if (me.dataMap[data.id]) {
|
165
|
+
me.updateData(me.dataMap[data.id]);
|
166
|
+
delete me.dataMap[data.id]
|
163
167
|
}
|
164
168
|
}
|
165
169
|
|
@@ -167,15 +171,9 @@ class AmCharts extends Base {
|
|
167
171
|
* @param {Object} data
|
168
172
|
* @param {String} data.id
|
169
173
|
*/
|
170
|
-
destroy(
|
171
|
-
|
172
|
-
|
173
|
-
if (!me.isReady) {
|
174
|
-
return me.cacheMethodCall({fn: 'destroy', data})
|
175
|
-
} else {
|
176
|
-
me.charts[data.id]?.dispose?.();
|
177
|
-
delete me.charts[data.id]
|
178
|
-
}
|
174
|
+
destroy({id}) {
|
175
|
+
this.charts[id]?.dispose?.();
|
176
|
+
delete this.charts[id]
|
179
177
|
}
|
180
178
|
|
181
179
|
/**
|
@@ -229,20 +227,10 @@ class AmCharts extends Base {
|
|
229
227
|
* @param {String} data.id
|
230
228
|
* @param {Object} data.properties
|
231
229
|
*/
|
232
|
-
setProperties(
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
return me.cacheMethodCall({fn: 'setProperties', data})
|
237
|
-
} else {
|
238
|
-
Object.entries(data.properties).forEach(([key, value]) => {
|
239
|
-
me.setProperty({
|
240
|
-
id : data.id,
|
241
|
-
path : key,
|
242
|
-
value
|
243
|
-
})
|
244
|
-
})
|
245
|
-
}
|
230
|
+
setProperties({id, properties}) {
|
231
|
+
Object.entries(properties).forEach(([key, value]) => {
|
232
|
+
this.setProperty({id, path: key, value})
|
233
|
+
})
|
246
234
|
}
|
247
235
|
|
248
236
|
/**
|
@@ -252,22 +240,16 @@ class AmCharts extends Base {
|
|
252
240
|
* @param {String} data.path
|
253
241
|
* @param {*} data.value
|
254
242
|
*/
|
255
|
-
setProperty(
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
243
|
+
setProperty({id, isColor=false, path, value}) {
|
244
|
+
if (this.hasChart(id)) {
|
245
|
+
let chart = this.charts[id],
|
246
|
+
pathArray = path.split('.'),
|
247
|
+
propertyName = pathArray.pop(),
|
248
|
+
scope = Neo.ns(pathArray.join('.'), false, chart);
|
249
|
+
|
250
|
+
scope[propertyName] = isColor ? am4core.color(value) : value
|
260
251
|
} else {
|
261
|
-
|
262
|
-
let chart = this.charts[data.id],
|
263
|
-
pathArray = data.path.split('.'),
|
264
|
-
propertyName = pathArray.pop(),
|
265
|
-
scope = Neo.ns(pathArray.join('.'), false, chart);
|
266
|
-
|
267
|
-
scope[propertyName] = data.isColor ? am4core.color(data.value) : data.value
|
268
|
-
} else {
|
269
|
-
// todo
|
270
|
-
}
|
252
|
+
// todo
|
271
253
|
}
|
272
254
|
}
|
273
255
|
|
@@ -280,9 +262,7 @@ class AmCharts extends Base {
|
|
280
262
|
updateData(data) {
|
281
263
|
let me = this;
|
282
264
|
|
283
|
-
if (!me.
|
284
|
-
return me.cacheMethodCall({fn: 'updateData', data})
|
285
|
-
} else if (!me.hasChart(data.id)) {
|
265
|
+
if (!me.hasChart(data.id)) {
|
286
266
|
me.dataMap[data.id] = data
|
287
267
|
} else {
|
288
268
|
let chart = me.charts[data.id];
|
package/src/main/addon/Base.mjs
CHANGED
@@ -179,6 +179,17 @@ class Base extends CoreBase {
|
|
179
179
|
*/
|
180
180
|
async loadFiles() {}
|
181
181
|
|
182
|
+
/**
|
183
|
+
* Handles intercepted remote method calls.
|
184
|
+
* If the addon is not ready, the call is cached using `cacheMethodCall()`.
|
185
|
+
* Otherwise, the original method is executed.
|
186
|
+
* @param {Object} msg The remote message object.
|
187
|
+
* @returns {Promise<any>} A promise that resolves with the method's return value.
|
188
|
+
*/
|
189
|
+
onInterceptRemotes(msg) {
|
190
|
+
return this.cacheMethodCall({fn: msg.remoteMethod, data: msg.data})
|
191
|
+
}
|
192
|
+
|
182
193
|
/**
|
183
194
|
* Sequentially processes any method calls that were cached while the addon was not ready.
|
184
195
|
* This method is asynchronous to allow awaiting the execution of individual cached methods.
|