neo.mjs 7.9.0 → 7.10.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.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='7.9.0'
23
+ * @member {String} version='7.10.0'
24
24
  */
25
- version: '7.9.0'
25
+ version: '7.10.0'
26
26
  }
27
27
 
28
28
  /**
@@ -16,7 +16,7 @@
16
16
  "@type": "Organization",
17
17
  "name": "Neo.mjs"
18
18
  },
19
- "datePublished": "2024-09-27",
19
+ "datePublished": "2024-09-30",
20
20
  "publisher": {
21
21
  "@type": "Organization",
22
22
  "name": "Neo.mjs"
@@ -111,7 +111,7 @@ class FooterContainer extends Container {
111
111
  }, {
112
112
  module: Component,
113
113
  cls : ['neo-version'],
114
- html : 'v7.9.0'
114
+ html : 'v7.10.0'
115
115
  }]
116
116
  }],
117
117
  /**
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='7.9.0'
23
+ * @member {String} version='7.10.0'
24
24
  */
25
- version: '7.9.0'
25
+ version: '7.10.0'
26
26
  }
27
27
 
28
28
  /**
@@ -135,7 +135,8 @@ class DemoDialog extends Dialog {
135
135
  trapFocus : true,
136
136
  optionalAnimateTargetId: button.id,
137
137
  style : {left: me.getOffset(), top: me.getOffset()},
138
- title : 'Dialog ' + nextIndex
138
+ title : 'Dialog ' + nextIndex,
139
+ windowId : me.windowId
139
140
  })
140
141
  }
141
142
 
@@ -50,7 +50,7 @@ class MainContainer extends Viewport {
50
50
  checked : true,
51
51
  hideLabel : true,
52
52
  hideValueLabel: false,
53
- listeners : {change: me.onConfigChange.bind(me, 'boundaryContainerId')},
53
+ listeners : {change: me.onBoundaryContainerIdChange.bind(me)},
54
54
  style : {marginLeft: '3em'},
55
55
  valueLabelText: 'Limit Drag&Drop to the document.body'
56
56
  }, {
@@ -82,29 +82,47 @@ class MainContainer extends Viewport {
82
82
  * @param {Object} data
83
83
  */
84
84
  createDialog(data) {
85
- let me = this;
85
+ let me = this,
86
+ button = data.component,
87
+ {appName, boundaryContainerId, windowId} = me;
86
88
 
87
- data.component.disabled = true;
89
+ button.disabled = true;
88
90
 
89
91
  me.dialog = Neo.create(DemoDialog, {
90
92
  animated : me.down({valueLabelText: 'Animated'}).checked,
91
- appName : me.appName,
92
- boundaryContainerId : me.boundaryContainerId,
93
+ appName,
94
+ boundaryContainerId,
93
95
  listeners : {close: me.onWindowClose, scope: me},
94
96
  modal : me.down({valueLabelText: 'Modal'}).checked,
95
97
  trapFocus : true,
96
- optionalAnimateTargetId: data.component.id,
97
- title : 'Dialog 1'
98
+ optionalAnimateTargetId: button.id,
99
+ title : 'Dialog 1',
100
+ windowId
98
101
  })
99
102
  }
100
103
 
104
+ /**
105
+ * @param {Object} opts
106
+ */
107
+ onBoundaryContainerIdChange(opts) {
108
+ let me = this,
109
+ {dialog} = me,
110
+ boundaryContainerId = opts.value ? 'document.body' : null;
111
+
112
+ me.boundaryContainerId = boundaryContainerId
113
+
114
+ if (dialog) {
115
+ dialog.boundaryContainerId = boundaryContainerId
116
+ }
117
+ }
118
+
101
119
  /**
102
120
  * @param {String} config
103
121
  * @param {Object} opts
104
122
  */
105
123
  onConfigChange(config, opts) {
106
124
  if (this.dialog) {
107
- this.dialog[config] = opts.value ? 'document.body' : null
125
+ this.dialog[config] = opts.value
108
126
  }
109
127
  }
110
128
 
@@ -120,7 +120,17 @@ class EditUserDialog extends Dialog {
120
120
  * @param {Object} data
121
121
  */
122
122
  onSelectedFieldChange(data) {
123
- this.record.annotations.selected = data.value
123
+ let me = this,
124
+ store = me.getModel().getStore('mainStore');
125
+
126
+ if (data.value === false) {
127
+ me.record.annotations.selected = false
128
+ } else {
129
+ // Assuming we want to support a single row selection
130
+ store.items.forEach(record => {
131
+ record.annotations.selected = record === me.record ? data.value : false
132
+ })
133
+ }
124
134
  }
125
135
  }
126
136
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "7.9.0",
3
+ "version": "7.10.0",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -54,13 +54,13 @@
54
54
  "envinfo": "^7.14.0",
55
55
  "fs-extra": "^11.2.0",
56
56
  "highlightjs-line-numbers.js": "^2.8.0",
57
- "inquirer": "^11.0.2",
57
+ "inquirer": "^11.1.0",
58
58
  "marked": "^14.1.2",
59
59
  "monaco-editor": "0.50.0",
60
60
  "neo-jsdoc": "1.0.1",
61
61
  "neo-jsdoc-x": "1.0.5",
62
62
  "postcss": "^8.4.47",
63
- "sass": "^1.79.3",
63
+ "sass": "^1.79.4",
64
64
  "siesta-lite": "5.5.2",
65
65
  "url": "^0.11.4",
66
66
  "webpack": "^5.95.0",
@@ -523,16 +523,16 @@ class MainView extends Base {
523
523
  module: Store,
524
524
  model: {
525
525
  fields: [{
526
- name: "humanReadableLocation",
526
+ name: "location",
527
527
  }, {
528
- name: "size",
528
+ name: "magnitude",
529
529
  }, {
530
530
  name: "timestamp",
531
531
  type: "Date",
532
532
  }],
533
533
  },
534
534
  url: "https://nameless-tundra-27404.herokuapp.com/go/?fn=earthquakes",
535
- responseRoot: "results",
535
+ responseRoot: "data",
536
536
  autoLoad: true,
537
537
  },
538
538
  style: {width: '100%'},
@@ -543,10 +543,10 @@ class MainView extends Base {
543
543
  {weekday: "long", year: "numeric", month: "long", day: "numeric"}
544
544
  )
545
545
  }, {
546
- dataField: "humanReadableLocation",
546
+ dataField: "location",
547
547
  text: "Location"
548
548
  }, {
549
- dataField: "size",
549
+ dataField: "magnitude",
550
550
  text: "Magnitude",
551
551
  align: "right",
552
552
  renderer: (data) => data.value.toLocaleString()
@@ -595,36 +595,38 @@ Here's the config for the store.
595
595
  module: Store,
596
596
  model: {
597
597
  fields: [{
598
- name: "humanReadableLocation",
598
+ name: "location",
599
599
  }, {
600
- name: "size",
600
+ name: "magnitude",
601
601
  }, {
602
602
  name: "timestamp",
603
603
  type: "Date",
604
604
  }],
605
605
  },
606
606
  url: "https://nameless-tundra-27404.herokuapp.com/go/?fn=earthquakes",
607
- responseRoot: "results",
607
+ responseRoot: "data",
608
608
  autoLoad: true,
609
609
  }
610
610
  </pre>
611
611
 
612
- The feed looks like this. (For simplicity, some values are omitted.)
612
+ The feed looks like this.
613
613
  <pre data-javascript>
614
614
  {
615
- "results": [{
616
- "timestamp": "2017-10-13T12:07:24.000Z",
617
- "latitude": 63.976,
618
- "longitude": -21.949,
619
- "size": 0.6,
620
- "humanReadableLocation": "6,1 km SV af Helgafelli"
615
+ "data": [{
616
+ "timestamp": "2024-09-29T16:45:14.000Z",
617
+ "lat": "64.012",
618
+ "lng": "-16.659",
619
+ "location": "1.2 km ESE of Hvannadalshnjúkur",
620
+ "magnitude": "0.32964",
621
+ "depth": "1.2"
621
622
  }, {
622
- "timestamp": "2017-10-13T09:50:50.000Z",
623
- "latitude": 65.124,
624
- "longitude": -16.288,
625
- "size": 0.9,
626
- "humanReadableLocation": "6,1 km NA af Her\u00F0ubrei\u00F0art\u00F6glum"
627
- }, //...
623
+ "timestamp": "2024-09-29T16:16:25.000Z",
624
+ "lat": "63.929",
625
+ "lng": "-21.447",
626
+ "location": "2.8 km WSW of Raufarhólshellir",
627
+ "magnitude": "0.80979",
628
+ "depth": "10.2"
629
+ }, ...
628
630
  ]
629
631
  }
630
632
  </pre>
@@ -644,10 +646,10 @@ columns: [{
644
646
  text: "Date",
645
647
  renderer: (data) => data.value.toLocaleDateString(undefined, {weekday: "long", year: "numeric", month: "long", day: "numeric"}),
646
648
  }, {
647
- dataField: "humanReadableLocation",
649
+ dataField: "location",
648
650
  text: "Location",
649
651
  }, {
650
- dataField: "size",
652
+ dataField: "magnitude",
651
653
  text: "Magnitude",
652
654
  align: "right",
653
655
  renderer: (data) => data.value.toLocaleString(),
@@ -692,10 +694,10 @@ class Table extends Base {
692
694
  text: "Date",
693
695
  renderer: (data) => data.value.toLocaleDateString(undefined, {weekday: "long", year: "numeric", month: "long", day: "numeric"}),
694
696
  }, {
695
- dataField: "humanReadableLocation",
697
+ dataField: "location",
696
698
  text: "Location",
697
699
  }, {
698
- dataField: "size",
700
+ dataField: "magnitude",
699
701
  text: "Magnitude",
700
702
  align: "right",
701
703
  renderer: (data) => data.value.toLocaleString(),
@@ -765,16 +767,16 @@ static config = {
765
767
  module: Store,
766
768
  model: {
767
769
  fields: [{
768
- name: "humanReadableLocation",
770
+ name: "location",
769
771
  }, {
770
- name: "size",
772
+ name: "magnitude",
771
773
  }, {
772
774
  name: "timestamp",
773
775
  type: "Date",
774
776
  }],
775
777
  },
776
778
  url: "https://nameless-tundra-27404.herokuapp.com/go/?fn=earthquakes",
777
- responseRoot: "results",
779
+ responseRoot: "data",
778
780
  autoLoad: true,
779
781
  },
780
782
  style: {width: '100%'},
@@ -888,16 +890,16 @@ class MainView extends Base {
888
890
  module: Store,
889
891
  model: {
890
892
  fields: [{
891
- name: "humanReadableLocation"
893
+ name: "location"
892
894
  }, {
893
- name: "size"
895
+ name: "magnitude"
894
896
  }, {
895
897
  name: "timestamp",
896
898
  type: "Date"
897
899
  }]
898
900
  },
899
901
  url: "https://nameless-tundra-27404.herokuapp.com/go/?fn=earthquakes",
900
- responseRoot: "results",
902
+ responseRoot: "data",
901
903
  autoLoad: true
902
904
  },
903
905
  }
@@ -912,16 +914,16 @@ class MainView extends Base {
912
914
  module: Store,
913
915
  model: {
914
916
  fields: [{
915
- name: "humanReadableLocation"
917
+ name: "location"
916
918
  }, {
917
- name: "size"
919
+ name: "magnitude"
918
920
  }, {
919
921
  name: "timestamp",
920
922
  type: "Date"
921
923
  }]
922
924
  },
923
925
  url: "https://nameless-tundra-27404.herokuapp.com/go/?fn=earthquakes",
924
- responseRoot: "results",
926
+ responseRoot: "data",
925
927
  autoLoad: true
926
928
  },
927
929
  style: {width: '100%'}
@@ -931,16 +933,16 @@ class MainView extends Base {
931
933
  module: Store,
932
934
  model: {
933
935
  fields: [{
934
- name: "humanReadableLocation"
936
+ name: "location"
935
937
  }, {
936
- name: "size"
938
+ name: "magnitude"
937
939
  }, {
938
940
  name: "timestamp",
939
941
  type: "Date"
940
942
  }]
941
943
  },
942
944
  url: "https://nameless-tundra-27404.herokuapp.com/go/?fn=earthquakes",
943
- responseRoot: "results",
945
+ responseRoot: "data",
944
946
  autoLoad: true
945
947
  },
946
948
  style: {width: '100%'}
@@ -1004,16 +1006,16 @@ class MainView extends Base {
1004
1006
  module: Store,
1005
1007
  model: {
1006
1008
  fields: [{
1007
- name: "humanReadableLocation"
1009
+ name: "location"
1008
1010
  }, {
1009
- name: "size"
1011
+ name: "magnitude"
1010
1012
  }, {
1011
1013
  name: "timestamp",
1012
1014
  type: "Date"
1013
1015
  }]
1014
1016
  },
1015
1017
  url: "https://nameless-tundra-27404.herokuapp.com/go/?fn=earthquakes",
1016
- responseRoot: "results",
1018
+ responseRoot: "data",
1017
1019
  autoLoad: true
1018
1020
  },
1019
1021
  }
@@ -1084,16 +1086,16 @@ class MainViewModel extends Model {
1084
1086
  module: Store,
1085
1087
  model: {
1086
1088
  fields: [{
1087
- name: "humanReadableLocation"
1089
+ name: "location"
1088
1090
  }, {
1089
- name: "size"
1091
+ name: "magnitude"
1090
1092
  }, {
1091
1093
  name: "timestamp",
1092
1094
  type: "Date"
1093
1095
  }]
1094
1096
  },
1095
1097
  url: "https://nameless-tundra-27404.herokuapp.com/go/?fn=earthquakes",
1096
- responseRoot: "results",
1098
+ responseRoot: "data",
1097
1099
  autoLoad: true
1098
1100
  },
1099
1101
  }
@@ -1247,22 +1249,22 @@ Edit `apps/earthquakes/view/MainViewModel.mjs` and modify `fields` as follows.
1247
1249
 
1248
1250
  <pre data-javascript>
1249
1251
  fields: [{
1250
- name: "humanReadableLocation",
1252
+ name: "location",
1251
1253
  }, {
1252
- name: "size",
1254
+ name: "magnitude",
1253
1255
  }, {
1254
1256
  name: "timestamp",
1255
1257
  type: "Date",
1256
1258
  }, {
1257
1259
  name: 'title',
1258
- mapping: "humanReadableLocation"
1260
+ mapping: "location"
1259
1261
  }, {
1260
1262
  name: "position",
1261
1263
  calculate: (data, field, item)=>({lat: item.latitude, lng: item.longitude})
1262
1264
  }],
1263
1265
  </pre>
1264
1266
 
1265
- As you can see, _title_ is mapped to the existing feed value _humanReadableLocation_, and _position_ is
1267
+ As you can see, _title_ is mapped to the existing feed value _location_, and _position_ is
1266
1268
  calculated by returning an object with _lat_ and _lng_ set to the corresponding values from the feed.
1267
1269
 
1268
1270
  Save and refresh _earthquakes_. You can use the debugger to inspect the store via _Shift-Ctrl-right-click_ and
@@ -1391,9 +1393,9 @@ Add this table config:
1391
1393
 
1392
1394
  Save and refresh, then click on a table row. If you look at the debugger console you'll see the record being logged.
1393
1395
 
1394
- Just for fun, expand the logged value and look for the size property. If you recall, that's a value from the feed, and one of the things we configured in the store's fields:[].
1396
+ Just for fun, expand the logged value and look for the `magnitude` property. If you recall, that's a value from the feed, and one of the things we configured in the store's fields:[].
1395
1397
 
1396
- In the console, click on the ellipses by size and enter a new value, like 2.5. (Don't enter a larger value, or you may destroy that part of Iceland.)
1398
+ In the console, click on the ellipses by `magnitude` and enter a new value, like 2.5. (Don't enter a larger value, or you may destroy that part of Iceland.)
1397
1399
 
1398
1400
  <img style="width:80%" src="https://s3.amazonaws.com/mjs.neo.learning.images/earthquakes/LogTableClick.png"></img>
1399
1401
 
@@ -262,12 +262,12 @@ const DefaultConfig = {
262
262
  useVdomWorker: true,
263
263
  /**
264
264
  * buildScripts/injectPackageVersion.mjs will update this value
265
- * @default '7.9.0'
265
+ * @default '7.10.0'
266
266
  * @memberOf! module:Neo
267
267
  * @name config.version
268
268
  * @type String
269
269
  */
270
- version: '7.9.0'
270
+ version: '7.10.0'
271
271
  };
272
272
 
273
273
  Object.assign(DefaultConfig, {
package/src/Neo.mjs CHANGED
@@ -92,17 +92,13 @@ Neo = globalThis.Neo = Object.assign({
92
92
  * @param {Neo.core.Base} cls
93
93
  */
94
94
  applyToGlobalNs(cls) {
95
- let proto = typeof cls === 'function' ? cls.prototype: cls,
96
- className, nsArray, key, ns;
95
+ let proto = typeof cls === 'function' ? cls.prototype : cls,
96
+ className = proto.isClass ? proto.config.className : proto.className,
97
+ nsArray = className.split('.'),
98
+ key = nsArray.pop(),
99
+ ns = Neo.ns(nsArray, true);
97
100
 
98
- if (proto.constructor.registerToGlobalNs === true) {
99
- className = proto.isClass ? proto.config.className : proto.className;
100
-
101
- nsArray = className.split('.');
102
- key = nsArray.pop();
103
- ns = Neo.ns(nsArray, true);
104
- ns[key] = cls
105
- }
101
+ ns[key] = cls
106
102
  },
107
103
 
108
104
  /**
@@ -571,8 +567,7 @@ const ignoreMixin = [
571
567
  'isClass',
572
568
  'mixin',
573
569
  'ntype',
574
- 'observable',
575
- 'registerToGlobalNs'
570
+ 'observable'
576
571
  ],
577
572
 
578
573
  charsRegex = /\d+/g,
@@ -1,6 +1,5 @@
1
1
  import Base from './Base.mjs';
2
2
  import ClassSystemUtil from '../util/ClassSystem.mjs';
3
- import Logger from '../util/Logger.mjs';
4
3
 
5
4
  /**
6
5
  * @class Neo.controller.Application
@@ -101,8 +100,6 @@ class Application extends Base {
101
100
  // short delay to ensure changes from onHashChange() got applied
102
101
  await me.timeout(Neo.config.hash ? 200 : 10);
103
102
 
104
- Logger.addContextMenuListener(me.mainView);
105
-
106
103
  await value.render(true)
107
104
  }
108
105
  }
package/src/core/Base.mjs CHANGED
@@ -52,14 +52,6 @@ class Base {
52
52
  * @static
53
53
  */
54
54
  static overwrittenMethods = {}
55
- /**
56
- * Set this one to false in case you don't want to stick
57
- * to the "anti-pattern" to apply classes to the global Neo or App namespace
58
- * @member {Boolean} registerToGlobalNs=true
59
- * @protected
60
- * @static
61
- */
62
- static registerToGlobalNs = true
63
55
  /**
64
56
  * Configs will get merged throughout the class hierarchy
65
57
  * @returns {Object} config
@@ -5,15 +5,6 @@
5
5
  * @singleton
6
6
  */
7
7
  class IdGenerator {
8
- /**
9
- * Set this one to false in case you don't want to stick
10
- * to the "anti-pattern" to apply classes to the global Neo or App namespace
11
- * @member {Boolean} registerToGlobalNs=true
12
- * @protected
13
- * @static
14
- */
15
- static registerToGlobalNs = true
16
-
17
8
  static config = {
18
9
  /**
19
10
  * @member {String} className='Neo.core.IdGenerator'
@@ -274,7 +274,7 @@ class Base extends Panel {
274
274
  super.afterSetMounted(value, oldValue);
275
275
 
276
276
  // Ensure focus trapping is up-to-date, enabled or disabled.
277
- this.syncTrapFocus()
277
+ oldValue !== undefined && this.syncTrapFocus()
278
278
  }
279
279
 
280
280
  /**
@@ -730,6 +730,30 @@ class Base extends Panel {
730
730
  this.hidden = true
731
731
  }
732
732
 
733
+ /**
734
+ * @param {Boolean} [mount] Mount the DOM after the vnode got created
735
+ */
736
+ async render(mount) {
737
+ let me = this,
738
+ {wrapperStyle} = me;
739
+
740
+ // If there is no animation target, we need to ensure that the initial offscreen positioning
741
+ // from .neo-floating gets reverted
742
+ if (!me.animateTargetId) {
743
+ if (!wrapperStyle.left) {
744
+ wrapperStyle.left = 'initial'
745
+ }
746
+
747
+ if (!wrapperStyle.top) {
748
+ wrapperStyle.top = 'initial'
749
+ }
750
+
751
+ me.wrapperStyle = wrapperStyle
752
+ }
753
+
754
+ await super.render(mount)
755
+ }
756
+
733
757
  /**
734
758
  * @param {Boolean} animate=!!this.animateTargetId
735
759
  */
@@ -739,7 +763,7 @@ class Base extends Panel {
739
763
  if (animate) {
740
764
  me.animateShow()
741
765
  } else {
742
- if (!me.rendered) {
766
+ if (!me.mounted) {
743
767
  me.render(true)
744
768
  }
745
769
 
@@ -172,7 +172,9 @@ class DomEvent extends Base {
172
172
  }
173
173
  }
174
174
 
175
- if (eventName.startsWith('drop')) {
175
+ if (eventName === 'contextmenu' && data.ctrlKey) {
176
+ Neo.util?.Logger?.onContextMenu(data)
177
+ } else if (eventName.startsWith('drop')) {
176
178
  let dragZone = data.dragZoneId && Neo.get(data.dragZoneId);
177
179
 
178
180
  if (dragZone) {
@@ -77,17 +77,6 @@ class Logger extends Base {
77
77
  })
78
78
  }
79
79
 
80
- /**
81
- * Ctrl-Right-Click will show the current component
82
- * @param {Neo.component.Base} view
83
- */
84
- addContextMenuListener(view) {
85
- view.addDomListeners({
86
- contextmenu: this.onContextMenu,
87
- scope : this
88
- })
89
- }
90
-
91
80
  /**
92
81
  * Set level to number based on position in logLevels
93
82
  * @param {String} value
@@ -169,11 +158,7 @@ class Logger extends Base {
169
158
  onContextMenu(data) {
170
159
  let {config} = Neo;
171
160
 
172
- if (
173
- data.ctrlKey
174
- && config.enableComponentLogger
175
- && !(config.env === 'dist/production' && config.enableLogsInProduction)
176
- ) {
161
+ if (config.enableComponentLogger && !(config.env === 'dist/production' && config.enableLogsInProduction)) {
177
162
  let isGroupSet = false,
178
163
  component;
179
164