neo.mjs 5.14.0 → 5.14.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.
- package/apps/ServiceWorker.mjs +2 -2
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/button/base/MainContainer.mjs +1 -0
- package/examples/component/timer/MainContainerController.mjs +2 -2
- package/examples/component/toast/MainContainerController.mjs +2 -2
- package/package.json +1 -1
- package/resources/scss/src/examples/button/base/MainContainer.scss +7 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/button/Base.mjs +8 -3
- package/src/calendar/view/week/Component.mjs +1 -1
- package/src/component/Base.mjs +1 -1
- package/src/container/AccordionItem.mjs +19 -15
- package/src/container/Dialog.mjs +7 -6
- package/src/controller/Application.mjs +2 -9
- package/src/core/Base.mjs +25 -0
- package/src/core/Util.mjs +0 -9
- package/src/dialog/Base.mjs +5 -5
- package/src/draggable/toolbar/SortZone.mjs +3 -3
- package/src/form/field/Picker.mjs +1 -1
- package/src/list/Base.mjs +4 -0
- package/src/main/addon/ScrollSync.mjs +1 -1
- package/src/menu/Model.mjs +3 -0
- package/src/model/Component.mjs +160 -86
- package/src/util/Logger.mjs +10 -5
- package/src/worker/App.mjs +97 -0
package/apps/ServiceWorker.mjs
CHANGED
package/package.json
CHANGED
package/src/DefaultConfig.mjs
CHANGED
@@ -245,12 +245,12 @@ const DefaultConfig = {
|
|
245
245
|
useVdomWorker: true,
|
246
246
|
/**
|
247
247
|
* buildScripts/injectPackageVersion.mjs will update this value
|
248
|
-
* @default '5.14.
|
248
|
+
* @default '5.14.2'
|
249
249
|
* @memberOf! module:Neo
|
250
250
|
* @name config.version
|
251
251
|
* @type String
|
252
252
|
*/
|
253
|
-
version: '5.14.
|
253
|
+
version: '5.14.2'
|
254
254
|
};
|
255
255
|
|
256
256
|
Object.assign(DefaultConfig, {
|
package/src/button/Base.mjs
CHANGED
@@ -82,6 +82,10 @@ class Base extends Component {
|
|
82
82
|
* @member {Object[]|null} menu_=null
|
83
83
|
*/
|
84
84
|
menu_: null,
|
85
|
+
/**
|
86
|
+
* @member {Object} menuListConfig=null
|
87
|
+
*/
|
88
|
+
menuListConfig: null,
|
85
89
|
/**
|
86
90
|
* The pressed state of the Button
|
87
91
|
* @member {Boolean} pressed_=false
|
@@ -258,7 +262,8 @@ class Base extends Component {
|
|
258
262
|
hidden : true,
|
259
263
|
items : value,
|
260
264
|
parentComponent: me,
|
261
|
-
style : {left: '-5000px', top: '-5000px'}
|
265
|
+
style : {left: '-5000px', top: '-5000px'},
|
266
|
+
...me.menuListConfig
|
262
267
|
})
|
263
268
|
})
|
264
269
|
}
|
@@ -476,7 +481,7 @@ class Base extends Component {
|
|
476
481
|
delete rippleWrapper.removeDom;
|
477
482
|
me.update();
|
478
483
|
|
479
|
-
await
|
484
|
+
await me.timeout(1);
|
480
485
|
|
481
486
|
rippleEl.style.animation = `ripple ${rippleEffectDuration}ms linear`;
|
482
487
|
me.update();
|
@@ -502,7 +507,7 @@ class Base extends Component {
|
|
502
507
|
menuList.hidden = hidden;
|
503
508
|
|
504
509
|
if (!hidden) {
|
505
|
-
await
|
510
|
+
await this.timeout(50);
|
506
511
|
menuList.focus()
|
507
512
|
}
|
508
513
|
}
|
package/src/component/Base.mjs
CHANGED
@@ -53,18 +53,19 @@ class AccordionContainer extends Base {
|
|
53
53
|
* @protected
|
54
54
|
*/
|
55
55
|
createItems() {
|
56
|
-
|
57
|
-
items = me.items,
|
58
|
-
title = me.title;
|
59
|
-
let iconCls = me.iconCls || ['no-icon'],
|
56
|
+
let me = this,
|
60
57
|
arrowCls = me.arrowCls || 'fa-caret-down',
|
58
|
+
iconCls = me.iconCls || ['no-icon'],
|
59
|
+
items = me.items,
|
60
|
+
title = me.title,
|
61
61
|
header, content;
|
62
62
|
|
63
63
|
if (!Neo.isArray(iconCls)) {
|
64
|
-
iconCls = iconCls.split(' ')
|
64
|
+
iconCls = iconCls.split(' ')
|
65
65
|
}
|
66
|
+
|
66
67
|
if (!Neo.isArray(arrowCls)) {
|
67
|
-
arrowCls = arrowCls.split(' ')
|
68
|
+
arrowCls = arrowCls.split(' ')
|
68
69
|
}
|
69
70
|
|
70
71
|
header = Neo.create({
|
@@ -85,6 +86,7 @@ class AccordionContainer extends Base {
|
|
85
86
|
cls : ['fa', ...arrowCls]
|
86
87
|
}]
|
87
88
|
});
|
89
|
+
|
88
90
|
content = {
|
89
91
|
ntype : 'container',
|
90
92
|
flag : 'content',
|
@@ -98,7 +100,7 @@ class AccordionContainer extends Base {
|
|
98
100
|
|
99
101
|
me.addDomListeners([
|
100
102
|
{click: me.onExpandClick, delegate: 'neo-accordion-header-arrow'}
|
101
|
-
])
|
103
|
+
])
|
102
104
|
}
|
103
105
|
|
104
106
|
/**
|
@@ -106,15 +108,15 @@ class AccordionContainer extends Base {
|
|
106
108
|
* @param {Boolean} isExpanded
|
107
109
|
*/
|
108
110
|
afterSetExpanded(isExpanded) {
|
109
|
-
|
110
|
-
|
111
|
-
|
111
|
+
let me = this,
|
112
|
+
cls = me.cls,
|
113
|
+
fn = isExpanded ? 'add' : 'remove';
|
112
114
|
|
113
115
|
NeoArray[fn](cls, 'neo-expanded');
|
114
116
|
me.cls = cls;
|
115
117
|
|
116
118
|
// Ensure scrollbars are not flipping in and out
|
117
|
-
|
119
|
+
me.timeout(450).then(() => {
|
118
120
|
NeoArray[fn](cls, 'neo-scrollable');
|
119
121
|
me.cls = cls;
|
120
122
|
})
|
@@ -133,7 +135,9 @@ class AccordionContainer extends Base {
|
|
133
135
|
if (iconEl) {
|
134
136
|
let cls = iconEl.cls;
|
135
137
|
|
136
|
-
if (!Neo.isArray(newValue))
|
138
|
+
if (!Neo.isArray(newValue)) {
|
139
|
+
newValue = newValue.split(' ')
|
140
|
+
}
|
137
141
|
|
138
142
|
NeoArray.remove(cls, oldValue);
|
139
143
|
NeoArray.add(cls, newValue);
|
@@ -158,9 +162,9 @@ class AccordionContainer extends Base {
|
|
158
162
|
* Otherwise we set this.expanded to the new value.
|
159
163
|
*/
|
160
164
|
onExpandClick() {
|
161
|
-
|
162
|
-
|
163
|
-
|
165
|
+
let me = this,
|
166
|
+
currentState = me.expanded,
|
167
|
+
parent = me.up('accordion');
|
164
168
|
|
165
169
|
if (parent.ntype === 'accordion') {
|
166
170
|
parent.childExpandChange({
|
package/src/container/Dialog.mjs
CHANGED
@@ -93,7 +93,7 @@ class Dialog extends Base {
|
|
93
93
|
|
94
94
|
iconNode.removeDom = !value || value === '';
|
95
95
|
this.update();
|
96
|
-
}
|
96
|
+
}
|
97
97
|
|
98
98
|
/**
|
99
99
|
* Triggered after the title config got changed
|
@@ -104,7 +104,7 @@ class Dialog extends Base {
|
|
104
104
|
afterSetTitle(value, oldValue) {
|
105
105
|
this.headerToolbar?.down({flag: 'panel-header-title'}).set({
|
106
106
|
text: value
|
107
|
-
})
|
107
|
+
})
|
108
108
|
}
|
109
109
|
|
110
110
|
/**
|
@@ -149,7 +149,7 @@ class Dialog extends Base {
|
|
149
149
|
hidden: !me.title,
|
150
150
|
text : me.title
|
151
151
|
}, ...me.headerConfig.items || []],
|
152
|
-
|
152
|
+
|
153
153
|
...headerConfigCopy
|
154
154
|
});
|
155
155
|
|
@@ -190,11 +190,12 @@ class Dialog extends Base {
|
|
190
190
|
*/
|
191
191
|
async show(modal = true) {
|
192
192
|
let me = this;
|
193
|
-
|
193
|
+
|
194
|
+
await me.timeout(20);
|
194
195
|
|
195
196
|
Neo.main.addon.Dialog[modal ? 'showModal': 'show']({
|
196
|
-
|
197
|
-
|
197
|
+
appName: me.appName,
|
198
|
+
id : me.id
|
198
199
|
});
|
199
200
|
}
|
200
201
|
}
|
@@ -88,9 +88,9 @@ class Application extends Base {
|
|
88
88
|
let me = this;
|
89
89
|
|
90
90
|
// short delay to ensure changes from onHashChange() got applied
|
91
|
-
await
|
91
|
+
await me.timeout(Neo.config.hash ? 200 : 10);
|
92
92
|
|
93
|
-
|
93
|
+
Logger.addContextMenuListener(me.mainView);
|
94
94
|
|
95
95
|
value.render(true)
|
96
96
|
}
|
@@ -122,13 +122,6 @@ class Application extends Base {
|
|
122
122
|
Neo.currentWorker.removeAppFromThemeMap(this.name);
|
123
123
|
super.destroy(...args)
|
124
124
|
}
|
125
|
-
|
126
|
-
/**
|
127
|
-
* @protected
|
128
|
-
*/
|
129
|
-
registerLoggerClickEvent() {
|
130
|
-
Logger.addContextMenuListener(this.mainView)
|
131
|
-
}
|
132
125
|
}
|
133
126
|
|
134
127
|
Neo.applyClassConfig(Application);
|
package/src/core/Base.mjs
CHANGED
@@ -79,6 +79,13 @@ class Base {
|
|
79
79
|
module: null
|
80
80
|
}
|
81
81
|
|
82
|
+
/**
|
83
|
+
* Internal cache for all timeout ids when using this.timeout()
|
84
|
+
* @member {Number[]} timeoutIds=[]
|
85
|
+
* @private
|
86
|
+
*/
|
87
|
+
#timeoutIds = []
|
88
|
+
|
82
89
|
/**
|
83
90
|
* Applies the observable mixin if needed, grants remote access if needed.
|
84
91
|
* @param {Object} config={}
|
@@ -240,6 +247,10 @@ class Base {
|
|
240
247
|
destroy() {
|
241
248
|
let me = this;
|
242
249
|
|
250
|
+
me.#timeoutIds.forEach(id => {
|
251
|
+
clearTimeout(id)
|
252
|
+
});
|
253
|
+
|
243
254
|
if (Base.instanceManagerAvailable === true) {
|
244
255
|
Neo.manager.Instance.unregister(me)
|
245
256
|
} else if (Neo.idMap) {
|
@@ -503,6 +514,20 @@ class Base {
|
|
503
514
|
return false
|
504
515
|
}
|
505
516
|
|
517
|
+
/**
|
518
|
+
* Stores timeoutIds internally, so that destroy() can clear them if needed
|
519
|
+
* @param {Number} time in milliseconds
|
520
|
+
* @returns {Promise<any>}
|
521
|
+
*/
|
522
|
+
timeout(time) {
|
523
|
+
return new Promise(resolve => {
|
524
|
+
let timeoutIds = this.#timeoutIds,
|
525
|
+
timeoutId = setTimeout(() => {timeoutIds.splice(timeoutIds.indexOf(timeoutId, 1)); resolve()}, time);
|
526
|
+
|
527
|
+
timeoutIds.push(timeoutId)
|
528
|
+
})
|
529
|
+
}
|
530
|
+
|
506
531
|
/**
|
507
532
|
* <p>Enhancing the toString() method, e.g.</p>
|
508
533
|
* `Neo.create('Neo.button.Base').toString() => "[object Neo.button.Base (neo-button-1)]"`
|
package/src/core/Util.mjs
CHANGED
@@ -199,14 +199,6 @@ class Util extends Base {
|
|
199
199
|
return typeof value === 'string';
|
200
200
|
}
|
201
201
|
|
202
|
-
/**
|
203
|
-
* @param {Number} time in milliseconds
|
204
|
-
* @returns {Promise<unknown>}
|
205
|
-
*/
|
206
|
-
static timeout(time) {
|
207
|
-
return new Promise(resolve => setTimeout(resolve, time));
|
208
|
-
}
|
209
|
-
|
210
202
|
/**
|
211
203
|
* Converts any iterable (strings, numeric indices and a length property) into a true array
|
212
204
|
* @param {Object|String} iterable
|
@@ -246,7 +238,6 @@ Neo.applyFromNs(Neo, Util, {
|
|
246
238
|
isNumber : 'isNumber',
|
247
239
|
isObject : 'isObject',
|
248
240
|
isString : 'isString',
|
249
|
-
timeout : 'timeout',
|
250
241
|
toArray : 'toArray'
|
251
242
|
}, true);
|
252
243
|
|
package/src/dialog/Base.mjs
CHANGED
@@ -298,7 +298,7 @@ class Base extends Panel {
|
|
298
298
|
|
299
299
|
me.closeOrHide(false);
|
300
300
|
|
301
|
-
await
|
301
|
+
await me.timeout(30);
|
302
302
|
|
303
303
|
await Neo.currentWorker.promiseMessage('main', {
|
304
304
|
action: 'updateDom',
|
@@ -314,7 +314,7 @@ class Base extends Panel {
|
|
314
314
|
}]
|
315
315
|
});
|
316
316
|
|
317
|
-
await
|
317
|
+
await me.timeout(250);
|
318
318
|
|
319
319
|
await Neo.currentWorker.promiseMessage('main', {
|
320
320
|
action: 'updateDom',
|
@@ -340,7 +340,7 @@ class Base extends Panel {
|
|
340
340
|
parentId: 'document.body'
|
341
341
|
});
|
342
342
|
|
343
|
-
await
|
343
|
+
await me.timeout(30);
|
344
344
|
|
345
345
|
await Neo.currentWorker.promiseMessage('main', {
|
346
346
|
action: 'updateDom',
|
@@ -357,9 +357,9 @@ class Base extends Panel {
|
|
357
357
|
}]
|
358
358
|
});
|
359
359
|
|
360
|
-
await
|
360
|
+
await me.timeout(200);
|
361
361
|
|
362
|
-
me.show(false)
|
362
|
+
me.show(false)
|
363
363
|
}
|
364
364
|
|
365
365
|
/**
|
@@ -82,14 +82,14 @@ class SortZone extends DragZone {
|
|
82
82
|
* @param {Object} data
|
83
83
|
*/
|
84
84
|
async onDragEnd(data) {
|
85
|
-
await Neo.timeout(10);
|
86
|
-
|
87
85
|
let me = this,
|
88
86
|
owner = me.owner,
|
89
87
|
itemStyles = me.itemStyles,
|
90
88
|
ownerStyle = owner.style || {},
|
91
89
|
itemStyle;
|
92
90
|
|
91
|
+
await me.timeout(10);
|
92
|
+
|
93
93
|
if (owner.sortable) {
|
94
94
|
ownerStyle.height = me.ownerStyle.height || null;
|
95
95
|
ownerStyle.width = me.ownerStyle.width || null;
|
@@ -127,7 +127,7 @@ class SortZone extends DragZone {
|
|
127
127
|
startIndex : -1
|
128
128
|
});
|
129
129
|
|
130
|
-
await
|
130
|
+
await me.timeout(30);
|
131
131
|
|
132
132
|
me.dragEnd(data); // we do not want to trigger the super class call here
|
133
133
|
}
|
package/src/list/Base.mjs
CHANGED
package/src/menu/Model.mjs
CHANGED
package/src/model/Component.mjs
CHANGED
@@ -44,6 +44,27 @@ class Component extends Base {
|
|
44
44
|
* @member {Object|null} data_=null
|
45
45
|
*/
|
46
46
|
data_: null,
|
47
|
+
/**
|
48
|
+
* @member {Object|null} formulas_=null
|
49
|
+
*
|
50
|
+
* @example
|
51
|
+
* data: {
|
52
|
+
* a: 1,
|
53
|
+
* b: 2
|
54
|
+
* }
|
55
|
+
* formulas: {
|
56
|
+
* aPlusB: {
|
57
|
+
* bind: {
|
58
|
+
* foo: 'a',
|
59
|
+
* bar: 'b'
|
60
|
+
* },
|
61
|
+
* get(data) {
|
62
|
+
* return data.foo + data.bar
|
63
|
+
* }
|
64
|
+
* }
|
65
|
+
* }
|
66
|
+
*/
|
67
|
+
formulas_: null,
|
47
68
|
/**
|
48
69
|
* @member {Neo.model.Component|null} parent_=null
|
49
70
|
*/
|
@@ -60,7 +81,7 @@ class Component extends Base {
|
|
60
81
|
construct(config) {
|
61
82
|
Neo.currentWorker.isUsingViewModels = true;
|
62
83
|
super.construct(config);
|
63
|
-
this.bindings = {}
|
84
|
+
this.bindings = {}
|
64
85
|
}
|
65
86
|
|
66
87
|
/**
|
@@ -77,12 +98,12 @@ class Component extends Base {
|
|
77
98
|
|
78
99
|
Neo.ns(key, true, me.data);
|
79
100
|
|
80
|
-
data
|
101
|
+
data = me.getDataScope(key);
|
81
102
|
scope = data.scope;
|
82
103
|
|
83
104
|
scope[data.key] = value;
|
84
105
|
|
85
|
-
me.createDataProperties(me.data, 'data')
|
106
|
+
me.createDataProperties(me.data, 'data')
|
86
107
|
}
|
87
108
|
|
88
109
|
/**
|
@@ -92,7 +113,17 @@ class Component extends Base {
|
|
92
113
|
* @protected
|
93
114
|
*/
|
94
115
|
afterSetData(value, oldValue) {
|
95
|
-
value && this.createDataProperties(value, 'data')
|
116
|
+
value && this.createDataProperties(value, 'data')
|
117
|
+
}
|
118
|
+
|
119
|
+
/**
|
120
|
+
* Triggered after the formulas config got changed
|
121
|
+
* @param {Object|null} value
|
122
|
+
* @param {Object|null} oldValue
|
123
|
+
* @protected
|
124
|
+
*/
|
125
|
+
afterSetFormulas(value, oldValue) {
|
126
|
+
value && this.resolveFormulas(null)
|
96
127
|
}
|
97
128
|
|
98
129
|
/**
|
@@ -101,7 +132,7 @@ class Component extends Base {
|
|
101
132
|
* @protected
|
102
133
|
*/
|
103
134
|
beforeGetData(value) {
|
104
|
-
return value || {}
|
135
|
+
return value || {}
|
105
136
|
}
|
106
137
|
|
107
138
|
/**
|
@@ -111,7 +142,7 @@ class Component extends Base {
|
|
111
142
|
* @protected
|
112
143
|
*/
|
113
144
|
beforeSetParent(value, oldValue) {
|
114
|
-
return value ? value : this.getParent()
|
145
|
+
return value ? value : this.getParent()
|
115
146
|
}
|
116
147
|
|
117
148
|
/**
|
@@ -126,23 +157,23 @@ class Component extends Base {
|
|
126
157
|
|
127
158
|
value && Object.entries(value).forEach(([key, storeValue]) => {
|
128
159
|
controller?.parseConfig(storeValue);
|
129
|
-
value[key] = ClassSystemUtil.beforeSetInstance(storeValue)
|
160
|
+
value[key] = ClassSystemUtil.beforeSetInstance(storeValue)
|
130
161
|
});
|
131
162
|
|
132
|
-
return value
|
163
|
+
return value
|
133
164
|
}
|
134
165
|
|
135
166
|
/**
|
136
167
|
* @param {Function} formatter
|
137
|
-
* @param {Object}
|
168
|
+
* @param {Object} data=null optionally pass this.getHierarchyData() for performance reasons
|
138
169
|
* @returns {String}
|
139
170
|
*/
|
140
171
|
callFormatter(formatter, data=null) {
|
141
172
|
if (!data) {
|
142
|
-
data = this.getHierarchyData()
|
173
|
+
data = this.getHierarchyData()
|
143
174
|
}
|
144
175
|
|
145
|
-
return formatter.call(this, data)
|
176
|
+
return formatter.call(this, data)
|
146
177
|
}
|
147
178
|
|
148
179
|
/**
|
@@ -162,21 +193,21 @@ class Component extends Base {
|
|
162
193
|
|
163
194
|
if (scope?.hasOwnProperty(keyLeaf)) {
|
164
195
|
bindingScope = Neo.ns(`${key}.${componentId}`, true, me.bindings);
|
165
|
-
bindingScope[value] = formatter
|
196
|
+
bindingScope[value] = formatter
|
166
197
|
} else {
|
167
198
|
parentModel = me.getParent();
|
168
199
|
|
169
200
|
if (parentModel) {
|
170
|
-
parentModel.createBinding(componentId, key, value, formatter)
|
201
|
+
parentModel.createBinding(componentId, key, value, formatter)
|
171
202
|
} else {
|
172
|
-
console.error('No model.Component found with the specified data property', componentId, keyLeaf, value)
|
203
|
+
console.error('No model.Component found with the specified data property', componentId, keyLeaf, value)
|
173
204
|
}
|
174
205
|
}
|
175
206
|
}
|
176
207
|
|
177
208
|
/**
|
178
209
|
* Registers a new binding in case a matching data property does exist.
|
179
|
-
* Otherwise it will use the closest model with a match.
|
210
|
+
* Otherwise, it will use the closest model with a match.
|
180
211
|
* @param {String} componentId
|
181
212
|
* @param {String} formatter
|
182
213
|
* @param {String} value
|
@@ -186,8 +217,8 @@ class Component extends Base {
|
|
186
217
|
formatterVars = me.getFormatterVariables(formatter);
|
187
218
|
|
188
219
|
formatterVars.forEach(key => {
|
189
|
-
me.createBinding(componentId, key, value, formatter)
|
190
|
-
})
|
220
|
+
me.createBinding(componentId, key, value, formatter)
|
221
|
+
})
|
191
222
|
}
|
192
223
|
|
193
224
|
/**
|
@@ -196,13 +227,13 @@ class Component extends Base {
|
|
196
227
|
createBindings(component) {
|
197
228
|
Object.entries(component.bind).forEach(([key, value]) => {
|
198
229
|
if (Neo.isObject(value)) {
|
199
|
-
value = value.value
|
230
|
+
value = value.value
|
200
231
|
}
|
201
232
|
|
202
233
|
if (!this.isStoreValue(value)) {
|
203
|
-
this.createBindingByFormatter(component.id, value, key)
|
234
|
+
this.createBindingByFormatter(component.id, value, key)
|
204
235
|
}
|
205
|
-
})
|
236
|
+
})
|
206
237
|
}
|
207
238
|
|
208
239
|
/**
|
@@ -222,31 +253,31 @@ class Component extends Base {
|
|
222
253
|
if (!(typeof descriptor === 'object' && typeof descriptor.set === 'function')) {
|
223
254
|
keyValue = config[key];
|
224
255
|
me.createDataProperty(key, newPath, root);
|
225
|
-
root[key] = keyValue
|
256
|
+
root[key] = keyValue
|
226
257
|
}
|
227
258
|
|
228
259
|
if (Neo.isObject(value)) {
|
229
|
-
me.createDataProperties(config[key], newPath)
|
260
|
+
me.createDataProperties(config[key], newPath)
|
230
261
|
}
|
231
262
|
}
|
232
|
-
})
|
263
|
+
})
|
233
264
|
}
|
234
265
|
|
235
266
|
/**
|
236
267
|
* @param {String} key
|
237
268
|
* @param {String} path
|
238
|
-
* @param {Object}
|
269
|
+
* @param {Object} root=this.data
|
239
270
|
*/
|
240
271
|
createDataProperty(key, path, root=this.data) {
|
241
272
|
let me = this;
|
242
273
|
|
243
274
|
if (path?.startsWith('data.')) {
|
244
|
-
path = path.substring(5)
|
275
|
+
path = path.substring(5)
|
245
276
|
}
|
246
277
|
|
247
278
|
Object.defineProperty(root, key, {
|
248
279
|
get() {
|
249
|
-
return root['_' + key]
|
280
|
+
return root['_' + key]
|
250
281
|
},
|
251
282
|
|
252
283
|
set(value) {
|
@@ -258,16 +289,16 @@ class Component extends Base {
|
|
258
289
|
enumerable: false,
|
259
290
|
value,
|
260
291
|
writable : true
|
261
|
-
})
|
292
|
+
})
|
262
293
|
} else {
|
263
|
-
root[_key] = value
|
294
|
+
root[_key] = value
|
264
295
|
}
|
265
296
|
|
266
297
|
if (!Neo.isEqual(value, oldValue)) {
|
267
|
-
me.onDataPropertyChange(path ? path : key, value, oldValue)
|
298
|
+
me.onDataPropertyChange(path ? path : key, value, oldValue)
|
268
299
|
}
|
269
300
|
}
|
270
|
-
})
|
301
|
+
})
|
271
302
|
}
|
272
303
|
|
273
304
|
/**
|
@@ -276,13 +307,13 @@ class Component extends Base {
|
|
276
307
|
* @returns {Neo.controller.Component|null}
|
277
308
|
*/
|
278
309
|
getController(ntype) {
|
279
|
-
return this.component.getController(ntype)
|
310
|
+
return this.component.getController(ntype)
|
280
311
|
}
|
281
312
|
|
282
313
|
/**
|
283
314
|
* Access the closest data property inside the VM parent chain.
|
284
315
|
* @param {String} key
|
285
|
-
* @param {Neo.model.Component}
|
316
|
+
* @param {Neo.model.Component} originModel=this for internal usage only
|
286
317
|
* @returns {*} value
|
287
318
|
*/
|
288
319
|
getData(key, originModel=this) {
|
@@ -293,16 +324,16 @@ class Component extends Base {
|
|
293
324
|
parentModel;
|
294
325
|
|
295
326
|
if (scope?.hasOwnProperty(keyLeaf)) {
|
296
|
-
return scope[keyLeaf]
|
327
|
+
return scope[keyLeaf]
|
297
328
|
}
|
298
329
|
|
299
330
|
parentModel = me.getParent();
|
300
331
|
|
301
332
|
if (!parentModel) {
|
302
|
-
console.error(`data property '${key}' does not exist.`, originModel)
|
333
|
+
console.error(`data property '${key}' does not exist.`, originModel)
|
303
334
|
}
|
304
335
|
|
305
|
-
return parentModel.getData(key, originModel)
|
336
|
+
return parentModel.getData(key, originModel)
|
306
337
|
}
|
307
338
|
|
308
339
|
/**
|
@@ -321,13 +352,13 @@ class Component extends Base {
|
|
321
352
|
if (key.includes('.')) {
|
322
353
|
key = key.split('.');
|
323
354
|
keyLeaf = key.pop();
|
324
|
-
data = Neo.ns(key.join('.'), false, data)
|
355
|
+
data = Neo.ns(key.join('.'), false, data)
|
325
356
|
}
|
326
357
|
|
327
358
|
return {
|
328
359
|
key : keyLeaf,
|
329
360
|
scope: data
|
330
|
-
}
|
361
|
+
}
|
331
362
|
}
|
332
363
|
|
333
364
|
/**
|
@@ -336,7 +367,7 @@ class Component extends Base {
|
|
336
367
|
*/
|
337
368
|
getFormatterVariables(value) {
|
338
369
|
if (Neo.isFunction(value)) {
|
339
|
-
value = value.toString()
|
370
|
+
value = value.toString()
|
340
371
|
}
|
341
372
|
|
342
373
|
if (Neo.config.environment === 'dist/production') {
|
@@ -353,7 +384,7 @@ class Component extends Base {
|
|
353
384
|
let dataName = value.match(variableNameRegex)[0],
|
354
385
|
variableRegExp = new RegExp(`(^|[^\\w.])(${dataName})(?!\\w)`, 'g');
|
355
386
|
|
356
|
-
value = value.replace(variableRegExp, '$1data')
|
387
|
+
value = value.replace(variableRegExp, '$1data')
|
357
388
|
}
|
358
389
|
|
359
390
|
let dataVars = value.match(dataVariableRegex) || [],
|
@@ -362,12 +393,12 @@ class Component extends Base {
|
|
362
393
|
dataVars.forEach(variable => {
|
363
394
|
// remove the "data." at the start
|
364
395
|
variable = variable.substr(5);
|
365
|
-
NeoArray.add(result, variable)
|
396
|
+
NeoArray.add(result, variable)
|
366
397
|
});
|
367
398
|
|
368
399
|
result.sort();
|
369
400
|
|
370
|
-
return result
|
401
|
+
return result
|
371
402
|
}
|
372
403
|
|
373
404
|
/**
|
@@ -383,16 +414,16 @@ class Component extends Base {
|
|
383
414
|
return {
|
384
415
|
...parent.getHierarchyData(data),
|
385
416
|
...me.getPlainData()
|
386
|
-
}
|
417
|
+
}
|
387
418
|
}
|
388
419
|
|
389
|
-
return me.getPlainData()
|
420
|
+
return me.getPlainData()
|
390
421
|
}
|
391
422
|
|
392
423
|
/**
|
393
424
|
* Returns a plain version of this.data.
|
394
425
|
* This excludes the property getters & setters.
|
395
|
-
* @param {Object}
|
426
|
+
* @param {Object} data=this.data
|
396
427
|
* @returns {Object}
|
397
428
|
*/
|
398
429
|
getPlainData(data=this.data) {
|
@@ -400,13 +431,13 @@ class Component extends Base {
|
|
400
431
|
|
401
432
|
Object.entries(data).forEach(([key, value]) => {
|
402
433
|
if (Neo.typeOf(value) === 'Object') {
|
403
|
-
plainData[key] = this.getPlainData(value)
|
434
|
+
plainData[key] = this.getPlainData(value)
|
404
435
|
} else {
|
405
|
-
plainData[key] = value
|
436
|
+
plainData[key] = value
|
406
437
|
}
|
407
438
|
});
|
408
439
|
|
409
|
-
return plainData
|
440
|
+
return plainData
|
410
441
|
}
|
411
442
|
|
412
443
|
/**
|
@@ -418,19 +449,19 @@ class Component extends Base {
|
|
418
449
|
parentComponent, parentId;
|
419
450
|
|
420
451
|
if (me.parent) {
|
421
|
-
return me.parent
|
452
|
+
return me.parent
|
422
453
|
}
|
423
454
|
|
424
|
-
parentId
|
455
|
+
parentId = me.component.parentId;
|
425
456
|
parentComponent = parentId && Neo.getComponent(parentId);
|
426
457
|
|
427
|
-
return parentComponent?.getModel() || null
|
458
|
+
return parentComponent?.getModel() || null
|
428
459
|
}
|
429
460
|
|
430
461
|
/**
|
431
462
|
* Access the closest store inside the VM parent chain.
|
432
463
|
* @param {String} key
|
433
|
-
* @param {Neo.model.Component}
|
464
|
+
* @param {Neo.model.Component} originModel=this for internal usage only
|
434
465
|
* @returns {*} value
|
435
466
|
*/
|
436
467
|
getStore(key, originModel=this) {
|
@@ -439,16 +470,16 @@ class Component extends Base {
|
|
439
470
|
parentModel;
|
440
471
|
|
441
472
|
if (stores?.hasOwnProperty(key)) {
|
442
|
-
return stores[key]
|
473
|
+
return stores[key]
|
443
474
|
}
|
444
475
|
|
445
476
|
parentModel = me.getParent();
|
446
477
|
|
447
478
|
if (!parentModel) {
|
448
|
-
console.error(`store '${key}' not found inside this model or parents.`, originModel)
|
479
|
+
console.error(`store '${key}' not found inside this model or parents.`, originModel)
|
449
480
|
}
|
450
481
|
|
451
|
-
return parentModel.getStore(key, originModel)
|
482
|
+
return parentModel.getStore(key, originModel)
|
452
483
|
}
|
453
484
|
|
454
485
|
/**
|
@@ -469,26 +500,26 @@ class Component extends Base {
|
|
469
500
|
|
470
501
|
if (Neo.isObject(key)) {
|
471
502
|
Object.entries(key).forEach(([dataKey, dataValue]) => {
|
472
|
-
me.internalSetData(dataKey, dataValue, originModel)
|
473
|
-
})
|
503
|
+
me.internalSetData(dataKey, dataValue, originModel)
|
504
|
+
})
|
474
505
|
} else {
|
475
506
|
data = me.getDataScope(key);
|
476
|
-
scope = data.scope;
|
477
507
|
keyLeaf = data.key;
|
508
|
+
scope = data.scope;
|
478
509
|
|
479
510
|
if (scope?.hasOwnProperty(keyLeaf)) {
|
480
|
-
scope[keyLeaf] = value
|
511
|
+
scope[keyLeaf] = value
|
481
512
|
} else {
|
482
513
|
if (originModel) {
|
483
514
|
parentModel = me.getParent();
|
484
515
|
|
485
516
|
if (parentModel) {
|
486
|
-
parentModel.internalSetData(key, value, originModel)
|
517
|
+
parentModel.internalSetData(key, value, originModel)
|
487
518
|
} else {
|
488
|
-
originModel.addDataProperty(key, value)
|
519
|
+
originModel.addDataProperty(key, value)
|
489
520
|
}
|
490
521
|
} else {
|
491
|
-
me.addDataProperty(key, value)
|
522
|
+
me.addDataProperty(key, value)
|
492
523
|
}
|
493
524
|
}
|
494
525
|
}
|
@@ -500,7 +531,7 @@ class Component extends Base {
|
|
500
531
|
* @returns {Boolean}
|
501
532
|
*/
|
502
533
|
isStoreValue(value) {
|
503
|
-
return Neo.isString(value) && value.startsWith('stores.')
|
534
|
+
return Neo.isString(value) && value.startsWith('stores.')
|
504
535
|
}
|
505
536
|
|
506
537
|
/**
|
@@ -511,10 +542,10 @@ class Component extends Base {
|
|
511
542
|
*/
|
512
543
|
mergeConfig(config, preventOriginalConfig) {
|
513
544
|
if (config.data) {
|
514
|
-
config.data = Neo.merge(Neo.clone(this.constructor.config.data, true) || {}, config.data)
|
545
|
+
config.data = Neo.merge(Neo.clone(this.constructor.config.data, true) || {}, config.data)
|
515
546
|
}
|
516
547
|
|
517
|
-
return super.mergeConfig(config, preventOriginalConfig)
|
548
|
+
return super.mergeConfig(config, preventOriginalConfig)
|
518
549
|
}
|
519
550
|
|
520
551
|
/**
|
@@ -532,35 +563,32 @@ class Component extends Base {
|
|
532
563
|
|
533
564
|
Object.entries(binding).forEach(([componentId, configObject]) => {
|
534
565
|
component = Neo.getComponent(componentId) || Neo.get(componentId); // timing issue: the cmp might not be registered inside manager.Component yet
|
535
|
-
config
|
536
|
-
model
|
566
|
+
config = {};
|
567
|
+
model = component.getModel();
|
537
568
|
|
538
569
|
if (!hierarchyData[model.id]) {
|
539
|
-
hierarchyData[model.id] = model.getHierarchyData()
|
570
|
+
hierarchyData[model.id] = model.getHierarchyData()
|
540
571
|
}
|
541
572
|
|
542
573
|
Object.entries(configObject).forEach(([configField, formatter]) => {
|
543
574
|
// we can not call me.callFormatter(), since a data property inside a parent model
|
544
575
|
// could have changed which is relying on data properties inside a closer model
|
545
|
-
config[configField] = model.callFormatter(formatter, hierarchyData[model.id])
|
576
|
+
config[configField] = model.callFormatter(formatter, hierarchyData[model.id])
|
546
577
|
});
|
547
578
|
|
548
|
-
component?.set(config)
|
549
|
-
})
|
579
|
+
component?.set(config)
|
580
|
+
})
|
550
581
|
}
|
551
582
|
|
552
|
-
me.
|
553
|
-
|
554
|
-
|
555
|
-
oldValue,
|
556
|
-
value
|
557
|
-
});
|
583
|
+
me.resolveFormulas({key, id: me.id, oldValue, value});
|
584
|
+
|
585
|
+
me.fire('dataPropertyChange', {key, id: me.id, oldValue, value})
|
558
586
|
}
|
559
587
|
|
560
588
|
/**
|
561
589
|
* This method will assign binding values at the earliest possible point inside the component lifecycle.
|
562
590
|
* It can not store bindings though, since child component ids most likely do not exist yet.
|
563
|
-
* @param {Neo.component.Base}
|
591
|
+
* @param {Neo.component.Base} component=this.component
|
564
592
|
*/
|
565
593
|
parseConfig(component=this.component) {
|
566
594
|
let me = this,
|
@@ -572,17 +600,17 @@ class Component extends Base {
|
|
572
600
|
Object.entries(component.bind).forEach(([key, value]) => {
|
573
601
|
if (Neo.isObject(value)) {
|
574
602
|
value.key = me.getFormatterVariables(value.value)[0];
|
575
|
-
value = value.value
|
603
|
+
value = value.value
|
576
604
|
}
|
577
605
|
|
578
606
|
if (me.isStoreValue(value)) {
|
579
|
-
me.resolveStore(component, key, value.substring(7))
|
607
|
+
me.resolveStore(component, key, value.substring(7)) // remove the "stores." at the start
|
580
608
|
} else {
|
581
|
-
config[key] = me.callFormatter(value)
|
609
|
+
config[key] = me.callFormatter(value)
|
582
610
|
}
|
583
611
|
});
|
584
612
|
|
585
|
-
component.set(config)
|
613
|
+
component.set(config)
|
586
614
|
}
|
587
615
|
}
|
588
616
|
|
@@ -596,10 +624,56 @@ class Component extends Base {
|
|
596
624
|
parentModel = me.getParent();
|
597
625
|
|
598
626
|
Object.entries(me.bindings).forEach(([dataProperty, binding]) => {
|
599
|
-
delete binding[componentId]
|
627
|
+
delete binding[componentId]
|
600
628
|
});
|
601
629
|
|
602
|
-
parentModel?.removeBindings(componentId)
|
630
|
+
parentModel?.removeBindings(componentId)
|
631
|
+
}
|
632
|
+
|
633
|
+
/**
|
634
|
+
* Resolve the formulas initially and update, when data change
|
635
|
+
* @param {Object} data data from event or null on initial call
|
636
|
+
*/
|
637
|
+
resolveFormulas(data) {
|
638
|
+
let me = this,
|
639
|
+
formulas = me.formulas,
|
640
|
+
initialRun = !data,
|
641
|
+
affectFormula, bindObject, fn, key, result, value;
|
642
|
+
|
643
|
+
if (formulas) {
|
644
|
+
if (!initialRun && (!data.key || !data.value)) {
|
645
|
+
console.warn('[ViewModel:formulas] missing key or value', data.key, data.value)
|
646
|
+
}
|
647
|
+
|
648
|
+
for ([key, value] of Object.entries(formulas)) {
|
649
|
+
affectFormula = true;
|
650
|
+
|
651
|
+
// Check if the change affects a formula
|
652
|
+
if (!initialRun) {
|
653
|
+
affectFormula = Object.values(value.bind).includes(data.key)
|
654
|
+
}
|
655
|
+
|
656
|
+
if (affectFormula) {
|
657
|
+
// Create Bind-Object and fill with new values
|
658
|
+
bindObject = Neo.clone(value.bind);
|
659
|
+
fn = value.get;
|
660
|
+
|
661
|
+
Object.keys(bindObject).forEach((key, index) => {
|
662
|
+
bindObject[key] = me.getData(bindObject[key])
|
663
|
+
});
|
664
|
+
|
665
|
+
// Calc the formula
|
666
|
+
result = fn(bindObject);
|
667
|
+
|
668
|
+
// Assign if no error or null
|
669
|
+
if (isNaN(result)) {
|
670
|
+
me.setData(key, null)
|
671
|
+
} else {
|
672
|
+
me.setData(key, result)
|
673
|
+
}
|
674
|
+
}
|
675
|
+
}
|
676
|
+
}
|
603
677
|
}
|
604
678
|
|
605
679
|
/**
|
@@ -608,7 +682,7 @@ class Component extends Base {
|
|
608
682
|
* @param {String} storeName
|
609
683
|
*/
|
610
684
|
resolveStore(component, configName, storeName) {
|
611
|
-
component[configName] = this.getStore(storeName)
|
685
|
+
component[configName] = this.getStore(storeName)
|
612
686
|
}
|
613
687
|
|
614
688
|
/**
|
@@ -618,7 +692,7 @@ class Component extends Base {
|
|
618
692
|
* @param {*} value
|
619
693
|
*/
|
620
694
|
setData(key, value) {
|
621
|
-
this.internalSetData(key, value, this)
|
695
|
+
this.internalSetData(key, value, this)
|
622
696
|
}
|
623
697
|
|
624
698
|
/**
|
@@ -628,7 +702,7 @@ class Component extends Base {
|
|
628
702
|
* @param {*} value
|
629
703
|
*/
|
630
704
|
setDataAtSameLevel(key, value) {
|
631
|
-
this.internalSetData(key, value)
|
705
|
+
this.internalSetData(key, value)
|
632
706
|
}
|
633
707
|
}
|
634
708
|
|
package/src/util/Logger.mjs
CHANGED
@@ -18,7 +18,7 @@ class Logger extends Base {
|
|
18
18
|
*
|
19
19
|
* Neo.util.Logger.enableLogsInProduction = true;
|
20
20
|
*
|
21
|
-
* @member {
|
21
|
+
* @member {Boolean} enableLogsInProduction=true
|
22
22
|
*/
|
23
23
|
enableLogsInProduction: false,
|
24
24
|
/**
|
@@ -27,9 +27,9 @@ class Logger extends Base {
|
|
27
27
|
*
|
28
28
|
* Neo.util.Logger.enableComponentLogger = true;
|
29
29
|
*
|
30
|
-
* @member {
|
30
|
+
* @member {Boolean} enableComponentLogger=true
|
31
31
|
*/
|
32
|
-
|
32
|
+
enableComponentLogger: true,
|
33
33
|
/**
|
34
34
|
* Set the minimum level, which you want to output.
|
35
35
|
* Change this at any time using a value of logLevels: ['info', 'log', 'warn', 'error']
|
@@ -101,7 +101,8 @@ class Logger extends Base {
|
|
101
101
|
*/
|
102
102
|
addContextMenuListener(view) {
|
103
103
|
view.addDomListeners({
|
104
|
-
contextmenu: this.onContextMenu
|
104
|
+
contextmenu: this.onContextMenu,
|
105
|
+
scope : this
|
105
106
|
})
|
106
107
|
}
|
107
108
|
|
@@ -184,7 +185,11 @@ class Logger extends Base {
|
|
184
185
|
* @param {Object} data
|
185
186
|
*/
|
186
187
|
onContextMenu(data) {
|
187
|
-
if (
|
188
|
+
if (
|
189
|
+
data.ctrlKey
|
190
|
+
&& this.enableComponentLogger
|
191
|
+
&& !(Neo.config.env === 'dist/production' && this.enableLogsInProduction)
|
192
|
+
) {
|
188
193
|
let isGroupSet = false,
|
189
194
|
component;
|
190
195
|
|
package/src/worker/App.mjs
CHANGED
@@ -20,6 +20,17 @@ class App extends Base {
|
|
20
20
|
* @protected
|
21
21
|
*/
|
22
22
|
className: 'Neo.worker.App',
|
23
|
+
/**
|
24
|
+
* Remote method access for other workers
|
25
|
+
* @member {Object} remote
|
26
|
+
* @protected
|
27
|
+
*/
|
28
|
+
remote: {
|
29
|
+
main: [
|
30
|
+
'createNeoInstance',
|
31
|
+
'destroyNeoInstance'
|
32
|
+
]
|
33
|
+
},
|
23
34
|
/**
|
24
35
|
* @member {Boolean} singleton=true
|
25
36
|
* @protected
|
@@ -72,6 +83,62 @@ class App extends Base {
|
|
72
83
|
return this.promiseMessage('main', {action: 'updateDom', appName, deltas})
|
73
84
|
}
|
74
85
|
|
86
|
+
/**
|
87
|
+
* Remote method to use inside main threads for creating neo based class instances.
|
88
|
+
* Be aware that you can only pass configs which can get converted into pure JSON.
|
89
|
+
*
|
90
|
+
* Rendering a component into the document.body
|
91
|
+
* @example:
|
92
|
+
* Neo.worker.App.createNeoInstance({
|
93
|
+
* ntype : 'button',
|
94
|
+
* autoMount : true,
|
95
|
+
* autoRender: true
|
96
|
+
* text : 'Hi Nige!'
|
97
|
+
* }).then(id => console.log(id))
|
98
|
+
*
|
99
|
+
* Inserting a component into a container
|
100
|
+
* @example:
|
101
|
+
* Neo.worker.App.createNeoInstance({
|
102
|
+
* ntype : 'button',
|
103
|
+
* parentId : 'neo-container-3',
|
104
|
+
* parentIndex: 0
|
105
|
+
* text : 'Hi Nige!'
|
106
|
+
* }).then(id => console.log(id))
|
107
|
+
*
|
108
|
+
* @param {Object} config
|
109
|
+
* @param {String} [config.parentId] passing a parentId will put your instance into a container
|
110
|
+
* @param {Number} [config.parentIndex] if a parentId is passed, but no index, neo will use add()
|
111
|
+
* @returns {String} the instance id
|
112
|
+
*/
|
113
|
+
createNeoInstance(config) {
|
114
|
+
let appName = Object.keys(Neo.apps)[0], // fallback in case no appName was provided
|
115
|
+
Container = Neo.container?.Base,
|
116
|
+
index, instance, parent;
|
117
|
+
|
118
|
+
config = {appName: appName, ...config};
|
119
|
+
|
120
|
+
if (config.parentId) {
|
121
|
+
parent = Neo.getComponent(config.parentId);
|
122
|
+
|
123
|
+
if (Container && parent && parent instanceof Container) {
|
124
|
+
index = config.parentIndex;
|
125
|
+
|
126
|
+
delete config.parentId;
|
127
|
+
delete config.parentIndex;
|
128
|
+
|
129
|
+
if (Neo.isNumber(index)) {
|
130
|
+
instance = parent.insert(index, config)
|
131
|
+
} else {
|
132
|
+
instance = parent.add(config)
|
133
|
+
}
|
134
|
+
}
|
135
|
+
} else {
|
136
|
+
instance = Neo[config.ntype ? 'ntype' : 'create'](config)
|
137
|
+
}
|
138
|
+
|
139
|
+
return instance.id
|
140
|
+
}
|
141
|
+
|
75
142
|
/**
|
76
143
|
* @param {Object} data
|
77
144
|
*/
|
@@ -81,6 +148,36 @@ class App extends Base {
|
|
81
148
|
this.resolveThemeFilesCache()
|
82
149
|
}
|
83
150
|
|
151
|
+
/**
|
152
|
+
* Remote method to use inside main threads for destroying neo based class instances.
|
153
|
+
*
|
154
|
+
* @example:
|
155
|
+
* Neo.worker.App.destroyNeoInstance('neo-button-3').then(success => console.log(success))
|
156
|
+
*
|
157
|
+
* @param {String} id
|
158
|
+
* @returns {Boolean} returns true, in case the instance was found
|
159
|
+
*/
|
160
|
+
destroyNeoInstance(id) {
|
161
|
+
let instance = Neo.get(id),
|
162
|
+
parent;
|
163
|
+
|
164
|
+
if (instance) {
|
165
|
+
if (instance.parentId) {
|
166
|
+
parent = Neo.getComponent(instance.parentId);
|
167
|
+
|
168
|
+
if (parent) {
|
169
|
+
parent.remove(instance);
|
170
|
+
return true
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
instance.destroy(true, true);
|
175
|
+
return true
|
176
|
+
}
|
177
|
+
|
178
|
+
return false
|
179
|
+
}
|
180
|
+
|
84
181
|
/**
|
85
182
|
* Only needed for the SharedWorkers context
|
86
183
|
* @param {String} eventName
|