neo.mjs 7.0.5 → 7.1.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.
- package/README.md +2 -2
- package/apps/ServiceWorker.mjs +2 -2
- package/apps/portal/index.html +1 -1
- package/apps/portal/model/Content.mjs +3 -2
- package/apps/portal/view/home/FooterContainer.mjs +1 -1
- package/apps/portal/view/home/parts/Features.mjs +5 -5
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/todoList/version2/MainContainer.mjs +38 -48
- package/examples/todoList/version2/TodoList.mjs +6 -39
- package/examples/todoList/version2/TodoListModel.mjs +1 -1
- package/package.json +7 -7
- package/resources/data/deck/learnneo/pages/Welcome.md +0 -4
- package/resources/data/deck/learnneo/pages/guides/Forms.md +1 -0
- package/resources/data/deck/learnneo/pages/guides/InstanceLifecycle.md +1 -0
- package/resources/data/deck/learnneo/pages/guides/Layouts.md +1 -0
- package/resources/data/deck/learnneo/pages/guides/Mixins.md +1 -0
- package/resources/data/deck/learnneo/pages/guides/MultiWindow.md +1 -0
- package/resources/data/deck/learnneo/pages/guides/Tables.md +1 -0
- package/resources/data/deck/learnneo/pages/guides/events/DomEvents.md +263 -0
- package/resources/data/deck/learnneo/pages/{TodoList.md → tutorials/TodoList.md} +23 -33
- package/resources/data/deck/learnneo/tree.json +45 -48
- package/resources/scss/src/component/Splitter.scss +10 -1
- package/resources/scss/theme-dark/component/Splitter.scss +6 -3
- package/resources/scss/theme-light/component/Splitter.scss +6 -3
- package/resources/scss/theme-neo-light/component/Splitter.scss +6 -20
- package/src/DefaultConfig.mjs +2 -2
- package/src/code/LivePreview.mjs +28 -1
- package/src/collection/Base.mjs +1 -0
- package/src/component/Splitter.mjs +22 -4
- package/src/controller/Component.mjs +10 -10
- package/src/core/Observable.mjs +4 -27
- package/src/draggable/DragZone.mjs +6 -5
- package/src/grid/View.mjs +82 -0
- package/src/list/Base.mjs +16 -0
- package/src/main/addon/DragDrop.mjs +3 -2
- package/src/manager/DomEvent.mjs +30 -18
- package/src/table/View.mjs +82 -0
- package/src/util/Function.mjs +24 -0
- package/resources/data/deck/learnneo/pages/2023-10-08T20-37-30-658Z.md +0 -0
- package/resources/data/deck/learnneo/pages/2023-10-08T22-22-11-013Z.md +0 -0
- package/resources/data/deck/learnneo/pages/Earthquakes-01-goals.md +0 -32
- package/resources/data/deck/learnneo/pages/Earthquakes-Lab-01-generate-a-workspace.md +0 -47
- package/resources/data/deck/learnneo/pages/Earthquakes-Lab-02-generate-the-starter-app.md +0 -150
- package/resources/data/deck/learnneo/pages/Earthquakes-Lab-03-debugging.md +0 -136
- package/resources/data/deck/learnneo/pages/Earthquakes-Lab-04-fetch-data.md +0 -146
- package/resources/data/deck/learnneo/pages/Earthquakes-Lab-05-refactor-the-table.md +0 -146
- package/resources/data/deck/learnneo/pages/Earthquakes-Lab-06-use-a-view-model.md +0 -301
- package/resources/data/deck/learnneo/pages/Earthquakes-Lab-07-use-the-google-maps-addon.md +0 -175
- package/resources/data/deck/learnneo/pages/Earthquakes-Lab-08-events.md +0 -38
- package/resources/data/deck/learnneo/pages/TestLivePreview.md +0 -32
- package/resources/data/deck/learnneo/pages/WhatAboutHTML.md +0 -1
- package/resources/data/deck/learnneo/pages/stylesheet.md +0 -57
- /package/resources/data/deck/learnneo/pages/{WhyNeo-Effort.md → benefits/Effort.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{WhyNeo-Features.md → benefits/Features.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{WhyNeo-Intro.md → benefits/Introduction.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{WhyNeo-Multi-Window.md → benefits/Multi-Window.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{WhyNeo-Quick.md → benefits/Quick.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{WhyNeo-Speed.md → benefits/Speed.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{ComponentModels.md → gettingstarted/ComponentModels.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{Config.md → gettingstarted/Config.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{DescribingTheUI.md → gettingstarted/DescribingTheUI.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{Events.md → gettingstarted/Events.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{Extending.md → gettingstarted/Extending.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{References.md → gettingstarted/References.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{Setup.md → gettingstarted/Setup.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{2023-10-14T19-25-08-153Z.md → gettingstarted/Workspaces.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{ComponentsAndContainers.md → guides/ComponentsAndContainers.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{CustomComponents.md → guides/CustomComponents.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{MainThreadAddonExample.md → guides/MainThreadAddonExample.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{MainThreadAddonIntro.md → guides/MainThreadAddonIntro.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{GuideViewModels.md → guides/ViewModels.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{GuideEvents.md → guides/events/CustomEvents.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{2023-10-08T20-20-37-336Z.md → javascript/ClassFeatures.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{2023-10-07T19-18-28-517Z.md → javascript/Classes.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{2023-10-31T13-59-37-550Z.md → javascript/NewNode.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{2023-10-08T20-20-07-934Z.md → javascript/Overrides.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{2023-10-08T21-58-25-809Z.md → javascript/Super.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{Earthquakes.md → tutorials/Earthquakes.md} +0 -0
- /package/resources/data/deck/learnneo/pages/{RSP.md → tutorials/RSP.md} +0 -0
package/src/grid/View.mjs
CHANGED
@@ -23,6 +23,27 @@ class View extends Component {
|
|
23
23
|
baseCls: ['neo-grid-view']
|
24
24
|
}
|
25
25
|
|
26
|
+
/**
|
27
|
+
* @param config
|
28
|
+
*/
|
29
|
+
construct(config) {
|
30
|
+
super.construct(config);
|
31
|
+
|
32
|
+
let me = this;
|
33
|
+
|
34
|
+
me.addDomListeners([{
|
35
|
+
click : me.onCellClick,
|
36
|
+
dblclick: me.onCellDoubleClick,
|
37
|
+
delegate: '.neo-grid-cell',
|
38
|
+
scope : me
|
39
|
+
}, {
|
40
|
+
click : me.onRowClick,
|
41
|
+
dblclick: me.onRowDoubleClick,
|
42
|
+
delegate: '.neo-grid-row',
|
43
|
+
scope : me
|
44
|
+
}])
|
45
|
+
}
|
46
|
+
|
26
47
|
/**
|
27
48
|
* @param {Array} inputData
|
28
49
|
*/
|
@@ -169,6 +190,39 @@ class View extends Component {
|
|
169
190
|
super.destroy(updateParentVdom, silent)
|
170
191
|
}
|
171
192
|
|
193
|
+
/**
|
194
|
+
* @param {Object} data
|
195
|
+
* @param {String} eventName
|
196
|
+
*/
|
197
|
+
fireCellEvent(data, eventName) {
|
198
|
+
let me = this,
|
199
|
+
{id} = data.target,
|
200
|
+
dataField = me.getCellDataField(id),
|
201
|
+
record = me.getRecord(id);
|
202
|
+
|
203
|
+
me.parent.fire(eventName, {id: me, data, dataField, record})
|
204
|
+
}
|
205
|
+
|
206
|
+
/**
|
207
|
+
* @param {Object} data
|
208
|
+
* @param {String} eventName
|
209
|
+
*/
|
210
|
+
fireRowEvent(data, eventName) {
|
211
|
+
let me = this,
|
212
|
+
{id} = data.target,
|
213
|
+
record = me.getRecord(id);
|
214
|
+
|
215
|
+
me.parent.fire(eventName, {id: me, data, record})
|
216
|
+
}
|
217
|
+
|
218
|
+
/**
|
219
|
+
* @param {String} cellId
|
220
|
+
* @returns {String}
|
221
|
+
*/
|
222
|
+
getCellDataField(cellId) {
|
223
|
+
return cellId.split('__')[2]
|
224
|
+
}
|
225
|
+
|
172
226
|
/**
|
173
227
|
* @param {Object} record
|
174
228
|
* @param {String} field
|
@@ -232,6 +286,34 @@ class View extends Component {
|
|
232
286
|
return ['neo-grid-row']
|
233
287
|
}
|
234
288
|
|
289
|
+
/**
|
290
|
+
* @param {Object} data
|
291
|
+
*/
|
292
|
+
onCellClick(data) {
|
293
|
+
this.fireCellEvent(data, 'cellClick')
|
294
|
+
}
|
295
|
+
|
296
|
+
/**
|
297
|
+
* @param {Object} data
|
298
|
+
*/
|
299
|
+
onCellDoubleClick(data) {
|
300
|
+
this.fireCellEvent(data, 'cellDoubleClick')
|
301
|
+
}
|
302
|
+
|
303
|
+
/**
|
304
|
+
* @param {Object} data
|
305
|
+
*/
|
306
|
+
onRowClick(data) {
|
307
|
+
this.fireRowEvent(data, 'rowClick')
|
308
|
+
}
|
309
|
+
|
310
|
+
/**
|
311
|
+
* @param {Object} data
|
312
|
+
*/
|
313
|
+
onRowDoubleClick(data) {
|
314
|
+
this.fireRowEvent(data, 'rowDoubleClick')
|
315
|
+
}
|
316
|
+
|
235
317
|
/**
|
236
318
|
* Gets triggered after changing the value of a record field.
|
237
319
|
* E.g. myRecord.foo = 'bar';
|
package/src/list/Base.mjs
CHANGED
@@ -409,6 +409,22 @@ class Base extends Component {
|
|
409
409
|
me.cls = cls
|
410
410
|
}
|
411
411
|
|
412
|
+
/**
|
413
|
+
* Triggered after the windowId config got changed
|
414
|
+
* @param {Number} value
|
415
|
+
* @param {Number} oldValue
|
416
|
+
* @protected
|
417
|
+
*/
|
418
|
+
afterSetWindowId(value, oldValue) {
|
419
|
+
super.afterSetWindowId(value, oldValue);
|
420
|
+
|
421
|
+
let {navigator} = this;
|
422
|
+
|
423
|
+
if (navigator) {
|
424
|
+
navigator.windowId = value
|
425
|
+
}
|
426
|
+
}
|
427
|
+
|
412
428
|
/**
|
413
429
|
* Triggered before the selectionModel config gets changed.
|
414
430
|
* @param {Neo.selection.Model} value
|
@@ -153,8 +153,8 @@ class DragDrop extends Base {
|
|
153
153
|
|
154
154
|
Promise.all(imports).then(modules => {
|
155
155
|
// create the Mouse- and / or TouchSensor
|
156
|
-
|
157
|
-
module:
|
156
|
+
modules.forEach(module => {
|
157
|
+
Neo.create({module: module.default})
|
158
158
|
})
|
159
159
|
})
|
160
160
|
}
|
@@ -461,6 +461,7 @@ class DragDrop extends Base {
|
|
461
461
|
node;
|
462
462
|
|
463
463
|
delete data.appName;
|
464
|
+
delete data.windowId;
|
464
465
|
|
465
466
|
if (data.boundaryContainerId) {
|
466
467
|
node = DomAccess.getElementOrBody(data.boundaryContainerId);
|
package/src/manager/DomEvent.mjs
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
import Base
|
2
|
-
import ComponentManager
|
3
|
-
import FocusManager
|
4
|
-
import Logger
|
5
|
-
import NeoArray
|
6
|
-
import
|
1
|
+
import Base from '../core/Base.mjs';
|
2
|
+
import ComponentManager from './Component.mjs';
|
3
|
+
import FocusManager from './Focus.mjs';
|
4
|
+
import Logger from '../util/Logger.mjs';
|
5
|
+
import NeoArray from '../util/Array.mjs';
|
6
|
+
import {resolveCallback} from '../util/Function.mjs';
|
7
|
+
import VDomUtil from '../util/VDom.mjs';
|
7
8
|
|
8
9
|
const eventConfigKeys = [
|
9
10
|
'bubble',
|
@@ -192,10 +193,12 @@ class DomEvent extends Base {
|
|
192
193
|
*/
|
193
194
|
generateListenerConfig(config, scope) {
|
194
195
|
return {
|
196
|
+
bubble : config.bubble,
|
195
197
|
delegate : config.delegate,
|
196
198
|
eventName: config.eventName,
|
197
199
|
id : scope.id,
|
198
200
|
opts : config,
|
201
|
+
priority : config.priority,
|
199
202
|
scope : config.scope || scope,
|
200
203
|
vnodeId : config.vnodeId || scope.id
|
201
204
|
};
|
@@ -217,6 +220,7 @@ class DomEvent extends Base {
|
|
217
220
|
|
218
221
|
/**
|
219
222
|
* @param {Object} config
|
223
|
+
* @param {Boolean} config.bubble
|
220
224
|
* @param {String} config.delegate
|
221
225
|
* @param {String} config.eventName
|
222
226
|
* @param {String} config.id
|
@@ -264,9 +268,10 @@ class DomEvent extends Base {
|
|
264
268
|
|
265
269
|
if (localEvents.length > 0) {
|
266
270
|
Neo.worker.App.promiseMessage('main', {
|
267
|
-
action
|
268
|
-
appName: component.appName,
|
269
|
-
events
|
271
|
+
action : 'addDomListener',
|
272
|
+
appName : component.appName,
|
273
|
+
events : localEvents,
|
274
|
+
windowId: component.windowId
|
270
275
|
}).then(data => {
|
271
276
|
// console.log('added domListener', data);
|
272
277
|
}).catch(err => {
|
@@ -278,6 +283,7 @@ class DomEvent extends Base {
|
|
278
283
|
|
279
284
|
/**
|
280
285
|
* @param {Object} config
|
286
|
+
* @param {Boolean} config.bubble
|
281
287
|
* @param {String} config.delegate
|
282
288
|
* @param {String} config.eventName
|
283
289
|
* @param {String} config.id
|
@@ -285,20 +291,23 @@ class DomEvent extends Base {
|
|
285
291
|
* @param {Number} config.opts
|
286
292
|
* @param {Number} config.originalConfig
|
287
293
|
* @param {String} config.ownerId
|
288
|
-
* @param {Number} config.priority
|
294
|
+
* @param {Number} config.priority=1
|
289
295
|
* @param {Object} config.scope
|
290
296
|
* @param {String} config.vnodeId
|
291
297
|
* @returns {Boolean} true if the listener got registered successfully (false in case it was already there)
|
292
298
|
*/
|
293
299
|
register(config) {
|
294
|
-
let
|
300
|
+
let me = this,
|
301
|
+
alreadyRegistered = false,
|
295
302
|
{eventName, id, opts, scope} = config,
|
296
|
-
listeners =
|
303
|
+
listeners = me.items,
|
297
304
|
fnType = typeof opts,
|
298
305
|
fn, listener, listenerConfig, listenerId;
|
299
306
|
|
300
|
-
if (fnType === 'function'
|
307
|
+
if (fnType === 'function') {
|
301
308
|
fn = opts
|
309
|
+
} else if (fnType === 'string') {
|
310
|
+
fn = resolveCallback(opts, scope).fn
|
302
311
|
} else {
|
303
312
|
fn = opts.fn;
|
304
313
|
scope = opts.scope || scope
|
@@ -343,22 +352,23 @@ class DomEvent extends Base {
|
|
343
352
|
mounted : !config.local && globalDomEvents.includes(eventName),
|
344
353
|
originalConfig: config.originalConfig,
|
345
354
|
ownerId : config.ownerId,
|
346
|
-
priority : config.priority || 1,
|
355
|
+
priority : config.priority || opts.priority || 1,
|
347
356
|
scope,
|
348
357
|
vnodeId : config.vnodeId
|
349
358
|
};
|
350
359
|
|
351
|
-
|
360
|
+
me.map[listenerId] = listenerConfig;
|
352
361
|
|
353
362
|
listeners[id][eventName].push(listenerConfig);
|
354
363
|
|
355
|
-
listeners[id][eventName].sort((a, b) =>
|
364
|
+
listeners[id][eventName].sort((a, b) => b.priority - a.priority);
|
356
365
|
|
357
366
|
return true
|
358
367
|
}
|
359
368
|
|
360
369
|
/**
|
361
370
|
* @param {Object} config
|
371
|
+
* @param {Boolean} config.bubble
|
362
372
|
* @param {String} config.eventName
|
363
373
|
* @param {String} config.id
|
364
374
|
* @param {Object} config.opts
|
@@ -414,14 +424,16 @@ class DomEvent extends Base {
|
|
414
424
|
Object.entries(domListener).forEach(([key, value]) => {
|
415
425
|
if (!eventConfigKeys.includes(key)) {
|
416
426
|
me.register({
|
427
|
+
bubble : domListener.bubble || value.bubble,
|
417
428
|
delegate : domListener.delegate || value.delegate || '#' + component.id,
|
418
429
|
eventName : key,
|
419
430
|
id : component.id,
|
420
431
|
opts : value,
|
421
432
|
originalConfig: domListener,
|
422
433
|
ownerId : component.id,
|
423
|
-
|
424
|
-
|
434
|
+
priority : domListener.priority || value.priority || 1,
|
435
|
+
scope : domListener.scope || component,
|
436
|
+
vnodeId : domListener.vnodeId || value.vnodeId || component.id
|
425
437
|
})
|
426
438
|
}
|
427
439
|
})
|
package/src/table/View.mjs
CHANGED
@@ -50,6 +50,27 @@ class View extends Component {
|
|
50
50
|
{tag: 'tbody', cn: []}
|
51
51
|
}
|
52
52
|
|
53
|
+
/**
|
54
|
+
* @param config
|
55
|
+
*/
|
56
|
+
construct(config) {
|
57
|
+
super.construct(config);
|
58
|
+
|
59
|
+
let me = this;
|
60
|
+
|
61
|
+
me.addDomListeners([{
|
62
|
+
click : me.onCellClick,
|
63
|
+
dblclick: me.onCellDoubleClick,
|
64
|
+
delegate: '.neo-table-cell',
|
65
|
+
scope : me
|
66
|
+
}, {
|
67
|
+
click : me.onRowClick,
|
68
|
+
dblclick: me.onRowDoubleClick,
|
69
|
+
delegate: '.neo-table-row',
|
70
|
+
scope : me
|
71
|
+
}])
|
72
|
+
}
|
73
|
+
|
53
74
|
/**
|
54
75
|
* @param {Object} data
|
55
76
|
* @param {String} [data.cellId]
|
@@ -246,6 +267,39 @@ class View extends Component {
|
|
246
267
|
super.destroy(...args)
|
247
268
|
}
|
248
269
|
|
270
|
+
/**
|
271
|
+
* @param {Object} data
|
272
|
+
* @param {String} eventName
|
273
|
+
*/
|
274
|
+
fireCellEvent(data, eventName) {
|
275
|
+
let me = this,
|
276
|
+
{id} = data.target,
|
277
|
+
dataField = me.getCellDataField(id),
|
278
|
+
record = me.getRecord(id);
|
279
|
+
|
280
|
+
me.parent.fire(eventName, {id: me, data, dataField, record})
|
281
|
+
}
|
282
|
+
|
283
|
+
/**
|
284
|
+
* @param {Object} data
|
285
|
+
* @param {String} eventName
|
286
|
+
*/
|
287
|
+
fireRowEvent(data, eventName) {
|
288
|
+
let me = this,
|
289
|
+
{id} = data.target,
|
290
|
+
record = me.getRecord(id);
|
291
|
+
|
292
|
+
me.parent.fire(eventName, {id: me, data, record})
|
293
|
+
}
|
294
|
+
|
295
|
+
/**
|
296
|
+
* @param {String} cellId
|
297
|
+
* @returns {String}
|
298
|
+
*/
|
299
|
+
getCellDataField(cellId) {
|
300
|
+
return cellId.split('__')[2]
|
301
|
+
}
|
302
|
+
|
249
303
|
/**
|
250
304
|
* @param {Object} record
|
251
305
|
* @param {String} dataField
|
@@ -341,6 +395,34 @@ class View extends Component {
|
|
341
395
|
return ['neo-table-row']
|
342
396
|
}
|
343
397
|
|
398
|
+
/**
|
399
|
+
* @param {Object} data
|
400
|
+
*/
|
401
|
+
onCellClick(data) {
|
402
|
+
this.fireCellEvent(data, 'cellClick')
|
403
|
+
}
|
404
|
+
|
405
|
+
/**
|
406
|
+
* @param {Object} data
|
407
|
+
*/
|
408
|
+
onCellDoubleClick(data) {
|
409
|
+
this.fireCellEvent(data, 'cellDoubleClick')
|
410
|
+
}
|
411
|
+
|
412
|
+
/**
|
413
|
+
* @param {Object} data
|
414
|
+
*/
|
415
|
+
onRowClick(data) {
|
416
|
+
this.fireRowEvent(data, 'rowClick')
|
417
|
+
}
|
418
|
+
|
419
|
+
/**
|
420
|
+
* @param {Object} data
|
421
|
+
*/
|
422
|
+
onRowDoubleClick(data) {
|
423
|
+
this.fireRowEvent(data, 'rowDoubleClick')
|
424
|
+
}
|
425
|
+
|
344
426
|
/**
|
345
427
|
* Gets triggered after changing the value of a record field.
|
346
428
|
* E.g. myRecord.foo = 'bar';
|
package/src/util/Function.mjs
CHANGED
@@ -123,6 +123,30 @@ export function intercept(target, targetMethodName, interceptFunction, scope, pr
|
|
123
123
|
})
|
124
124
|
}
|
125
125
|
|
126
|
+
/**
|
127
|
+
* Locate a callable function by name in the passed scope.
|
128
|
+
*
|
129
|
+
* If the name starts with 'up.', the parent Component chain is searched.
|
130
|
+
*
|
131
|
+
* This is used by manager.DomEvents & core.Observable.fire and by 'handler' function calls to resolve
|
132
|
+
* string function names in the Component's own hierarchy.
|
133
|
+
* @param {Function|String} fn A function, or the name of a function to find in the passed scope object/
|
134
|
+
* @param {Object} scope=this The scope to find the function in if it is specified as a string.
|
135
|
+
* @returns {Object}
|
136
|
+
*/
|
137
|
+
export function resolveCallback(fn, scope=this) {
|
138
|
+
if (typeof fn === 'string') {
|
139
|
+
if (!scope[fn] && fn.startsWith('up.')) {
|
140
|
+
fn = fn.slice(3);
|
141
|
+
while (!scope[fn] && (scope = scope.parent));
|
142
|
+
}
|
143
|
+
|
144
|
+
fn = scope[fn]
|
145
|
+
}
|
146
|
+
|
147
|
+
return {fn, scope}
|
148
|
+
}
|
149
|
+
|
126
150
|
/**
|
127
151
|
* @param {Function} callback
|
128
152
|
* @param {Neo.core.Base} scope
|
File without changes
|
File without changes
|
@@ -1,32 +0,0 @@
|
|
1
|
-
In this topic you'll create an application that fetches data on earthquakes in Iceland,
|
2
|
-
and show the information in two views: a table, and a map.
|
3
|
-
You'll do this in a series of simple labs.
|
4
|
-
|
5
|
-
What are the goals of this lengthy topic?
|
6
|
-
|
7
|
-
- To give you hands-on coding a simple app
|
8
|
-
- To introduce fundamental Neo concepts
|
9
|
-
|
10
|
-
Most of these labs are copy-and-paste because we're focusing on _what_ the code is doing on rather than _how_.
|
11
|
-
|
12
|
-
For this tutorial don't worry about syntax details. Other tutorials and guides will spend more and
|
13
|
-
more time on syntax.e
|
14
|
-
|
15
|
-
## Key concepts
|
16
|
-
|
17
|
-
A few key concepts we'll be discussing:
|
18
|
-
|
19
|
-
- Creating a starter app
|
20
|
-
- Configuring components
|
21
|
-
- Debugging
|
22
|
-
- Class-based coding
|
23
|
-
- View models
|
24
|
-
- Events
|
25
|
-
- Controllers
|
26
|
-
|
27
|
-
## Advice
|
28
|
-
|
29
|
-
A word of advice: Keep a high-level perspective, especially early on. We'll have plenty of time to get
|
30
|
-
into the code, and we'll do most things multiple times. In other words, focus on what you're accomplishing,
|
31
|
-
and don't worry about syntax details.
|
32
|
-
|
@@ -1,47 +0,0 @@
|
|
1
|
-
In this lab, you'll generate a Neo.mjs workspace and run the starter app.
|
2
|
-
|
3
|
-
<details>
|
4
|
-
<summary>Wait!</summary>
|
5
|
-
You may already have a workspace! If so, you can skip this lab. For example, if you followed the <a href="#/learn/Setup">Getting Started > Setup</a> topic, above, you should already have a workspace.
|
6
|
-
|
7
|
-
If you don't have a workspace, then continue on to the next step.
|
8
|
-
</details>
|
9
|
-
|
10
|
-
<details>
|
11
|
-
<summary>Use the command-line to generate the workspace</summary>
|
12
|
-
|
13
|
-
Use a terminal window to navigate to some parent folder,
|
14
|
-
then run
|
15
|
-
|
16
|
-
npx neo-app@latest
|
17
|
-
|
18
|
-
You'll be prompted for a workspace name, starter app name, etc — accept the default for everything.
|
19
|
-
As the command finishes it starts a server and opens a browser window.
|
20
|
-
</details>
|
21
|
-
|
22
|
-
<details>
|
23
|
-
<summary>Inspect the workspace</summary>
|
24
|
-
|
25
|
-
The workspace contains a local copy of the API docs, an `apps` directory (where your apps are found),
|
26
|
-
and some other directories.
|
27
|
-
</details>
|
28
|
-
|
29
|
-
<details>
|
30
|
-
<summary>Start the server</summary>
|
31
|
-
From the root of the `workspace` start the server via `npm run server-start`. That starts a server
|
32
|
-
at port 8080 and opens a new browser window.
|
33
|
-
|
34
|
-
<img src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/StartServer.png" style="width:80%"/>
|
35
|
-
|
36
|
-
</details>
|
37
|
-
|
38
|
-
|
39
|
-
<details>
|
40
|
-
<summary>Run the starter app</summary>
|
41
|
-
|
42
|
-
By default, an app named `myapp` was created. You can run it by entering the `apps` directory and
|
43
|
-
clicking `myapp`. It's a folder containing an `index.html` along with the source code for the app.
|
44
|
-
|
45
|
-
<img src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/RunTheStarterApp.png" style="width:80%"/>
|
46
|
-
|
47
|
-
</details>
|
@@ -1,150 +0,0 @@
|
|
1
|
-
In this lab you'll create a starter app and add a single component.
|
2
|
-
|
3
|
-
<details>
|
4
|
-
|
5
|
-
<summary>Use the command-line to create a starter app</summary>
|
6
|
-
|
7
|
-
Use a terminal window to navigate to the workspace and run the following script. Use "Earthquakes"
|
8
|
-
as the app name, and defaults for everything else.
|
9
|
-
|
10
|
-
npm run create-app-minimal
|
11
|
-
|
12
|
-
After the script runs yous should see these files in the `app/earthquakes` directory.
|
13
|
-
|
14
|
-
`view/MainContainer.mjs`
|
15
|
-
- `app.mjs`
|
16
|
-
- `index.html`
|
17
|
-
- `neo-config.json`
|
18
|
-
|
19
|
-
If you look in `neo-config.json` you should see this content. Note the `mainThreadAddons` block
|
20
|
-
— it reflects the add-ons you chose when you followed the instructions in the script.
|
21
|
-
<pre>
|
22
|
-
{
|
23
|
-
"appPath": "../../apps/earthquakes/app.mjs",
|
24
|
-
"basePath": "../../",
|
25
|
-
"environment": "development",
|
26
|
-
"mainPath": "../node_modules/neo.mjs/src/Main.mjs",
|
27
|
-
"mainThreadAddons": [
|
28
|
-
"DragDrop",
|
29
|
-
"Stylesheet"
|
30
|
-
],
|
31
|
-
"workerBasePath": "../../node_modules/neo.mjs/src/worker/"
|
32
|
-
}</pre>
|
33
|
-
|
34
|
-
You're free to edit `neo-config.json` if you were to change your mind later about the theme or need for other add-ons.
|
35
|
-
|
36
|
-
If you refresh browser at <a href="http://localhost:8080/apps/" target="apps">http://localhost:8080/apps/</a>
|
37
|
-
you'll see the new _earthquakes_ app listed, and if you run it you'll see... nothing! That's because the
|
38
|
-
minimal starter app is the shell of an application without any view content. We'll add a little content
|
39
|
-
later in the lab.
|
40
|
-
|
41
|
-
<img style="width:80%" src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/EmptyEarthquakes.png"></img>
|
42
|
-
|
43
|
-
</details>
|
44
|
-
|
45
|
-
<details>
|
46
|
-
<summary>Look at the main view source</summary>
|
47
|
-
|
48
|
-
Use a code editor and look at `workspace/apps/earthquakes/src/view/MainView.mjs`. You'll see the
|
49
|
-
following class definition:
|
50
|
-
|
51
|
-
<pre data-javascript>
|
52
|
-
|
53
|
-
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
54
|
-
import Controller from './MainViewController.mjs';
|
55
|
-
import ViewModel from './MainViewModel.mjs';
|
56
|
-
|
57
|
-
class MainView extends Base {
|
58
|
-
static config = {
|
59
|
-
className: 'Earthquakes.view.MainView',
|
60
|
-
ntype: 'earthquakes-main',
|
61
|
-
|
62
|
-
controller: {module: Controller},
|
63
|
-
model: {module: ViewModel},
|
64
|
-
|
65
|
-
layout: {ntype: 'fit'},
|
66
|
-
items: [],
|
67
|
-
}
|
68
|
-
}
|
69
|
-
|
70
|
-
Neo.setupClass(MainView);
|
71
|
-
|
72
|
-
export default MainView;
|
73
|
-
</pre>
|
74
|
-
|
75
|
-
As you can see, `MainView extends Base`, and `Base` is a _container_ (`Neo.container.Base`).
|
76
|
-
A container is a component — it holds other components, specified in `items:[]`. There
|
77
|
-
are no items in the starter app. The `layout` config specifies how the items are arranged.
|
78
|
-
|
79
|
-
</details>
|
80
|
-
|
81
|
-
<details>
|
82
|
-
<summary>Add a component</summary>
|
83
|
-
|
84
|
-
Let's add a button. To do that, add an import for the button base class, then configure it
|
85
|
-
in the container's `items:[]`. If you were to read the API docs for buttons, you'd see
|
86
|
-
that buttons have various configs, such as `text`, which is the button text, `iconCls`, which
|
87
|
-
is typically a FontAwesome CSS class used to show an icon, and `handler`, which specifies
|
88
|
-
which method to run when the button is clicked. We'll use `text`.
|
89
|
-
|
90
|
-
<pre data-javascript>
|
91
|
-
|
92
|
-
import Base from '../../../node_modules/neo.mjs/src/container/Base.mjs';
|
93
|
-
import Button from '../../../node_modules/neo.mjs/src/button/Base.mjs';
|
94
|
-
import Controller from './MainViewController.mjs';
|
95
|
-
import ViewModel from './MainViewModel.mjs';
|
96
|
-
|
97
|
-
class MainView extends Base {
|
98
|
-
static config = {
|
99
|
-
className: 'Earthquakes.view.MainView',
|
100
|
-
ntype: 'earthquakes-main',
|
101
|
-
|
102
|
-
controller: {module: Controller},
|
103
|
-
model: {module: ViewModel},
|
104
|
-
|
105
|
-
layout: {ntype: 'fit'},
|
106
|
-
items: [{
|
107
|
-
module: Button,
|
108
|
-
text: 'Button!'
|
109
|
-
}],
|
110
|
-
}
|
111
|
-
}
|
112
|
-
|
113
|
-
Neo.setupClass(MainView);
|
114
|
-
|
115
|
-
export default MainView;
|
116
|
-
</pre>
|
117
|
-
|
118
|
-
|
119
|
-
When you run the app you'll see the single button.
|
120
|
-
|
121
|
-
<img src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/EarthquakesSingleFitButton.png" style="width:80%"/>
|
122
|
-
|
123
|
-
The button takes up the full width. Buttons look different depending on the theme. We're using
|
124
|
-
the _neo-theme-neo-light_ theme, which controls button height. Otherwise, child items a using the _fit_ layout
|
125
|
-
take up the full window.
|
126
|
-
</details>
|
127
|
-
|
128
|
-
|
129
|
-
<details>
|
130
|
-
<summary>Modify the layout</summary>
|
131
|
-
The `layout` configures how child items are visually arranged. First, note that the config
|
132
|
-
specifies `ntype`. We used `module` for the button config. An `ntype` is a class alias — if a class
|
133
|
-
has already been imported, you can use the `ntype` rather than importing it again and using the `module`
|
134
|
-
config. We haven't imported any layouts, but it turns out that `Neo.container.Base` _does_ import all the
|
135
|
-
layout types, which means we're always free to use `ntype` with layouts. You're free to specify an `ntype`
|
136
|
-
for the classes you define.
|
137
|
-
|
138
|
-
Let's change the layout to arrange items vertically, with items aligned horizontally at the start.
|
139
|
-
|
140
|
-
<pre data-javascript>
|
141
|
-
layout: {
|
142
|
-
ntype: 'vbox',
|
143
|
-
align: 'start'
|
144
|
-
}
|
145
|
-
</pre>
|
146
|
-
|
147
|
-
<img src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/EarthquakesSingleVoxStartButton.png" style="width:80%"/>
|
148
|
-
|
149
|
-
|
150
|
-
</details>
|