neo.mjs 5.12.4 → 5.12.6

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='5.12.4'
23
+ * @member {String} version='5.12.6'
24
24
  */
25
- version: '5.12.4'
25
+ version: '5.12.6'
26
26
  }
27
27
 
28
28
  /**
@@ -69,17 +69,14 @@ class ConfigurationViewport extends Viewport {
69
69
  items : [me.exampleComponent],
70
70
  flex : me.exampleComponentFlex,
71
71
  layout: 'base',
72
- style : {padding: '20px'}
72
+ style : {overflow: 'auto', padding: '20px'},
73
+ ...me.exampleContainerConfig
73
74
  }, {
74
75
  module: Panel,
75
76
  cls : ['neo-panel', 'neo-container', 'neo-configuration-panel'],
76
77
  flex : me.configPanelFlex,
77
78
  style : {margin: '20px', minWidth: me.configPanelMinWidth},
78
79
 
79
- containerConfig: {
80
- style: {overflowY: 'scroll'}
81
- },
82
-
83
80
  headers: [{
84
81
  dock : 'top',
85
82
  style: {borderLeft:0, borderRight:0, borderTop:0},
@@ -100,7 +97,7 @@ class ConfigurationViewport extends Viewport {
100
97
  items: [{
101
98
  module: Container,
102
99
  layout: {ntype: 'vbox'},
103
- style : {padding: '10px'},
100
+ style : {overflowY: 'auto', padding: '10px'},
104
101
  cls : ['neo-configuration-panel-body'],
105
102
  itemDefaults: {
106
103
  clearToOriginalValue: true,
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='5.12.4'
23
+ * @member {String} version='5.12.6'
24
24
  */
25
- version: '5.12.4'
25
+ version: '5.12.6'
26
26
  }
27
27
 
28
28
  /**
@@ -177,9 +177,11 @@ class MainContainer extends ConfigurationViewport {
177
177
  return Neo.create({
178
178
  module : Button,
179
179
  badgeText: 'Badge',
180
+ flex : 'none',
180
181
  handler : data => console.log('button click =>', data.component.id),
181
182
  height : 50,
182
183
  iconCls : 'fa fa-home',
184
+ style : {marginBottom: '1500px', marginTop: '500px'},
183
185
  text : 'Hello World',
184
186
  ui : 'primary',
185
187
  width : 150,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "5.12.4",
3
+ "version": "5.12.6",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -236,12 +236,12 @@ const DefaultConfig = {
236
236
  useVdomWorker: true,
237
237
  /**
238
238
  * buildScripts/injectPackageVersion.mjs will update this value
239
- * @default '5.12.4'
239
+ * @default '5.12.6'
240
240
  * @memberOf! module:Neo
241
241
  * @name config.version
242
242
  * @type String
243
243
  */
244
- version: '5.12.4'
244
+ version: '5.12.6'
245
245
  };
246
246
 
247
247
  Object.assign(DefaultConfig, {
@@ -251,45 +251,15 @@ class Base extends Component {
251
251
  let me = this;
252
252
 
253
253
  me.menuList = Neo.create({
254
- module : module.default,
255
- appName : me.appName,
256
- displayField: 'text',
257
- floating : true,
258
- hidden : true,
259
- items : value,
260
- parentId : me.id
261
- });
262
-
263
- me.vdom.cn.push(me.menuList.vdom)
264
- })
265
- }
266
- }
267
-
268
- /**
269
- * Triggered after the mounted config got changed
270
- * @param {Boolean} value
271
- * @param {Boolean} oldValue
272
- * @protected
273
- */
274
- afterSetMounted(value, oldValue) {
275
- super.afterSetMounted(value, oldValue);
276
-
277
- let me = this,
278
- style;
279
-
280
- if (value && me.menu) {
281
- setTimeout(() => {
282
- me.getDomRect().then(rect => {
283
- style = me.menuList.style || {};
284
-
285
- Object.assign(style, {
286
- right: 0,
287
- top : rect.height + 'px'
288
- });
289
-
290
- me.menuList.style = style
254
+ module : module.default,
255
+ appName : me.appName,
256
+ displayField : 'text',
257
+ floating : true,
258
+ hidden : true,
259
+ items : value,
260
+ parentComponent: me
291
261
  })
292
- }, 50)
262
+ })
293
263
  }
294
264
  }
295
265
 
@@ -302,7 +272,7 @@ class Base extends Component {
302
272
  afterSetPressed(value, oldValue) {
303
273
  let cls = this.cls;
304
274
 
305
- NeoArray[value === true ? 'add' : 'remove'](cls, 'pressed');
275
+ NeoArray.toggle(cls, 'pressed', value === true);
306
276
  this.cls = cls;
307
277
  }
308
278
 
@@ -314,18 +284,16 @@ class Base extends Component {
314
284
  */
315
285
  afterSetText(value, oldValue) {
316
286
  let me = this,
287
+ isEmpty = !value || value === '',
317
288
  vdomRoot = me.getVdomRoot(),
318
289
  textNode = vdomRoot.cn[1];
319
290
 
320
- if (!value || value === '') {
321
- NeoArray.add(me._cls, 'no-text');
322
- NeoArray.add(vdomRoot.cls, 'no-text');
323
- textNode.removeDom = true;
324
- } else {
325
- NeoArray.remove(me._cls, 'no-text');
326
- NeoArray.remove(vdomRoot.cls, 'no-text');
327
- textNode.removeDom = false;
328
- textNode.innerHTML = value;
291
+ NeoArray.toggle(me._cls, 'no-text', isEmpty);
292
+ NeoArray.toggle(vdomRoot.cls, 'no-text', isEmpty);
293
+ textNode.removeDom = isEmpty;
294
+
295
+ if (!isEmpty) {
296
+ textNode.innerHTML = value
329
297
  }
330
298
 
331
299
  me.update()
@@ -430,7 +398,7 @@ class Base extends Component {
430
398
  * @protected
431
399
  */
432
400
  beforeSetIconPosition(value, oldValue) {
433
- return this.beforeSetEnumValue(value, oldValue, 'iconPosition');
401
+ return this.beforeSetEnumValue(value, oldValue, 'iconPosition')
434
402
  }
435
403
 
436
404
  /**
@@ -520,23 +488,21 @@ class Base extends Component {
520
488
  rippleWrapper.removeDom = true;
521
489
  me.update()
522
490
  }
523
- }, rippleEffectDuration);
491
+ }, rippleEffectDuration)
524
492
  }
525
493
 
526
494
  /**
527
495
  *
528
496
  */
529
- toggleMenu() {
497
+ async toggleMenu() {
530
498
  let menuList = this.menuList,
531
499
  hidden = !menuList.hidden;
532
500
 
533
501
  menuList.hidden = hidden;
534
502
 
535
503
  if (!hidden) {
536
- setTimeout(() => {
537
- console.log('focus'); // todo: does not activate the key nav
538
- menuList.focus()
539
- }, 500)
504
+ await Neo.timeout(50);
505
+ menuList.focus()
540
506
  }
541
507
  }
542
508
  }
@@ -1828,6 +1828,7 @@ class Base extends CoreBase {
1828
1828
 
1829
1829
  me.vdom.removeDom = true;
1830
1830
 
1831
+ me._hidden = true; // silent update
1831
1832
  me.mounted = false;
1832
1833
 
1833
1834
  Neo.currentWorker.promiseMessage('main', {
package/src/menu/List.mjs CHANGED
@@ -39,6 +39,11 @@ class List extends BaseList {
39
39
  * @protected
40
40
  */
41
41
  focusTimeoutId: null,
42
+ /**
43
+ * Hides a floating list on leaf item click, in case it has a parentComponent
44
+ * @member {Boolean} hideOnLeafItemClick=true
45
+ */
46
+ hideOnLeafItemClick: true,
42
47
  /**
43
48
  * Optionally pass menu.Store data directly
44
49
  * @member {Object[]|null} items_=null
@@ -104,6 +109,12 @@ class List extends BaseList {
104
109
  {tag: 'ul', tabIndex: -1, cn: []}
105
110
  }
106
111
 
112
+ /**
113
+ * If the menu is floating, it will anchor itself to the parentRect
114
+ * @member {Neo.component.Base|null} parentComponent=null
115
+ */
116
+ parentComponent = null
117
+
107
118
  /**
108
119
  * Triggered after the floating config got changed
109
120
  * @param {Object[]} value
@@ -143,7 +154,6 @@ class List extends BaseList {
143
154
  if (me.isRoot) {
144
155
  if (!value) {
145
156
  me.focusTimeoutId = setTimeout(() => {
146
- console.log('unmount'); // todo: does not hide a top-level floating menu
147
157
  me[me.floating ? 'unmount' : 'hideSubMenu']();
148
158
  }, 20);
149
159
  } else {
@@ -157,6 +167,43 @@ class List extends BaseList {
157
167
  }
158
168
  }
159
169
 
170
+ /**
171
+ * Triggered after the mounted config got changed
172
+ * @param {Boolean} value
173
+ * @param {Boolean} oldValue
174
+ * @protected
175
+ */
176
+ afterSetMounted(value, oldValue) {
177
+ super.afterSetMounted(value, oldValue);
178
+
179
+ let me = this,
180
+ id = me.id,
181
+ parentId = me.parentComponent?.id;
182
+
183
+ if (parentId) {
184
+ if (value) {
185
+ Neo.main.addon.ScrollSync.register({
186
+ sourceId: parentId,
187
+ targetId: id
188
+ });
189
+
190
+ me.getDomRect([id, parentId]).then(rects => {
191
+ let style = me.style || {};
192
+
193
+ style.left = `${rects[1].right - rects[0].width}px`;
194
+ style.top = `${rects[1].bottom + 1}px`;
195
+
196
+ me.style = style
197
+ })
198
+ } else if (oldValue !== undefined) {
199
+ Neo.main.addon.ScrollSync.unregister({
200
+ sourceId: parentId,
201
+ targetId: id
202
+ })
203
+ }
204
+ }
205
+ }
206
+
160
207
  /**
161
208
  * Triggered after the zIndex config got changed
162
209
  * @param {Number} value
@@ -270,7 +317,22 @@ class List extends BaseList {
270
317
  * @param {Object[]} data.oldPath
271
318
  */
272
319
  onFocusLeave(data) {
273
- this.menuFocus = false
320
+ let insideParent = false,
321
+ parentId = this.parentComponent?.id,
322
+ item;
323
+
324
+ if (parentId) {
325
+ for (item of data.oldPath) {
326
+ if (item.id === parentId) {
327
+ insideParent = true;
328
+ break;
329
+ }
330
+ }
331
+ }
332
+
333
+ if (!insideParent) {
334
+ this.menuFocus = false
335
+ }
274
336
  }
275
337
 
276
338
  /**
@@ -280,7 +342,13 @@ class List extends BaseList {
280
342
  onItemClick(node, data) {
281
343
  super.onItemClick(node, data);
282
344
 
283
- data.record.handler?.call(this, data)
345
+ let me = this;
346
+
347
+ data.record.handler?.call(me, data);
348
+
349
+ if (me.hideOnLeafItemClick && !data.record.items) {
350
+ me.unmount()
351
+ }
284
352
  }
285
353
 
286
354
  /**
@@ -45,6 +45,87 @@ class View extends Component {
45
45
  {tag: 'tbody', cn: []}
46
46
  }
47
47
 
48
+ /**
49
+ * @param {String} cellId
50
+ * @param {Object} column
51
+ * @param {Object} record
52
+ * @param {Number} index
53
+ * @param {Neo.table.Container} tableContainer
54
+ * @returns {Object}
55
+ */
56
+ applyRendererOutput(cellId, column, record, index, tableContainer) {
57
+ let me = this,
58
+ cellCls = ['neo-table-cell'],
59
+ dataField = column.dataField,
60
+ fieldValue = record[dataField],
61
+ hasStore = tableContainer.store?.model, // todo: remove as soon as all tables use stores (examples table)
62
+ vdom = me.vdom,
63
+ cellConfig, rendererOutput;
64
+
65
+ if (fieldValue === undefined) {
66
+ fieldValue = ''
67
+ }
68
+
69
+ rendererOutput = column.renderer.call(column.rendererScope || tableContainer, {
70
+ dataField,
71
+ index,
72
+ record,
73
+ value: fieldValue
74
+ });
75
+
76
+ switch (Neo.typeOf(rendererOutput)) {
77
+ case 'Object': {
78
+ if (rendererOutput.cls && rendererOutput.html) {
79
+ cellCls.push(...rendererOutput.cls);
80
+ } else {
81
+ rendererOutput = [rendererOutput];
82
+ }
83
+ break;
84
+ }
85
+ case 'Number':
86
+ case 'String': {
87
+ rendererOutput = {
88
+ cls : cellCls,
89
+ html: rendererOutput?.toString()
90
+ };
91
+ break;
92
+ }
93
+ }
94
+
95
+ if (rendererOutput === null || rendererOutput === undefined) {
96
+ rendererOutput = ''
97
+ }
98
+
99
+ if (column.align !== 'left') {
100
+ cellCls.push('neo-' + column.align)
101
+ }
102
+
103
+ if (!cellId) {
104
+ // todo: remove the else part as soon as all tables use stores (examples table)
105
+ if (hasStore) {
106
+ cellId = me.getCellId(record, column.dataField)
107
+ } else {
108
+ cellId = vdom.cn[i]?.cn[j]?.id || Neo.getId('td')
109
+ }
110
+ }
111
+
112
+ cellConfig = {
113
+ tag : 'td',
114
+ id : cellId,
115
+ cls : cellCls,
116
+ style : rendererOutput.style || {},
117
+ tabIndex: '-1'
118
+ };
119
+
120
+ if (Neo.typeOf(rendererOutput) === 'Object') {
121
+ cellConfig.innerHTML = rendererOutput.html || ''
122
+ } else {
123
+ cellConfig.cn = rendererOutput
124
+ }
125
+
126
+ return cellConfig
127
+ }
128
+
48
129
  /**
49
130
  * @param {Array} inputData
50
131
  */
@@ -52,14 +133,13 @@ class View extends Component {
52
133
  let me = this,
53
134
  amountRows = inputData.length,
54
135
  container = Neo.getComponent(me.parentId),
55
- hasStore = container.store?.model, // todo: remove as soon as all tables use stores (examples table)
56
136
  columns = container.items[0].items,
57
137
  colCount = columns.length,
58
138
  data = [],
59
139
  i = 0,
60
140
  vdom = me.vdom,
61
- cellCls, cellId, config, column, dockLeftMargin, dockRightMargin, id, index, j, rendererOutput,
62
- record, rendererValue, selectedRows, trCls;
141
+ config, column, dockLeftMargin, dockRightMargin, id, index, j,
142
+ record, selectedRows, trCls;
63
143
 
64
144
  me.recordVnodeMap = {}; // remove old data
65
145
 
@@ -97,69 +177,8 @@ class View extends Component {
97
177
  j = 0;
98
178
 
99
179
  for (; j < colCount; j++) {
100
- column = columns[j];
101
- rendererValue = record[column.dataField];
102
-
103
- if (rendererValue === undefined) {
104
- rendererValue = '';
105
- }
106
-
107
- rendererOutput = column.renderer.call(column.rendererScope || container, {
108
- dataField: column.dataField,
109
- index : i,
110
- record,
111
- value : rendererValue
112
- });
113
-
114
- if (!rendererOutput) {
115
- rendererOutput = ''
116
- }
117
-
118
- cellCls = ['neo-table-cell'];
119
-
120
- switch (Neo.typeOf(rendererOutput)) {
121
- case 'Object': {
122
- if (rendererOutput.cls && rendererOutput.html) {
123
- cellCls.push(...rendererOutput.cls);
124
- } else {
125
- rendererOutput = [rendererOutput];
126
- }
127
- break;
128
- }
129
- case 'Number':
130
- case 'String': {
131
- rendererOutput = {
132
- cls : cellCls,
133
- html: rendererOutput?.toString()
134
- };
135
- break;
136
- }
137
- }
138
-
139
- if (column.align !== 'left') {
140
- cellCls.push('neo-' + column.align)
141
- }
142
-
143
- // todo: remove the else part as soon as all tables use stores (examples table)
144
- if (hasStore) {
145
- cellId = me.getCellId(record, column.dataField);
146
- } else {
147
- cellId = vdom.cn[i]?.cn[j]?.id || Neo.getId('td');
148
- }
149
-
150
- config = {
151
- tag : 'td',
152
- id : cellId,
153
- cls : cellCls,
154
- style : rendererOutput.style || {},
155
- tabIndex: '-1'
156
- };
157
-
158
- if (Neo.typeOf(rendererOutput) === 'Object') {
159
- config.innerHTML = rendererOutput.html || ''
160
- } else {
161
- config.cn = rendererOutput
162
- }
180
+ column = columns[j];
181
+ config = me.applyRendererOutput(null, column, record, i, container);
163
182
 
164
183
  if (column.dock) {
165
184
  config.cls = ['neo-locked', ...config.cls || []];
@@ -200,7 +219,7 @@ class View extends Component {
200
219
  // this logic only works for selection.table.RowModel
201
220
  Neo.main.DomAccess.scrollToTableRow({id: selectedRows[0]});
202
221
  }
203
- });
222
+ })
204
223
  }
205
224
 
206
225
  /**
@@ -221,6 +240,29 @@ class View extends Component {
221
240
  return this.id + '__' + record[this.store.keyProperty] + '__' + dataField;
222
241
  }
223
242
 
243
+ /**
244
+ * Get a table column by a given field name
245
+ * @param {String} field
246
+ * @returns {Object|null}
247
+ */
248
+ getColumn(field) {
249
+ let container = Neo.getComponent(this.parentId),
250
+ columns = container.columns,
251
+ i = 0,
252
+ len = columns.length,
253
+ column;
254
+
255
+ for (; i < len; i++) {
256
+ column = columns[i];
257
+
258
+ if (column.dataField === field) {
259
+ return column
260
+ }
261
+ }
262
+
263
+ return null
264
+ }
265
+
224
266
  /**
225
267
  * Get the matching record by passing a row id, a cell id or an id inside a table cell.
226
268
  * @param {String} nodeId
@@ -292,26 +334,28 @@ class View extends Component {
292
334
  * @param {Object} opts.record
293
335
  */
294
336
  onStoreRecordChange(opts) {
295
- let me = this,
296
- deltas = [],
297
- cellId, cellNode;
337
+ let me = this,
338
+ container = Neo.getComponent(me.parentId),
339
+ needsUpdate = false,
340
+ vdom = me.vdom,
341
+ cellId, cellNode, column, index, scope;
298
342
 
299
343
  opts.fields.forEach(field => {
300
344
  cellId = me.getCellId(opts.record, field.name);
301
- cellNode = me.getVdomChild(cellId);
345
+ cellNode = VDomUtil.findVdomChild(vdom, cellId);
302
346
 
303
347
  // the vdom might not exist yet => nothing to do in this case
304
- if (cellNode) {
305
- cellNode.innerHTML = field.value; // keep the vdom in sync
348
+ if (cellNode?.vdom) {
349
+ column = me.getColumn(field.name);
350
+ index = cellNode.index;
351
+ needsUpdate = true;
352
+ scope = column.rendererScope || container;
306
353
 
307
- deltas.push({
308
- id : cellId,
309
- innerHTML: field.value
310
- })
354
+ cellNode.parentNode.cn[index] = me.applyRendererOutput(cellId, column, opts.record, index, container)
311
355
  }
312
356
  });
313
357
 
314
- deltas.length > 0 && Neo.applyDeltas(me.appName, deltas);
358
+ needsUpdate && me.update()
315
359
  }
316
360
  }
317
361