neo.mjs 8.41.0 → 8.41.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='8.41.0'
23
+ * @member {String} version='8.41.2'
24
24
  */
25
- version: '8.41.0'
25
+ version: '8.41.2'
26
26
  }
27
27
 
28
28
  /**
@@ -42,6 +42,7 @@ class Table extends Container {
42
42
  minWidth : 40,
43
43
  text : '#',
44
44
  renderer : Util.indexRenderer,
45
+ sortable : false,
45
46
  width : 40
46
47
  }, {
47
48
  cellAlign : 'left',
@@ -16,7 +16,7 @@
16
16
  "@type": "Organization",
17
17
  "name": "Neo.mjs"
18
18
  },
19
- "datePublished": "2025-04-06",
19
+ "datePublished": "2025-04-09",
20
20
  "publisher": {
21
21
  "@type": "Organization",
22
22
  "name": "Neo.mjs"
@@ -107,7 +107,7 @@ class FooterContainer extends Container {
107
107
  }, {
108
108
  module: Component,
109
109
  cls : ['neo-version'],
110
- html : 'v8.41.0'
110
+ html : 'v8.41.2'
111
111
  }]
112
112
  }],
113
113
  /**
@@ -42,6 +42,7 @@ class Table extends Container {
42
42
  minWidth : 40,
43
43
  text : '#',
44
44
  renderer : Util.indexRenderer,
45
+ sortable : false,
45
46
  width : 40
46
47
  }, {
47
48
  cellAlign : 'left',
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='8.41.0'
23
+ * @member {String} version='8.41.2'
24
24
  */
25
- version: '8.41.0'
25
+ version: '8.41.2'
26
26
  }
27
27
 
28
28
  /**
@@ -1,5 +1,4 @@
1
1
  import ComponentController from '../../../src/controller/Component.mjs';
2
- import NeoArray from '../../../src/util/Array.mjs';
3
2
 
4
3
  /**
5
4
  * @class Neo.examples.calendar.basic.MainContainerController
@@ -22,7 +21,7 @@ class MainContainerController extends ComponentController {
22
21
  button = data.component,
23
22
  component = me.component,
24
23
  headerToolbar = me.getReference('headerToolbar'),
25
- buttonText, cls, headerColor, iconCls, style, theme;
24
+ buttonText, headerColor, iconCls, style, theme;
26
25
 
27
26
  if (button.text === 'Theme Light') {
28
27
  buttonText = 'Theme Dark';
@@ -36,16 +35,7 @@ class MainContainerController extends ComponentController {
36
35
  theme = 'neo-theme-dark'
37
36
  }
38
37
 
39
- cls = [...component.cls];
40
-
41
- component.cls.forEach(item => {
42
- if (item.includes('neo-theme')) {
43
- NeoArray.remove(cls, item)
44
- }
45
- });
46
-
47
- NeoArray.add(cls, theme);
48
- component.cls = cls;
38
+ component.theme = theme;
49
39
 
50
40
  button.set({
51
41
  iconCls,
@@ -1,5 +1,6 @@
1
1
  import CheckBox from '../../../src/form/field/CheckBox.mjs';
2
2
  import CountryField from '../../../src/form/field/Country.mjs';
3
+ import DateField from '../../../src/form/field/Date.mjs';
3
4
  import Dialog from '../../../src/dialog/Base.mjs';
4
5
  import TextField from '../../../src/form/field/Text.mjs';
5
6
 
@@ -58,6 +59,11 @@ class EditUserDialog extends Dialog {
58
59
  labelText: 'Lastname',
59
60
  listeners: {change: 'up.onLastnameFieldChange'},
60
61
  reference: 'lastname-field'
62
+ }, {
63
+ module : DateField,
64
+ labelText: 'Date',
65
+ listeners: {change: 'up.onDateFieldChange'},
66
+ reference: 'date-field'
61
67
  }, {
62
68
  module : CountryField,
63
69
  bind : {store: 'stores.countries'},
@@ -89,6 +95,7 @@ class EditUserDialog extends Dialog {
89
95
  await me.timeout(20);
90
96
 
91
97
  me.getItem('country-field') .value = record.country;
98
+ me.getItem('date-field') .value = record.date;
92
99
  me.getItem('firstname-field').value = record['user.firstname'];
93
100
  me.getItem('lastname-field') .value = record['user.lastname'];
94
101
  me.getItem('selected-field') .checked = record['annotations.selected'];
@@ -106,6 +113,17 @@ class EditUserDialog extends Dialog {
106
113
  this.record.set({country: data.value.code})
107
114
  }
108
115
 
116
+ /**
117
+ * @param {Object} data
118
+ */
119
+ onDateFieldChange(data) {
120
+ // You can also access the internal setter directly:
121
+ // this.record.country = data.value.code
122
+ // Using the API allows bulk changes
123
+
124
+ this.record.set({date: data.value})
125
+ }
126
+
109
127
  /**
110
128
  * @param {Object} data
111
129
  */
@@ -26,6 +26,9 @@ class MainModel extends Model {
26
26
  }, {
27
27
  name: 'country',
28
28
  type: 'String'
29
+ }, {
30
+ name: 'date',
31
+ type: 'String'
29
32
  }, {
30
33
  name: 'edit',
31
34
  type: 'String'
@@ -13,6 +13,7 @@ class MainStore extends Store {
13
13
 
14
14
  data: [{
15
15
  country : 'DE',
16
+ date : '2025-04-15',
16
17
  githubId: 'tobiu',
17
18
 
18
19
  user: {
@@ -25,6 +26,7 @@ class MainStore extends Store {
25
26
  },
26
27
 
27
28
  country : 'US',
29
+ date : '2025-04-16',
28
30
  githubId: 'rwaters',
29
31
 
30
32
  user: {
@@ -33,6 +35,7 @@ class MainStore extends Store {
33
35
  }
34
36
  }, {
35
37
  country : 'DE',
38
+ date : '2025-04-17',
36
39
  githubId: 'mrsunshine',
37
40
 
38
41
  user: {
@@ -41,6 +44,7 @@ class MainStore extends Store {
41
44
  }
42
45
  }, {
43
46
  country : 'US',
47
+ date : '2025-04-18',
44
48
  githubId: 'camtnbikerrwc',
45
49
 
46
50
  user: {
@@ -1,6 +1,7 @@
1
1
  import BaseViewport from '../../../src/container/Viewport.mjs';
2
2
  import Button from '../../../src/button/Base.mjs';
3
3
  import GridContainer from '../../../src/grid/Container.mjs';
4
+ import ViewportController from './ViewportController.mjs';
4
5
  import ViewportStateProvider from './ViewportStateProvider.mjs';
5
6
 
6
7
  /**
@@ -14,6 +15,10 @@ class Viewport extends BaseViewport {
14
15
  * @protected
15
16
  */
16
17
  className: 'Neo.examples.grid.nestedRecordFields.Viewport',
18
+ /**
19
+ * @member {Neo.controller.Component} controller=ViewportController
20
+ */
21
+ controller: ViewportController,
17
22
  /**
18
23
  * @member {Neo.state.Provider} stateProvider=ViewportStateProvider
19
24
  */
@@ -32,12 +37,12 @@ class Viewport extends BaseViewport {
32
37
  style : {marginBottom: '1em'},
33
38
 
34
39
  items: ['->', {
35
- handler: 'up.onSwitchDragModeButtonClick',
40
+ handler: 'onSwitchDragModeButtonClick',
36
41
  iconCls: 'far fa-square',
37
42
  style : {marginRight: '1em'},
38
43
  text : 'Drag column headers only'
39
44
  }, {
40
- handler: 'up.onSwitchThemeButtonClick',
45
+ handler: 'onSwitchThemeButtonClick',
41
46
  iconCls: 'fas fa-sun',
42
47
  text : 'Light Theme'
43
48
  }]
@@ -54,10 +59,11 @@ class Viewport extends BaseViewport {
54
59
  {dataField: 'user.firstname', text: 'Firstname'},
55
60
  {dataField: 'user.lastname', text: 'Lastname'},
56
61
  {dataField: 'githubId', text: 'Github Id'},
62
+ {dataField: 'date', text: 'Date'},
57
63
  {dataField: 'country', text: 'Country', renderer: 'up.countryRenderer'},
58
64
  {dataField: 'edit', text: 'Edit Action', component: {
59
65
  module : Button,
60
- handler: 'up.editButtonHandler',
66
+ handler: 'editButtonHandler',
61
67
  text : 'Edit'
62
68
  }}
63
69
  ],
@@ -68,11 +74,6 @@ class Viewport extends BaseViewport {
68
74
  }]
69
75
  }
70
76
 
71
- /**
72
- * @member {Neo.dialog.Base|null} dialog=null
73
- */
74
- dialog = null
75
-
76
77
  /**
77
78
  * @param {Object} data
78
79
  */
@@ -85,73 +86,6 @@ class Viewport extends BaseViewport {
85
86
 
86
87
  return ''
87
88
  }
88
-
89
- /**
90
- * @param {Object} data
91
- */
92
- editButtonHandler(data) {
93
- let me = this,
94
- button = data.component,
95
- {appName, dialog, theme, windowId} = me,
96
- {record} = button;
97
-
98
- if (!dialog) {
99
- import('./EditUserDialog.mjs').then(module => {
100
- me.dialog = Neo.create({
101
- module : module.default,
102
- animateTargetId: button.id,
103
- appName,
104
- stateProvider : {parent: me.getStateProvider()},
105
- record,
106
- theme,
107
- windowId
108
- })
109
- })
110
- } else {
111
- dialog.animateTargetId = button.id;
112
- dialog.record = record;
113
-
114
- dialog.show()
115
- }
116
- }
117
-
118
- /**
119
- * @param {Object} data
120
- */
121
- onSwitchDragModeButtonClick(data) {
122
- let button = data.component,
123
- grid = this.getReference('grid'),
124
- {sortZone} = grid.headerToolbar;
125
-
126
- if (button.iconCls === 'fas fa-check') {
127
- button.set({iconCls: 'far fa-square'});
128
- sortZone.moveColumnContent = true
129
- } else {
130
- button.set({iconCls: 'fas fa-check'});
131
- sortZone.moveColumnContent = false
132
- }
133
- }
134
-
135
- /**
136
- * @param {Object} data
137
- */
138
- onSwitchThemeButtonClick(data) {
139
- let me = this,
140
- button = data.component,
141
- isDarkTheme = me.theme !== 'neo-theme-light',
142
- theme = isDarkTheme ? 'neo-theme-light' : 'neo-theme-dark';
143
-
144
- button.set({
145
- iconCls: isDarkTheme ? 'fa fa-moon' : 'fa fa-sun',
146
- text : isDarkTheme ? 'Dark Theme' : 'Light Theme'
147
- });
148
-
149
- me.theme = theme;
150
-
151
- if (me.dialog) {
152
- me.dialog.theme = theme
153
- }
154
- }
155
89
  }
156
90
 
157
91
  export default Neo.setupClass(Viewport);
@@ -0,0 +1,110 @@
1
+ import Component from '../../../src/controller/Component.mjs';
2
+
3
+ /**
4
+ * @class Neo.examples.grid.nestedRecordFields.ViewportController
5
+ * @extends Neo.controller.Component
6
+ */
7
+ class ViewportController extends Component {
8
+ static config = {
9
+ /**
10
+ * @member {String} className='Neo.examples.grid.nestedRecordFields.ViewportController'
11
+ * @protected
12
+ */
13
+ className: 'Neo.examples.grid.nestedRecordFields.ViewportController'
14
+ }
15
+
16
+ /**
17
+ * @member {Neo.dialog.Base|null} dialog=null
18
+ */
19
+ dialog = null
20
+
21
+ /**
22
+ * @param {Object} data
23
+ */
24
+ editButtonHandler(data) {
25
+ let me = this,
26
+ button = data.component,
27
+ {appName, dialog, theme, windowId} = me,
28
+ {record} = button;
29
+
30
+ if (!dialog) {
31
+ import('./EditUserDialog.mjs').then(module => {
32
+ me.dialog = Neo.create({
33
+ module : module.default,
34
+ animateTargetId: button.id,
35
+ appName,
36
+ stateProvider : {parent: me.getStateProvider()},
37
+ record,
38
+ theme,
39
+ windowId
40
+ })
41
+ })
42
+ } else {
43
+ dialog.animateTargetId = button.id;
44
+ dialog.record = record;
45
+
46
+ dialog.show()
47
+ }
48
+ }
49
+
50
+ /**
51
+ * @param {Record[]} items
52
+ */
53
+ onCountryStoreLoad(items) {
54
+ let me = this,
55
+ mainStore = me.getStore('mainStore'),
56
+ country;
57
+
58
+ // if the main table store is already loaded, the country field renderer had no data
59
+ if (mainStore.getCount() > 0) {
60
+ mainStore.items.forEach(record => {
61
+ country = record.country;
62
+
63
+ // hack resetting the current value to get a new record change
64
+ record.toJSON().country = null;
65
+
66
+ record.country = country
67
+ })
68
+ }
69
+ }
70
+
71
+ /**
72
+ * @param {Object} data
73
+ */
74
+ onSwitchDragModeButtonClick(data) {
75
+ let button = data.component,
76
+ grid = this.getReference('grid'),
77
+ {sortZone} = grid.headerToolbar;
78
+
79
+ if (button.iconCls === 'fas fa-check') {
80
+ button.set({iconCls: 'far fa-square'});
81
+ sortZone.moveColumnContent = true
82
+ } else {
83
+ button.set({iconCls: 'fas fa-check'});
84
+ sortZone.moveColumnContent = false
85
+ }
86
+ }
87
+
88
+ /**
89
+ * @param {Object} data
90
+ */
91
+ onSwitchThemeButtonClick(data) {
92
+ let me = this,
93
+ button = data.component,
94
+ isDarkTheme = me.theme !== 'neo-theme-light',
95
+ theme = isDarkTheme ? 'neo-theme-light' : 'neo-theme-dark';
96
+
97
+ button.set({
98
+ iconCls: isDarkTheme ? 'fa fa-moon' : 'fa fa-sun',
99
+ text : isDarkTheme ? 'Dark Theme' : 'Light Theme'
100
+ });
101
+
102
+ me.theme = theme;
103
+
104
+ if (me.dialog) {
105
+ me.dialog.theme = theme
106
+ }
107
+ }
108
+ }
109
+
110
+ export default Neo.setupClass(ViewportController);
@@ -2,8 +2,6 @@ import MainStore from './MainStore.mjs';
2
2
  import StateProvider from '../../../src/state/Provider.mjs';
3
3
  import Store from '../../../src/data/Store.mjs';
4
4
 
5
- const dataSymbol = Symbol.for('data');
6
-
7
5
  /**
8
6
  * @class Neo.examples.grid.nestedRecordFields.ViewportStateProvider
9
7
  * @extends Neo.state.Provider
@@ -36,27 +34,6 @@ class ViewportStateProvider extends StateProvider {
36
34
  mainStore: MainStore
37
35
  }
38
36
  }
39
-
40
- /**
41
- * @param {Record[]} items
42
- */
43
- onCountryStoreLoad(items) {
44
- let me = this,
45
- mainStore = me.getStore('mainStore'),
46
- country;
47
-
48
- // if the main table store is already loaded, the country field renderer had no data
49
- if (mainStore.getCount() > 0) {
50
- mainStore.items.forEach(record => {
51
- country = record.country;
52
-
53
- // hack resetting the current value to get a new record change
54
- record[dataSymbol].country = null;
55
-
56
- record.country = country
57
- })
58
- }
59
- }
60
37
  }
61
38
 
62
39
  export default Neo.setupClass(ViewportStateProvider);
@@ -37,6 +37,7 @@ class TableContainer extends BaseTableContainer {
37
37
  minWidth : 40,
38
38
  text : '#',
39
39
  renderer : Util.indexRenderer,
40
+ sortable : false,
40
41
  width : 40
41
42
  }, {
42
43
  cellAlign : 'left',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "8.41.0",
3
+ "version": "8.41.2",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -57,7 +57,7 @@
57
57
  "fs-extra": "^11.3.0",
58
58
  "highlightjs-line-numbers.js": "^2.9.0",
59
59
  "inquirer": "^12.5.2",
60
- "marked": "^15.0.7",
60
+ "marked": "^15.0.8",
61
61
  "monaco-editor": "0.50.0",
62
62
  "neo-jsdoc": "1.0.1",
63
63
  "neo-jsdoc-x": "1.0.5",
@@ -65,7 +65,7 @@
65
65
  "sass": "^1.86.3",
66
66
  "siesta-lite": "5.5.2",
67
67
  "url": "^0.11.4",
68
- "webpack": "^5.98.0",
68
+ "webpack": "^5.99.3",
69
69
  "webpack-cli": "^6.0.1",
70
70
  "webpack-dev-server": "^5.2.1",
71
71
  "webpack-hook-plugin": "^1.0.7",
@@ -263,12 +263,12 @@ const DefaultConfig = {
263
263
  useVdomWorker: true,
264
264
  /**
265
265
  * buildScripts/injectPackageVersion.mjs will update this value
266
- * @default '8.41.0'
266
+ * @default '8.41.2'
267
267
  * @memberOf! module:Neo
268
268
  * @name config.version
269
269
  * @type String
270
270
  */
271
- version: '8.41.0'
271
+ version: '8.41.2'
272
272
  };
273
273
 
274
274
  Object.assign(DefaultConfig, {
@@ -289,6 +289,26 @@ class MainContainer extends Container {
289
289
  }
290
290
  }
291
291
 
292
+ /**
293
+ * Triggered after the theme config got changed
294
+ * @param {String} value
295
+ * @param {String} oldValue
296
+ * @protected
297
+ */
298
+ afterSetTheme(value, oldValue) {
299
+ super.afterSetTheme(value, oldValue);
300
+
301
+ let me = this;
302
+
303
+ if (me._editCalendarContainer) {
304
+ me._editCalendarContainer.theme = value
305
+ }
306
+
307
+ if (me._editEventContainer) {
308
+ me._editEventContainer.theme = value
309
+ }
310
+ }
311
+
292
312
  /**
293
313
  * Triggered after the useSettingsContainer config got changed
294
314
  * @param {Boolean} value
@@ -330,6 +350,7 @@ class MainContainer extends Container {
330
350
  appName : me.appName,
331
351
  owner : me,
332
352
  stateProvider: {parent: me.getStateProvider()},
353
+ theme : me.theme,
333
354
  width : 250,
334
355
  windowId : me.windowId,
335
356
  ...me.editCalendarContainerConfig
@@ -353,6 +374,7 @@ class MainContainer extends Container {
353
374
  appName : me.appName,
354
375
  owner : me,
355
376
  stateProvider: {parent: me.getStateProvider()},
377
+ theme : me.theme,
356
378
  width : 250,
357
379
  windowId : me.windowId,
358
380
  ...me.editEventContainerConfig
@@ -1582,11 +1582,11 @@ class Component extends Base {
1582
1582
  me.isVdomUpdating = false;
1583
1583
  reject?.()
1584
1584
  }).then(data => {
1585
- me.isVdomUpdating = false;
1586
-
1587
- // checking if the component got destroyed before the update cycle is done
1585
+ // Checking if the component got destroyed before the update cycle is done
1588
1586
  if (me.id) {
1589
- me.vnode = data.vnode;
1587
+ // It is crucial to delegate the vnode tree before resolving the cycle
1588
+ me.vnode = data.vnode;
1589
+ me.isVdomUpdating = false;
1590
1590
 
1591
1591
  deltas = data.deltas;
1592
1592
 
@@ -2316,7 +2316,7 @@ class Component extends Base {
2316
2316
  {useVdomWorker} = Neo.config;
2317
2317
 
2318
2318
  // Verify that the critical rendering path => CSS files for the new tree is in place
2319
- if (currentWorker.countLoadingThemeFiles !== 0) {
2319
+ if (autoMount && currentWorker.countLoadingThemeFiles !== 0) {
2320
2320
  currentWorker.on('themeFilesLoaded', function() {
2321
2321
  !me.mounted && me.render(mount)
2322
2322
  }, me, {once: true});
@@ -303,7 +303,7 @@ class Container extends Component {
303
303
  createItem(item, index) {
304
304
  let me = this,
305
305
  config = {appName: me.appName, parentId: me.id, parentIndex: index, windowId: me.windowId},
306
- defaults = {...me.itemDefaults},
306
+ defaults = {theme: me.theme, ...me.itemDefaults},
307
307
  lazyLoadItem, module;
308
308
 
309
309
  if (defaults) {
@@ -1,4 +1,5 @@
1
1
  import Base from './Base.mjs';
2
+ import NeoArray from '../util/Array.mjs';
2
3
  import {resolveCallback} from '../util/Function.mjs';
3
4
 
4
5
  /**
@@ -182,7 +183,7 @@ class Observable extends Base {
182
183
 
183
184
  // remove the listener if the scope no longer exists
184
185
  if (cb.scope && !cb.scope.id) {
185
- listeners[name].splice(i, 1)
186
+ NeoArray.remove(listeners[name], handler)
186
187
  } else {
187
188
  if (!me.suspendEvents) {
188
189
  // Object event format. Inject firer reference in as 'source'
@@ -191,7 +192,7 @@ class Observable extends Base {
191
192
  }
192
193
 
193
194
  // remove the listener if it has the once flag
194
- handler.once && listeners[name].splice(i, 1)
195
+ handler.once && NeoArray.remove(listeners[name], handler);
195
196
 
196
197
  if (Neo.isNumber(delay) && delay > 0) {
197
198
  me.delayedCallback(cb, handler.data ? args.concat(handler.data) : args, delay)
@@ -83,6 +83,7 @@ class Component extends Column {
83
83
  }
84
84
 
85
85
  componentConfig = me.applyRecordConfigs(componentConfig, record);
86
+ componentConfig = {...componentConfig};
86
87
 
87
88
  if (component) {
88
89
  delete componentConfig.className;
@@ -103,6 +104,9 @@ class Component extends Column {
103
104
  windowId
104
105
  });
105
106
 
107
+ view.getController() ?.parseConfig(component);
108
+ view.getStateProvider()?.parseConfig(component);
109
+
106
110
  me.map.set(id, component)
107
111
  }
108
112
 
@@ -155,6 +155,12 @@ class Toolbar extends BaseToolbar {
155
155
 
156
156
  me.itemDefaults.showHeaderFilter = me.showHeaderFilters;
157
157
 
158
+ me.items.forEach(item => {
159
+ if (!Object.hasOwn(item, 'sortable')) {
160
+ item.sortable = me.sortable
161
+ }
162
+ });
163
+
158
164
  super.createItems();
159
165
 
160
166
  let {items} = me,
@@ -170,7 +176,6 @@ class Toolbar extends BaseToolbar {
170
176
  if (item.minWidth) {style.minWidth = item.minWidth + 'px'}
171
177
  if (item.width) {style.width = item.width + 'px'}
172
178
 
173
- item.sortable = me.sortable;
174
179
  item.wrapperStyle = style
175
180
  });
176
181
 
@@ -128,6 +128,12 @@ class Toolbar extends BaseToolbar {
128
128
 
129
129
  me.itemDefaults.showHeaderFilter = me.showHeaderFilters;
130
130
 
131
+ me.items.forEach(item => {
132
+ if (!Object.hasOwn(item, 'sortable')) {
133
+ item.sortable = me.sortable
134
+ }
135
+ });
136
+
131
137
  super.createItems();
132
138
 
133
139
  let dockLeftWidth = 0,
@@ -156,7 +162,6 @@ class Toolbar extends BaseToolbar {
156
162
  item.vdom.cls = [] // remove the button cls from the th tag
157
163
  }
158
164
 
159
- item.sortable = me.sortable;
160
165
  item.wrapperStyle = style;
161
166
 
162
167
  // inverse loop direction
@@ -1,2 +0,0 @@
1
- # Development in progress
2
- Currently, scheduled for the v4.x release