neo.mjs 10.0.0-alpha.3 → 10.0.0-alpha.4
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/.github/CODING_GUIDELINES.md +1 -1
- package/README.md +52 -11
- package/ServiceWorker.mjs +2 -2
- package/apps/portal/index.html +1 -1
- package/apps/portal/view/home/FooterContainer.mjs +1 -1
- package/apps/portal/view/learn/ContentComponent.mjs +2 -1
- package/apps/portal/view/learn/MainContainerStateProvider.mjs +3 -6
- package/apps/realworld/view/HomeComponent.mjs +1 -1
- package/apps/realworld/view/user/ProfileComponent.mjs +1 -1
- package/apps/sharedcovid/view/MainContainerController.mjs +1 -1
- package/apps/shareddialog/view/MainContainerController.mjs +2 -2
- package/learn/README.md +83 -0
- package/learn/guides/ApplicationBootstrap.md +354 -0
- package/learn/guides/DeclarativeComponentTreesVsImperativeVdom.md +500 -0
- package/learn/guides/WorkingWithVDom.md +748 -0
- package/learn/tree.json +53 -0
- package/package.json +2 -2
- package/src/DefaultConfig.mjs +27 -14
- package/src/Main.mjs +1 -1
- package/src/Neo.mjs +16 -0
- package/src/button/Base.mjs +2 -2
- package/src/calendar/view/MainContainerStateProvider.mjs +1 -1
- package/src/grid/header/Button.mjs +1 -1
- package/src/layout/Cube.mjs +2 -2
- package/src/main/DeltaUpdates.mjs +11 -10
- package/src/main/addon/Navigator.mjs +1 -1
- package/src/main/addon/WindowPosition.mjs +1 -1
- package/src/main/render/StringBasedRenderer.mjs +1 -1
- package/src/tab/header/Toolbar.mjs +1 -1
- package/src/table/header/Button.mjs +1 -1
- package/src/toolbar/Base.mjs +1 -1
- package/src/util/VDom.mjs +1 -1
- package/src/util/VNode.mjs +1 -1
- package/src/vdom/Helper.mjs +96 -49
- package/src/vdom/VNode.mjs +38 -2
- package/src/worker/App.mjs +2 -1
- package/src/worker/Base.mjs +87 -5
- package/src/worker/Manager.mjs +86 -28
- package/resources/data/deck/learnneo/tree.json +0 -50
- package/resources/data/deck/whyneo.md +0 -80
- /package/{resources/data/deck/learnneo/pages → learn}/Glossary.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/UsingTheseTopics.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/benefits/ConfigSystem.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/benefits/Effort.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/benefits/Features.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/benefits/FormsEngine.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/benefits/FourEnvironments.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/benefits/Introduction.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/benefits/MultiWindow.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/benefits/OffTheMainThread.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/benefits/Quick.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/benefits/Speed.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/gettingstarted/ComponentModels.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/gettingstarted/Config.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/gettingstarted/DescribingTheUI.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/gettingstarted/Events.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/gettingstarted/Extending.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/gettingstarted/References.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/gettingstarted/Setup.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/gettingstarted/Workspaces.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/ComponentsAndContainers.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/CustomComponents.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/Forms.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/InstanceLifecycle.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/Layouts.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/MainThreadAddonExample.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/MainThreadAddonIntro.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/Mixins.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/MultiWindow.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/PortalApp.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/StateProviders.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/Tables.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/events/CustomEvents.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/guides/events/DomEvents.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/javascript/ClassFeatures.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/javascript/Classes.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/javascript/NewNode.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/javascript/Overrides.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/javascript/Super.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/tutorials/Earthquakes.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/tutorials/RSP.md +0 -0
- /package/{resources/data/deck/learnneo/pages → learn}/tutorials/TodoList.md +0 -0
- /package/resources/data/{deck/learnneo/data/theBeatles.json → theBeatles.json} +0 -0
package/src/vdom/VNode.mjs
CHANGED
@@ -76,7 +76,7 @@ class VNode {
|
|
76
76
|
} else {
|
77
77
|
Object.assign(me, {
|
78
78
|
attributes: config.attributes || {},
|
79
|
-
className : config.className
|
79
|
+
className : normalizeClassName(config.className),
|
80
80
|
nodeName : config.nodeName || 'div',
|
81
81
|
style : config.style
|
82
82
|
});
|
@@ -88,7 +88,7 @@ class VNode {
|
|
88
88
|
|
89
89
|
// We only apply textContent, in case it has content
|
90
90
|
else if (Object.hasOwn(config, 'textContent')) {
|
91
|
-
me.textContent = Neo.config.
|
91
|
+
me.textContent = Neo.config.useDomApiRenderer ? textContent : StringUtil.escapeHtml(textContent)
|
92
92
|
}
|
93
93
|
}
|
94
94
|
|
@@ -99,6 +99,42 @@ class VNode {
|
|
99
99
|
}
|
100
100
|
}
|
101
101
|
|
102
|
+
/**
|
103
|
+
* vdom cls definitions might contain spaces, especially when it comes to iconCls.
|
104
|
+
* @example: myVdom = {cls: ['my-button', 'fa fa-user']}
|
105
|
+
*
|
106
|
+
* On DOM level, classList.add() will throw, in case it gets an input containing a space.
|
107
|
+
*
|
108
|
+
* This is a module-scoped utility function, not a method of the VNode class.
|
109
|
+
* VNodes are transferred via structured cloning (e.g., in postMessage()), which strips methods.
|
110
|
+
* Keeping this logic separate from the VNode class itself ensures conceptual purity and a cleaner data model,
|
111
|
+
* as methods defined on the VNode instance would be lost during transfer anyway.
|
112
|
+
*
|
113
|
+
* @param {String|String[]} classNameInput
|
114
|
+
* @returns {String[]}
|
115
|
+
* @private
|
116
|
+
*/
|
117
|
+
function normalizeClassName(classNameInput) {
|
118
|
+
let normalizedClasses = [];
|
119
|
+
|
120
|
+
if (Neo.isString(classNameInput)) {
|
121
|
+
normalizedClasses = classNameInput.split(' ').filter(Boolean)
|
122
|
+
} else if (Array.isArray(classNameInput)) {
|
123
|
+
classNameInput.forEach(cls => {
|
124
|
+
if (Neo.isString(cls)) {
|
125
|
+
if (cls.includes(' ')) {
|
126
|
+
normalizedClasses.push(...cls.split(' ').filter(Boolean))
|
127
|
+
} else if (cls !== '') {
|
128
|
+
normalizedClasses.push(cls)
|
129
|
+
}
|
130
|
+
}
|
131
|
+
})
|
132
|
+
}
|
133
|
+
|
134
|
+
// Remove duplicates if necessary
|
135
|
+
return [...new Set(normalizedClasses)]
|
136
|
+
}
|
137
|
+
|
102
138
|
const ns = Neo.ns('Neo.vdom', true);
|
103
139
|
ns.VNode = VNode;
|
104
140
|
|
package/src/worker/App.mjs
CHANGED
package/src/worker/Base.mjs
CHANGED
@@ -71,8 +71,9 @@ class Worker extends Base {
|
|
71
71
|
gt.onmessage = me.onMessage.bind(me)
|
72
72
|
}
|
73
73
|
|
74
|
-
Neo.currentWorker
|
75
|
-
Neo.
|
74
|
+
Neo.currentWorker = me;
|
75
|
+
Neo.setGlobalConfig = me.setGlobalConfig.bind(me);
|
76
|
+
Neo.workerId = me.workerId
|
76
77
|
}
|
77
78
|
|
78
79
|
/**
|
@@ -220,10 +221,17 @@ class Worker extends Base {
|
|
220
221
|
}
|
221
222
|
|
222
223
|
/**
|
223
|
-
*
|
224
|
+
* Handles the initial registration of the `Neo.config` for this worker's realm.
|
225
|
+
* Triggered when receiving a worker message with `{action: 'registerNeoConfig'}` from the Main Thread's `Neo.worker.Manager`.
|
226
|
+
* This method is primarily responsible for setting the initial global `Neo.config` object in this worker's scope
|
227
|
+
* upon its creation. It also handles associating `windowId` with `MessagePort`s for Shared Workers.
|
228
|
+
*
|
229
|
+
* @param {Object} msg The incoming message object.
|
230
|
+
* @param {Object} msg.data The initial global Neo.config data object.
|
231
|
+
* @param {Number} msg.data.windowId The unique ID of the window/tab (relevant for SharedWorkers).
|
224
232
|
*/
|
225
233
|
onRegisterNeoConfig(msg) {
|
226
|
-
Neo.
|
234
|
+
Neo.ns('Neo.config', true);
|
227
235
|
|
228
236
|
let me = this,
|
229
237
|
{windowId} = msg.data,
|
@@ -236,7 +244,29 @@ class Worker extends Base {
|
|
236
244
|
}
|
237
245
|
}
|
238
246
|
|
239
|
-
|
247
|
+
Neo.merge(Neo.config, msg.data)
|
248
|
+
}
|
249
|
+
|
250
|
+
/**
|
251
|
+
* Handles runtime updates to the global `Neo.config` for this worker's realm.
|
252
|
+
* This method is triggered when receiving a worker message with `{action: 'setNeoConfig'}`
|
253
|
+
* from the Main Thread's `Neo.worker.Manager`. This message signifies a global config change
|
254
|
+
* that originated either from this worker's Main Thread or was broadcast from another
|
255
|
+
* connected browser window via a Shared Worker.
|
256
|
+
*
|
257
|
+
* It merges the incoming configuration changes into this worker's local `Neo.config`
|
258
|
+
* and fires a local `neoConfigChange` event, allowing other instances within this worker
|
259
|
+
* to react to the updated configuration.
|
260
|
+
*
|
261
|
+
* @param {Object} msg The destructured arguments from the message payload.
|
262
|
+
* @param {Object} msg.config The partial or full `Neo.config` object to merge.
|
263
|
+
*/
|
264
|
+
onSetNeoConfig({config}) {
|
265
|
+
let me = this;
|
266
|
+
|
267
|
+
Neo.merge(Neo.config, config);
|
268
|
+
|
269
|
+
me.fire('neoConfigChange', config)
|
240
270
|
}
|
241
271
|
|
242
272
|
/**
|
@@ -307,6 +337,58 @@ class Worker extends Base {
|
|
307
337
|
|
308
338
|
return message
|
309
339
|
}
|
340
|
+
|
341
|
+
/**
|
342
|
+
* Initiates a global Neo.config change from a worker's context.
|
343
|
+
* This method is exposed globally as `Neo.setGlobalConfig` within each worker realm.
|
344
|
+
*
|
345
|
+
* It orchestrates the propagation of the config change to the Main Thread
|
346
|
+
* and, if a Shared Worker is active, across all connected browser windows,
|
347
|
+
* ensuring a single, consistent Neo.config state everywhere.
|
348
|
+
*
|
349
|
+
* You can pass a partial config object to update specific keys.
|
350
|
+
* For nested objects, Neo.mjs performs a deep merge.
|
351
|
+
*
|
352
|
+
* @param {Object} config The partial or full Neo.config object with changes to apply.
|
353
|
+
*/
|
354
|
+
setGlobalConfig(config) {
|
355
|
+
const
|
356
|
+
me = this,
|
357
|
+
{Manager} = Neo.worker; // Remote access proxy object
|
358
|
+
|
359
|
+
// Apply the config change locally to this worker's Neo.config and
|
360
|
+
// trigger its local change events immediately. This ensures immediate
|
361
|
+
// feedback and an updated state for the worker that initiated the change.
|
362
|
+
me.onSetNeoConfig({config});
|
363
|
+
|
364
|
+
if (me.isSharedWorker) {
|
365
|
+
// This block executes when the calling worker instance is a Shared Worker.
|
366
|
+
// This happens if `Neo.config.useSharedWorkers` is true, meaning App, VDom,
|
367
|
+
// Data, Canvas, and Task workers are all SharedWorker instances.
|
368
|
+
// This Shared Worker (the one where setGlobalConfig was called) acts as the
|
369
|
+
// central point to inform all connected Main Threads (browser windows).
|
370
|
+
me.ports.forEach((port, index) => {
|
371
|
+
// Send the config change to each connected Main Thread.
|
372
|
+
// The `broadcast` flag is crucial here for the *receiving* Main Thread:
|
373
|
+
// - `broadcast: true` (for the first port/Main Thread in the list): This Main Thread
|
374
|
+
// will apply the config locally and is then responsible for propagating it to *all*
|
375
|
+
// its own associated Shared Workers connected to that Main Thread),
|
376
|
+
// **excluding the worker that originated this change**.
|
377
|
+
// - `broadcast: false` (for all other ports/Main Threads): These Main Threads
|
378
|
+
// will simply apply the config locally and stop. They are passive recipients
|
379
|
+
// of the broadcast, synchronizing their state without initiating further actions back.
|
380
|
+
// The `excludeOrigin` parameter ensures the originating worker doesn't receive a redundant broadcast.
|
381
|
+
Manager.setNeoConfig({broadcast: index < 1, config, excludeOrigin: me.workerId, windowId: port.windowId})
|
382
|
+
})
|
383
|
+
} else {
|
384
|
+
// This Dedicated Worker (the one where setGlobalConfig was called) informs
|
385
|
+
// its single, connected Main Thread. The Main Thread will then:
|
386
|
+
// 1. Apply the config locally.
|
387
|
+
// 2. Broadcast this change to *all* other Dedicated Workers connected to
|
388
|
+
// *that same Main Thread*, **excluding the sender worker itself**.
|
389
|
+
Manager.setNeoConfig({broadcast: true, config, excludeOrigin: me.workerId})
|
390
|
+
}
|
391
|
+
}
|
310
392
|
}
|
311
393
|
|
312
394
|
export default Neo.setupClass(Worker);
|
package/src/worker/Manager.mjs
CHANGED
@@ -27,11 +27,6 @@ class Manager extends Base {
|
|
27
27
|
* @protected
|
28
28
|
*/
|
29
29
|
className: 'Neo.worker.Manager',
|
30
|
-
/**
|
31
|
-
* @member {Boolean} singleton=true
|
32
|
-
* @protected
|
33
|
-
*/
|
34
|
-
singleton: true,
|
35
30
|
/**
|
36
31
|
* @member {Number} activeWorkers=0
|
37
32
|
* @protected
|
@@ -51,12 +46,29 @@ class Manager extends Base {
|
|
51
46
|
* @member {String[]|Neo.core.Base[]|null} mixins=[Observable, RemoteMethodAccess]
|
52
47
|
*/
|
53
48
|
mixins: [Observable, RemoteMethodAccess],
|
49
|
+
/**
|
50
|
+
* Remote method access for other workers
|
51
|
+
* @member {Object} remote
|
52
|
+
* @protected
|
53
|
+
*/
|
54
|
+
remote: {
|
55
|
+
app : ['setNeoConfig'],
|
56
|
+
canvas: ['setNeoConfig'],
|
57
|
+
data : ['setNeoConfig'],
|
58
|
+
task : ['setNeoConfig'],
|
59
|
+
vdom : ['setNeoConfig']
|
60
|
+
},
|
54
61
|
/**
|
55
62
|
* True in case the current browser supports window.SharedWorker.
|
56
63
|
* @member {Boolean} sharedWorkersEnabled=false
|
57
64
|
* @protected
|
58
65
|
*/
|
59
66
|
sharedWorkersEnabled: false,
|
67
|
+
/**
|
68
|
+
* @member {Boolean} singleton=true
|
69
|
+
* @protected
|
70
|
+
*/
|
71
|
+
singleton: true,
|
60
72
|
/**
|
61
73
|
* Internal flag to stop the worker communication in case their creation fails
|
62
74
|
* @member {Boolean} stopCommunication=false
|
@@ -71,7 +83,7 @@ class Manager extends Base {
|
|
71
83
|
*/
|
72
84
|
webWorkersEnabled: false,
|
73
85
|
/**
|
74
|
-
* Using the current timestamp as
|
86
|
+
* Using the current timestamp as a unique window identifier
|
75
87
|
* @member {Number} windowId=new Date().getTime()
|
76
88
|
* @protected
|
77
89
|
*/
|
@@ -121,7 +133,8 @@ class Manager extends Base {
|
|
121
133
|
|
122
134
|
!Neo.insideWorker && me.createWorkers();
|
123
135
|
|
124
|
-
Neo.
|
136
|
+
Neo.setGlobalConfig = me.setGlobalConfig.bind(me);
|
137
|
+
Neo.workerId = 'main';
|
125
138
|
|
126
139
|
me.promises = {};
|
127
140
|
|
@@ -136,18 +149,18 @@ class Manager extends Base {
|
|
136
149
|
|
137
150
|
/**
|
138
151
|
* Sends a message to each worker defined inside the this.workers config.
|
139
|
-
*
|
152
|
+
* Only sends to workers that are currently active and available.
|
153
|
+
* @param {Object} msg The message payload to broadcast.
|
154
|
+
* @param {Object} [excludeOrigin] Optionally pass the origin realm name to exclude from the broadcast.
|
140
155
|
*/
|
141
|
-
broadcast(msg) {
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
name
|
147
|
-
)) {
|
148
|
-
this.sendMessage(name, msg)
|
156
|
+
broadcast(msg, excludeOrigin) {
|
157
|
+
let me = this;
|
158
|
+
|
159
|
+
Object.keys(me.workers).forEach(name => {
|
160
|
+
if (name !== excludeOrigin && me.getWorker(name)) {
|
161
|
+
me.sendMessage(name, msg)
|
149
162
|
}
|
150
|
-
})
|
163
|
+
})
|
151
164
|
}
|
152
165
|
|
153
166
|
/**
|
@@ -325,8 +338,10 @@ class Manager extends Base {
|
|
325
338
|
data = data.data
|
326
339
|
}
|
327
340
|
|
328
|
-
|
329
|
-
|
341
|
+
if (data) {
|
342
|
+
promise[data.reject ? 'reject' : 'resolve'](data);
|
343
|
+
delete me.promises[replyId]
|
344
|
+
}
|
330
345
|
}
|
331
346
|
}
|
332
347
|
|
@@ -385,7 +400,14 @@ class Manager extends Base {
|
|
385
400
|
|
386
401
|
return new Promise((resolve, reject) => {
|
387
402
|
let message = me.sendMessage(dest, opts, transfer),
|
388
|
-
msgId
|
403
|
+
msgId;
|
404
|
+
|
405
|
+
if (!message) {
|
406
|
+
reject(new Error(me.stopCommunication ? 'Communication is stopped.' : `Target worker '${dest}' does not exist.`));
|
407
|
+
return
|
408
|
+
}
|
409
|
+
|
410
|
+
msgId = message.id;
|
389
411
|
|
390
412
|
me.promises[msgId] = {reject, resolve}
|
391
413
|
})
|
@@ -412,7 +434,7 @@ class Manager extends Base {
|
|
412
434
|
* @param {Array} [transfer] An optional array of Transferable objects to transfer ownership of.
|
413
435
|
* If the ownership of an object is transferred, it becomes unusable (neutered) in the context it was sent from
|
414
436
|
* and becomes available only to the worker it was sent to.
|
415
|
-
* @returns {Neo.worker.Message}
|
437
|
+
* @returns {Neo.worker.Message|null}
|
416
438
|
* @protected
|
417
439
|
*/
|
418
440
|
sendMessage(dest, opts, transfer) {
|
@@ -427,17 +449,53 @@ class Manager extends Base {
|
|
427
449
|
worker = me.getWorker(dest)
|
428
450
|
}
|
429
451
|
|
430
|
-
if (
|
431
|
-
|
452
|
+
if (worker) {
|
453
|
+
opts.destination = dest;
|
454
|
+
|
455
|
+
message = new Message(opts);
|
456
|
+
|
457
|
+
(worker.port ? worker.port : worker).postMessage(message, transfer);
|
458
|
+
return message
|
432
459
|
}
|
460
|
+
}
|
461
|
+
|
462
|
+
return null
|
463
|
+
}
|
464
|
+
|
465
|
+
/**
|
466
|
+
* Initiates a global Neo.config change from the Main Thread.
|
467
|
+
*
|
468
|
+
* This method acts as a proxy, routing the config change request to the App Worker.
|
469
|
+
* This design centralizes the complex multi-threaded and multi-window synchronization
|
470
|
+
* logic within the App Worker's `setGlobalConfig` method.
|
471
|
+
*
|
472
|
+
* Developers should typically use `Neo.setGlobalConfig(config)` directly,
|
473
|
+
* which will correctly resolve to this proxy when called from the Main Thread.
|
474
|
+
*
|
475
|
+
* @param {Object} config The partial or full Neo.config object with changes to apply.
|
476
|
+
*/
|
477
|
+
setGlobalConfig(config) {
|
478
|
+
// Remotely calls the App Worker's setGlobalConfig method.
|
479
|
+
// This ensures all global config changes are processed through the App Worker
|
480
|
+
// which contains the centralized multi-window synchronization logic.
|
481
|
+
Neo.worker.App.setGlobalConfig(config)
|
482
|
+
}
|
433
483
|
|
434
|
-
|
484
|
+
/**
|
485
|
+
* Change Neo.config globally from a worker
|
486
|
+
* @param {Object} data
|
487
|
+
* @param {Boolean} data.broadcast
|
488
|
+
* @param {Object} data.config
|
489
|
+
* @param {String} [data.excludeOrigin]
|
490
|
+
*/
|
491
|
+
setNeoConfig({broadcast, config, excludeOrigin}) {
|
492
|
+
let me = this;
|
435
493
|
|
436
|
-
|
494
|
+
Neo.merge(Neo.config, config);
|
437
495
|
|
438
|
-
|
439
|
-
|
440
|
-
}
|
496
|
+
me.fire('neoConfigChange', config);
|
497
|
+
|
498
|
+
broadcast && me.broadcast({action: 'setNeoConfig', config}, excludeOrigin)
|
441
499
|
}
|
442
500
|
}
|
443
501
|
|
@@ -1,50 +0,0 @@
|
|
1
|
-
{"data": [
|
2
|
-
{"name": "Using These Topics", "parentId": null, "id": "UsingTheseTopics" },
|
3
|
-
{"name": "Benefits", "parentId": null, "isLeaf": false, "id": "Benefits"},
|
4
|
-
{"name": "Introduction ", "parentId": "Benefits", "id": "benefits.Introduction"},
|
5
|
-
{"name": "Off the Main Thread", "parentId": "Benefits", "id": "benefits.OffTheMainThread"},
|
6
|
-
{"name": "4 Environments", "parentId": "Benefits", "id": "benefits.FourEnvironments"},
|
7
|
-
{"name": "Unified Config System", "parentId": "Benefits", "id": "benefits.ConfigSystem"},
|
8
|
-
{"name": "Extreme Speed", "parentId": "Benefits", "id": "benefits.Speed"},
|
9
|
-
{"name": "Multi-Window Applications", "parentId": "Benefits", "id": "benefits.MultiWindow"},
|
10
|
-
{"name": "Quick Application Development", "parentId": "Benefits", "id": "benefits.Quick"},
|
11
|
-
{"name": "Complexity and Effort", "parentId": "Benefits", "id": "benefits.Effort"},
|
12
|
-
{"name": "Forms Engine", "parentId": "Benefits", "id": "benefits.FormsEngine"},
|
13
|
-
{"name": "Features and Benefits Summary", "parentId": "Benefits", "id": "benefits.Features"},
|
14
|
-
{"name": "Getting Started", "parentId": null, "isLeaf": false, "id": "GettingStarted", "collapsed": true},
|
15
|
-
{"name": "Setup", "parentId": "GettingStarted", "id": "gettingstarted.Setup"},
|
16
|
-
{"name": "Workspaces and Applications", "parentId": "GettingStarted", "id": "gettingstarted.Workspaces"},
|
17
|
-
{"name": "Describing a View", "parentId": "GettingStarted", "id": "gettingstarted.DescribingTheUI"},
|
18
|
-
{"name": "Events", "parentId": "GettingStarted", "id": "gettingstarted.Events"},
|
19
|
-
{"name": "Component References", "parentId": "GettingStarted", "id": "gettingstarted.References"},
|
20
|
-
{"name": "Extending Classes", "parentId": "GettingStarted", "id": "gettingstarted.Extending"},
|
21
|
-
{"name": "Config", "parentId": "GettingStarted", "id": "gettingstarted.Config"},
|
22
|
-
{"name": "Shared Bindable Data", "parentId": "GettingStarted", "id": "gettingstarted.ComponentModels"},
|
23
|
-
{"name": "Tutorials", "parentId": null, "isLeaf": false, "id": "Tutorials", "collapsed": true},
|
24
|
-
{"name": "Rock Scissors Paper", "parentId": "Tutorials", "id": "tutorials.RSP", "hidden": true},
|
25
|
-
{"name": "Earthquakes", "parentId": "Tutorials", "id": "tutorials.Earthquakes"},
|
26
|
-
{"name": "Todo List", "parentId": "Tutorials", "id": "tutorials.TodoList"},
|
27
|
-
{"name": "Guides", "parentId": null, "isLeaf": false, "id": "InDepth", "collapsed": true},
|
28
|
-
{"name": "Instance Lifecycle", "parentId": "InDepth", "id": "guides.InstanceLifecycle", "hidden": true},
|
29
|
-
{"name": "User Input (Forms)", "parentId": "InDepth", "id": "guides.Forms", "hidden": true},
|
30
|
-
{"name": "Component and Container Basics", "parentId": "InDepth", "id": "guides.ComponentsAndContainers"},
|
31
|
-
{"name": "Layouts", "parentId": "InDepth", "isLeaf": false, "id": "guides.Layouts", "hidden": true},
|
32
|
-
{"name": "Shared Bindable Data (State Providers)", "parentId": "InDepth", "id": "guides.StateProviders"},
|
33
|
-
{"name": "Custom Components", "parentId": "InDepth", "id": "guides.CustomComponents", "hidden": true},
|
34
|
-
{"name": "Events", "parentId": "InDepth", "isLeaf": false, "id": "GuideEvents"},
|
35
|
-
{"name": "Custom Events", "parentId": "GuideEvents", "id": "guides.events.CustomEvents"},
|
36
|
-
{"name": "DOM Events", "parentId": "GuideEvents", "id": "guides.events.DomEvents"},
|
37
|
-
{"name": "Portal App", "parentId": "InDepth", "id": "guides.PortalApp"},
|
38
|
-
{"name": "Tables (Stores)", "parentId": "InDepth", "id": "guides.Tables", "hidden": true},
|
39
|
-
{"name": "Multi-Window Applications", "parentId": "InDepth", "id": "guides.MultiWindow", "hidden": true},
|
40
|
-
{"name": "Main Thread Addons", "parentId": "InDepth", "isLeaf": false, "id": "MainThreadAddons", "hidden": true},
|
41
|
-
{"name": "Introduction", "parentId": "MainThreadAddons", "id": "guides.MainThreadAddonIntro"},
|
42
|
-
{"name": "Example", "parentId": "MainThreadAddons", "id": "guides.MainThreadAddonExample"},
|
43
|
-
{"name": "Mixins", "parentId": "InDepth", "id": "guides.Mixins", "hidden": true},
|
44
|
-
{"name": "JavaScript Classes", "parentId": null, "isLeaf": false, "id": "JavaScript", "hidden": true},
|
45
|
-
{"name": "Classes, Properties, and Methods", "parentId": "JavaScript", "id": "javascript.Classes"},
|
46
|
-
{"name": "Overriding Methods", "parentId": "JavaScript", "id": "javascript.Overrides"},
|
47
|
-
{"name": "Other JavaScript Class Features", "parentId": "JavaScript", "id": "javascript.ClassFeatures"},
|
48
|
-
{"name": "Super", "parentId": "JavaScript", "id": "javascript.Super"},
|
49
|
-
{"name": "New Node", "parentId": "JavaScript", "id": "javascript.NewNode"}
|
50
|
-
]}
|
@@ -1,80 +0,0 @@
|
|
1
|
-
|
2
|
-
#hi
|
3
|
-
|
4
|
-
|
5
|
-
Neo.mjs is a framework used to create browser-based applications.
|
6
|
-
|
7
|
-
Some key features and benefits of Neo.mjs are:
|
8
|
-
|
9
|
-
<div type="expander" caption="Multi-Threaded">
|
10
|
-
<p>
|
11
|
-
When a Neo.mjs application starts, the framework spawns three web-workers.
|
12
|
-
Web-workers are each run in their own thread. As a result, a typical Neo.mjs application
|
13
|
-
has four threads:
|
14
|
-
<ol>
|
15
|
-
<li>The _main_ thread, where DOM updates are applied
|
16
|
-
<li>An _application_ web-worker where normal application locic is run
|
17
|
-
<li>A _data_ web-worker were HTTP and socket calls are run
|
18
|
-
<li>A _view_ web-worker that manages delta updates
|
19
|
-
</ol>
|
20
|
-
</div>
|
21
|
-
|
22
|
-
<div type="expander" caption="Extreme Speed">
|
23
|
-
<p>
|
24
|
-
The Neo.mjs web-worker proccesses are automatically run in parallel, on separate CPU cores.
|
25
|
-
</p>
|
26
|
-
<p>
|
27
|
-
By contrast, other JavaScript frameworks run in a single thread. That means
|
28
|
-
in a typical framework all business logic, data handling, and DOM rendering compete for
|
29
|
-
CPU reasources.
|
30
|
-
</p>
|
31
|
-
<p>
|
32
|
-
This means Neo.mjs applications run and render faster. This is
|
33
|
-
particularly beneficial for processor- and data-intensive applications,
|
34
|
-
and applications that need to rapidly update what's viewed. In testing, Neo.mjs applications
|
35
|
-
easily apply over 20,000 DOM updates per second.
|
36
|
-
</p>
|
37
|
-
<p>
|
38
|
-
If the default four threads aren't enough, you're free to launch additional web-worker threads
|
39
|
-
to run other specialized logic.
|
40
|
-
</p>
|
41
|
-
</div>
|
42
|
-
|
43
|
-
<div type="expander" caption="Quick Application Development">
|
44
|
-
<p>
|
45
|
-
Neo.js classes let you specify properties in a way that allows code to detect "before" and "after"
|
46
|
-
changes. This makes it easy to handle value validation and transformation, and react to changes.
|
47
|
-
</p>
|
48
|
-
<p>
|
49
|
-
Neo.mjs also has elegant yet powerful state management features that make it easy to create shared,
|
50
|
-
bindable data. For example, if two components are bound to the same propery, a change to the
|
51
|
-
property will automatically be applied to both components.
|
52
|
-
</p>
|
53
|
-
</div>
|
54
|
-
|
55
|
-
<div type="expander" caption="Multi-Window Applications">
|
56
|
-
<p>
|
57
|
-
Neo.mjs applications can also launch as _shared web workers_, which allows you to have a single
|
58
|
-
application run in multiple browser windows; those windows could be moved to multiple monitors.
|
59
|
-
</p>
|
60
|
-
<p>
|
61
|
-
For example, you can have a data analysis application with a control panel on one monitor,
|
62
|
-
tabular data in another, and charts on another — all sharing the same data, handling events
|
63
|
-
across windows, running seamlessly as a single application.
|
64
|
-
</p>
|
65
|
-
</div>
|
66
|
-
|
67
|
-
<div type="expander" caption="Open-Source and Standards-Based">
|
68
|
-
<p>
|
69
|
-
Neo.mjs is an open-source library. Features needed for the community can be added to the
|
70
|
-
library via pull-requests. And since Neo.mjs uses the standard JavaScript class system,
|
71
|
-
all Neo.mjs classes can be extended.
|
72
|
-
</p>
|
73
|
-
<p>
|
74
|
-
Neo.mjs uses standard modular JavaScript, so developers don't need to learn non-standard language
|
75
|
-
syntax, and there's no need for special pre-compilers or WebPack modules.
|
76
|
-
That means fewer dependencies and easier configuration. Furthermore, the use of
|
77
|
-
standard JavaScript makes debugging easier: any statement you write while developing your
|
78
|
-
applcation can also be run in the debugging console.
|
79
|
-
</p>
|
80
|
-
</div>
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|