neo.mjs 5.1.16 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/ServiceWorker.mjs +2 -2
- package/apps/form/Overwrites.mjs +2 -1
- package/apps/form/view/FormContainer.mjs +19 -22
- package/apps/form/view/Viewport.mjs +3 -2
- package/apps/form/view/ViewportController.mjs +47 -7
- package/examples/ServiceWorker.mjs +2 -2
- package/package.json +1 -1
- package/resources/scss/src/form/field/Text.scss +1 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/form/Container.mjs +82 -31
- package/src/form/field/Text.mjs +8 -4
- package/src/layout/Card.mjs +51 -20
package/apps/ServiceWorker.mjs
CHANGED
package/apps/form/Overwrites.mjs
CHANGED
@@ -38,8 +38,14 @@ class FormContainer extends BaseFormContainer {
|
|
38
38
|
cls : ['form-header-label'],
|
39
39
|
flex : 'none'
|
40
40
|
}, '->', {
|
41
|
+
iconCls: ['fas', 'fa-file'],
|
41
42
|
handler: 'onValidatePageButtonClick',
|
42
|
-
text : 'Validate
|
43
|
+
text : 'Validate page'
|
44
|
+
}, {
|
45
|
+
iconCls: ['fas', 'fa-layer-group'],
|
46
|
+
handler: 'onValidateAllPagesButtonClick',
|
47
|
+
style : {marginLeft: '1em'},
|
48
|
+
text : 'Validate all pages'
|
43
49
|
}]
|
44
50
|
}, {
|
45
51
|
module : Container,
|
@@ -50,27 +56,18 @@ class FormContainer extends BaseFormContainer {
|
|
50
56
|
bind : {activeIndex: data => data.activeIndex}
|
51
57
|
},
|
52
58
|
|
53
|
-
items: [
|
54
|
-
module: () => import('./pages/Page1.mjs')
|
55
|
-
|
56
|
-
module: () => import('./pages/
|
57
|
-
|
58
|
-
module: () => import('./pages/
|
59
|
-
|
60
|
-
module: () => import('./pages/
|
61
|
-
|
62
|
-
module: () => import('./pages/
|
63
|
-
|
64
|
-
|
65
|
-
}, {
|
66
|
-
module: () => import('./pages/Page7.mjs')
|
67
|
-
}, {
|
68
|
-
module: () => import('./pages/Page8.mjs')
|
69
|
-
}, {
|
70
|
-
module: () => import('./pages/Page9.mjs')
|
71
|
-
}, {
|
72
|
-
module: () => import('./pages/Page10.mjs')
|
73
|
-
}]
|
59
|
+
items: [
|
60
|
+
{module: () => import('./pages/Page1.mjs')},
|
61
|
+
{module: () => import('./pages/Page2.mjs')},
|
62
|
+
{module: () => import('./pages/Page3.mjs')},
|
63
|
+
{module: () => import('./pages/Page4.mjs')},
|
64
|
+
{module: () => import('./pages/Page5.mjs')},
|
65
|
+
{module: () => import('./pages/Page6.mjs')},
|
66
|
+
{module: () => import('./pages/Page7.mjs')},
|
67
|
+
{module: () => import('./pages/Page8.mjs')},
|
68
|
+
{module: () => import('./pages/Page9.mjs')},
|
69
|
+
{module: () => import('./pages/Page10.mjs')}
|
70
|
+
]
|
74
71
|
}, {
|
75
72
|
module: Toolbar,
|
76
73
|
cls : ['form-footer'],
|
@@ -40,8 +40,9 @@ class Viewport extends BaseViewport {
|
|
40
40
|
}
|
41
41
|
}]
|
42
42
|
}, {
|
43
|
-
module: FormContainer,
|
44
|
-
|
43
|
+
module : FormContainer,
|
44
|
+
reference: 'main-form',
|
45
|
+
style : {margin: '20px'}
|
45
46
|
}],
|
46
47
|
/**
|
47
48
|
* @member {Object} layout={ntype:'hbox',align:'stretch'}
|
@@ -16,19 +16,59 @@ class ViewportController extends Component {
|
|
16
16
|
/**
|
17
17
|
* @param {Object} data
|
18
18
|
*/
|
19
|
-
|
19
|
+
async onValidateAllPagesButtonClick(data) {
|
20
|
+
let me = this,
|
21
|
+
form = me.getReference('main-form'),
|
22
|
+
isValid = await form.validate(),
|
23
|
+
formValues = await form.getValues();
|
24
|
+
|
25
|
+
console.log({isValid, formValues});
|
26
|
+
|
27
|
+
await me.updateRecordValidityState()
|
28
|
+
}
|
29
|
+
|
30
|
+
/**
|
31
|
+
* @param {Object} data
|
32
|
+
*/
|
33
|
+
async onValidatePageButtonClick(data) {
|
34
|
+
let me = this,
|
35
|
+
activeIndex = me.getModel().data.activeIndex,
|
36
|
+
activeCard = me.getReference('pages-container').items[activeIndex],
|
37
|
+
formValues = await activeCard.getValues();
|
38
|
+
|
39
|
+
await activeCard.validate();
|
40
|
+
await me.updateRecordValidityState(activeIndex)
|
41
|
+
|
42
|
+
console.log(`Current page: ${activeIndex + 1}`, formValues);
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Not passing a pageIndex validates all pages
|
47
|
+
* @param {Number|null} [pageIndex]
|
48
|
+
* @returns {Promise<void>}
|
49
|
+
*/
|
50
|
+
async updateRecordValidityState(pageIndex=null) {
|
20
51
|
let me = this,
|
21
52
|
model = me.getModel(),
|
22
|
-
activeIndex = model.data.activeIndex,
|
23
53
|
pagesContainer = me.getReference('pages-container'),
|
54
|
+
sideNav = me.getReference('side-nav'),
|
24
55
|
store = model.getStore('sideNav'),
|
25
|
-
|
26
|
-
|
27
|
-
isValid
|
56
|
+
i = 0,
|
57
|
+
len = pagesContainer.items.length,
|
58
|
+
isValid, listIndex, page;
|
59
|
+
|
60
|
+
if (Neo.isNumber(pageIndex)) {
|
61
|
+
i = pageIndex;
|
62
|
+
len = pageIndex + 1;
|
63
|
+
}
|
28
64
|
|
29
|
-
|
65
|
+
for (; i < len; i++) {
|
66
|
+
page = pagesContainer.items[i];
|
67
|
+
listIndex = sideNav.getActiveIndex(i);
|
68
|
+
isValid = await page.isValid();
|
30
69
|
|
31
|
-
|
70
|
+
store.getAt(listIndex).isValid = isValid;
|
71
|
+
}
|
32
72
|
}
|
33
73
|
}
|
34
74
|
|
package/package.json
CHANGED
package/src/DefaultConfig.mjs
CHANGED
@@ -237,12 +237,12 @@ const DefaultConfig = {
|
|
237
237
|
useVdomWorker: true,
|
238
238
|
/**
|
239
239
|
* buildScripts/injectPackageVersion.mjs will update this value
|
240
|
-
* @default '5.
|
240
|
+
* @default '5.2.0'
|
241
241
|
* @memberOf! module:Neo
|
242
242
|
* @name config.version
|
243
243
|
* @type String
|
244
244
|
*/
|
245
|
-
version: '5.
|
245
|
+
version: '5.2.0'
|
246
246
|
};
|
247
247
|
|
248
248
|
Object.assign(DefaultConfig, {
|
package/src/form/Container.mjs
CHANGED
@@ -31,11 +31,30 @@ class Container extends BaseContainer {
|
|
31
31
|
}
|
32
32
|
|
33
33
|
/**
|
34
|
-
*
|
34
|
+
* @param {Neo.container.Base} parent
|
35
|
+
* @param {Object[]} modules
|
36
|
+
* @returns {Object[]}
|
37
|
+
*/
|
38
|
+
findNotLoadedModules(parent=this, modules=[]) {
|
39
|
+
parent.items.forEach(item => {
|
40
|
+
if (Neo.typeOf(item.module) === 'Function' && !item.isLoading) {
|
41
|
+
modules.push({item, parent});
|
42
|
+
} else {
|
43
|
+
item.items && this.findNotLoadedModules(item, modules);
|
44
|
+
}
|
45
|
+
});
|
46
|
+
|
47
|
+
return modules;
|
48
|
+
}
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Either pass a field name or id
|
35
52
|
* @param {String} name
|
36
|
-
* @returns {Neo.form.field.Base|null} fields
|
53
|
+
* @returns {Promise<Neo.form.field.Base|null>} fields
|
37
54
|
*/
|
38
|
-
getField(name) {
|
55
|
+
async getField(name) {
|
56
|
+
await this.loadModules();
|
57
|
+
|
39
58
|
let fields = ComponentManager.getChildComponents(this),
|
40
59
|
field;
|
41
60
|
|
@@ -51,11 +70,13 @@ class Container extends BaseContainer {
|
|
51
70
|
}
|
52
71
|
|
53
72
|
/**
|
54
|
-
* @returns {Neo.form.field.Base[]} fields
|
73
|
+
* @returns {Promise<Neo.form.field.Base[]>} fields
|
55
74
|
*/
|
56
|
-
getFields() {
|
75
|
+
async getFields() {
|
57
76
|
let fields = [];
|
58
77
|
|
78
|
+
await this.loadModules();
|
79
|
+
|
59
80
|
ComponentManager.getChildComponents(this).forEach(item => {
|
60
81
|
item instanceof BaseField && fields.push(item);
|
61
82
|
});
|
@@ -64,12 +85,13 @@ class Container extends BaseContainer {
|
|
64
85
|
}
|
65
86
|
|
66
87
|
/**
|
67
|
-
* @returns {Object}
|
88
|
+
* @returns {Promise<Object>}
|
68
89
|
*/
|
69
|
-
getSubmitValues() {
|
70
|
-
let
|
90
|
+
async getSubmitValues() {
|
91
|
+
let fields = await this.getFields(),
|
92
|
+
values = {};
|
71
93
|
|
72
|
-
|
94
|
+
fields.forEach(item => {
|
73
95
|
values[item.name || item.id] = item.getSubmitValue();
|
74
96
|
});
|
75
97
|
|
@@ -77,12 +99,13 @@ class Container extends BaseContainer {
|
|
77
99
|
}
|
78
100
|
|
79
101
|
/**
|
80
|
-
* @returns {Object}
|
102
|
+
* @returns {Promise<Object>}
|
81
103
|
*/
|
82
|
-
getValues() {
|
83
|
-
let
|
104
|
+
async getValues() {
|
105
|
+
let fields = await this.getFields(),
|
106
|
+
values = {};
|
84
107
|
|
85
|
-
|
108
|
+
fields.forEach(item => {
|
86
109
|
values[item.name || item.id] = item.value;
|
87
110
|
});
|
88
111
|
|
@@ -91,10 +114,10 @@ class Container extends BaseContainer {
|
|
91
114
|
|
92
115
|
/**
|
93
116
|
* Returns true in case no form field isValid() call returns false
|
94
|
-
* @returns {Boolean}
|
117
|
+
* @returns {Promise<Boolean>}
|
95
118
|
*/
|
96
|
-
isValid() {
|
97
|
-
let fields = this.getFields(),
|
119
|
+
async isValid() {
|
120
|
+
let fields = await this.getFields(),
|
98
121
|
i = 0,
|
99
122
|
len = fields.length;
|
100
123
|
|
@@ -107,16 +130,35 @@ class Container extends BaseContainer {
|
|
107
130
|
return true;
|
108
131
|
}
|
109
132
|
|
133
|
+
/**
|
134
|
+
* Loads all not loaded items inside card layouts
|
135
|
+
* @returns {Promise<Neo.component.Base[]>}
|
136
|
+
*/
|
137
|
+
async loadModules() {
|
138
|
+
let me = this,
|
139
|
+
modules = me.findNotLoadedModules(),
|
140
|
+
promises = [];
|
141
|
+
|
142
|
+
modules.forEach(module => {
|
143
|
+
promises.push(module.parent.layout.loadModule(module.item));
|
144
|
+
});
|
145
|
+
|
146
|
+
modules = await Promise.all(promises);
|
147
|
+
|
148
|
+
return modules;
|
149
|
+
}
|
150
|
+
|
110
151
|
/**
|
111
152
|
* Resets field values by field name or field id.
|
112
153
|
* Fields not included with a value will get reset to null.
|
113
154
|
* @param {Object} [values]
|
114
155
|
*/
|
115
|
-
reset(values={}) {
|
116
|
-
let keys
|
156
|
+
async reset(values={}) {
|
157
|
+
let keys = values ? Object.keys(values) : [],
|
158
|
+
fields = await this.getFields(),
|
117
159
|
index;
|
118
160
|
|
119
|
-
|
161
|
+
fields.forEach(item => {
|
120
162
|
index = keys.indexOf(item.name);
|
121
163
|
|
122
164
|
if (index < 0) {
|
@@ -124,18 +166,19 @@ class Container extends BaseContainer {
|
|
124
166
|
}
|
125
167
|
|
126
168
|
item.reset(index > -1 ? values[keys[index]] : null);
|
127
|
-
})
|
169
|
+
})
|
128
170
|
}
|
129
171
|
|
130
172
|
/**
|
131
173
|
* Set field values by field name or field id
|
132
174
|
* @param {Object} values={}
|
133
175
|
*/
|
134
|
-
setValues(values={}) {
|
135
|
-
let keys
|
176
|
+
async setValues(values={}) {
|
177
|
+
let keys = Object.keys(values),
|
178
|
+
fields = await this.getFields(),
|
136
179
|
index;
|
137
180
|
|
138
|
-
|
181
|
+
fields.forEach(item => {
|
139
182
|
index = keys.indexOf(item.name);
|
140
183
|
|
141
184
|
if (index < 0) {
|
@@ -145,20 +188,28 @@ class Container extends BaseContainer {
|
|
145
188
|
if (index > -1) {
|
146
189
|
item.value = values[keys[index]];
|
147
190
|
}
|
148
|
-
})
|
191
|
+
})
|
149
192
|
}
|
150
193
|
|
151
194
|
/**
|
152
|
-
* Updates the invalid state for all fields
|
153
|
-
* This can be useful for create
|
154
|
-
* @returns {Boolean}
|
195
|
+
* Updates the invalid state for all fields which have validate() implemented.
|
196
|
+
* This can be useful for create-entity forms which show up "clean" until pressing a submit button.
|
197
|
+
* @returns {Promise<Boolean>}
|
155
198
|
*/
|
156
|
-
validate() {
|
157
|
-
|
158
|
-
|
199
|
+
async validate() {
|
200
|
+
let isValid = true,
|
201
|
+
fields = await this.getFields(),
|
202
|
+
validField;
|
203
|
+
|
204
|
+
fields.forEach(item => {
|
205
|
+
validField = item.validate?.(false);
|
206
|
+
|
207
|
+
if (!validField) {
|
208
|
+
isValid = false;
|
209
|
+
}
|
159
210
|
});
|
160
211
|
|
161
|
-
return
|
212
|
+
return isValid;
|
162
213
|
}
|
163
214
|
}
|
164
215
|
|
package/src/form/field/Text.mjs
CHANGED
@@ -570,7 +570,7 @@ class Text extends Base {
|
|
570
570
|
|
571
571
|
me.validate(); // silent
|
572
572
|
me.changeInputElKey('required', value ? value : null, true); // silent update
|
573
|
-
me.labelText = me.labelText;
|
573
|
+
me.labelText = me.labelText; // triggers a vdom update
|
574
574
|
}
|
575
575
|
|
576
576
|
/**
|
@@ -786,8 +786,10 @@ class Text extends Base {
|
|
786
786
|
labelOptionalText = me.labelOptionalText,
|
787
787
|
hasOptionalText = value.endsWith(labelOptionalText);
|
788
788
|
|
789
|
-
if (me.showOptionalText && !me.required
|
790
|
-
|
789
|
+
if (me.showOptionalText && !me.required) {
|
790
|
+
if (!hasOptionalText) {
|
791
|
+
value += labelOptionalText;
|
792
|
+
}
|
791
793
|
} else if (value && hasOptionalText) {
|
792
794
|
value = value.replace(labelOptionalText, '');
|
793
795
|
}
|
@@ -1086,11 +1088,13 @@ class Text extends Base {
|
|
1086
1088
|
onFocusLeave(data) {
|
1087
1089
|
let me = this,
|
1088
1090
|
centerBorderEl = me.getCenterBorderEl(), // labelPosition: 'inline'
|
1089
|
-
cls
|
1091
|
+
cls;
|
1090
1092
|
|
1091
1093
|
if (!me.readOnly) {
|
1092
1094
|
me.validate(); // silent
|
1093
1095
|
|
1096
|
+
cls = me.cls; // has to get set after validate()
|
1097
|
+
|
1094
1098
|
NeoArray.remove(cls, 'neo-focus');
|
1095
1099
|
me.cls = cls;
|
1096
1100
|
|
package/src/layout/Card.mjs
CHANGED
@@ -65,11 +65,10 @@ class Card extends Base {
|
|
65
65
|
sCfg = me.constructor,
|
66
66
|
needsUpdate = false,
|
67
67
|
removeInactiveCards = me.removeInactiveCards,
|
68
|
-
i, isActiveIndex, item, items, len, module,
|
68
|
+
i, isActiveIndex, item, items, len, module, wrapperCls;
|
69
69
|
|
70
70
|
if (Neo.isNumber(value) && container) {
|
71
71
|
items = container.items;
|
72
|
-
vdom = container.vdom;
|
73
72
|
len = items.length;
|
74
73
|
|
75
74
|
if (!items[value]) {
|
@@ -80,7 +79,7 @@ class Card extends Base {
|
|
80
79
|
for (i=0; i < len; i++) {
|
81
80
|
module = items[i].module;
|
82
81
|
|
83
|
-
if (i === value &&
|
82
|
+
if (i === value && Neo.typeOf(module) === 'Function') {
|
84
83
|
needsUpdate = true;
|
85
84
|
break;
|
86
85
|
}
|
@@ -91,23 +90,8 @@ class Card extends Base {
|
|
91
90
|
item = items[i];
|
92
91
|
module = item.module;
|
93
92
|
|
94
|
-
if (isActiveIndex &&
|
95
|
-
|
96
|
-
module = module.default;
|
97
|
-
proto = module.prototype;
|
98
|
-
wrapperCls = item.wrapperCls || proto.constructor.config.wrapperCls || [];
|
99
|
-
|
100
|
-
item.className = proto.className;
|
101
|
-
item.wrapperCls = [...wrapperCls, sCfg.itemCls];
|
102
|
-
item.module = module;
|
103
|
-
|
104
|
-
delete item.vdom;
|
105
|
-
|
106
|
-
items[i] = item = Neo.create(item);
|
107
|
-
|
108
|
-
container.fire('cardLoaded', {item});
|
109
|
-
|
110
|
-
vdom.cn[i] = item.vdom;
|
93
|
+
if (isActiveIndex && Neo.typeOf(module) === 'Function') {
|
94
|
+
item = await me.loadModule(item, i);
|
111
95
|
}
|
112
96
|
|
113
97
|
if (item instanceof Neo.core.Base) {
|
@@ -180,6 +164,53 @@ class Card extends Base {
|
|
180
164
|
container.wrapperCls = wrapperCls;
|
181
165
|
}
|
182
166
|
|
167
|
+
/**
|
168
|
+
* Loads a component.Base module which is defined via module: () => import('...')
|
169
|
+
* @param {Object} item
|
170
|
+
* @param {Number} [index]
|
171
|
+
* @returns {Neo.component.Base}
|
172
|
+
*/
|
173
|
+
async loadModule(item, index) {
|
174
|
+
let me = this,
|
175
|
+
containerId = me.containerId,
|
176
|
+
container = Neo.getComponent(containerId) || Neo.get(containerId), // the instance might not be registered yet
|
177
|
+
items = container.items,
|
178
|
+
sCfg = me.constructor,
|
179
|
+
vdom = container.vdom,
|
180
|
+
module = item.module,
|
181
|
+
proto, wrapperCls;
|
182
|
+
|
183
|
+
if (!Neo.isNumber(index)) {
|
184
|
+
index = items.indexOf(item);
|
185
|
+
}
|
186
|
+
|
187
|
+
item.isLoading = true; // prevent the item from getting queued multiple times inside form.Container
|
188
|
+
|
189
|
+
module = await module();
|
190
|
+
module = module.default;
|
191
|
+
proto = module.prototype;
|
192
|
+
wrapperCls = item.wrapperCls || proto.constructor.config.wrapperCls || [];
|
193
|
+
|
194
|
+
item.className = proto.className;
|
195
|
+
item.wrapperCls = [...wrapperCls, sCfg.itemCls];
|
196
|
+
item.module = module;
|
197
|
+
|
198
|
+
delete item.isLoading;
|
199
|
+
delete item.vdom;
|
200
|
+
|
201
|
+
items[index] = item = Neo.create(item);
|
202
|
+
|
203
|
+
if (me.removeInactiveCards) {
|
204
|
+
item.vdom.removeDom = true;
|
205
|
+
}
|
206
|
+
|
207
|
+
container.fire('cardLoaded', {item});
|
208
|
+
|
209
|
+
vdom.cn[index] = item.vdom;
|
210
|
+
|
211
|
+
return item;
|
212
|
+
}
|
213
|
+
|
183
214
|
/**
|
184
215
|
* Removes all CSS rules from the container this layout is bound to.
|
185
216
|
* Gets called when switching to a different layout.
|