@jinntec/fore 0.25.0 → 1.0.0-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/README.md +75 -22
- package/dist/fore-all.js +11 -11
- package/dist/fore.js +1 -1
- package/index.js +5 -1
- package/package.json +17 -6
- package/resources/fore.css +121 -4
- package/resources/toastify.css +3 -1
- package/src/DependencyNotifyingDomFacade.js +9 -1
- package/src/ForeElementMixin.js +83 -12
- package/src/actions/abstract-action.js +101 -27
- package/src/actions/fx-action.js +4 -2
- package/src/actions/fx-append.js +21 -18
- package/src/actions/fx-confirm.js +22 -0
- package/src/actions/fx-dispatch.js +10 -2
- package/src/actions/fx-insert.js +35 -30
- package/src/actions/fx-message.js +7 -1
- package/src/actions/fx-send.js +1 -1
- package/src/actions/fx-setvalue.js +2 -9
- package/src/dep_graph.js +9 -0
- package/src/drawdown.js +172 -0
- package/src/fore.js +126 -18
- package/src/functions/fx-function.js +2 -2
- package/src/fx-bind.js +11 -7
- package/src/fx-fore.js +283 -67
- package/src/fx-header.js +20 -0
- package/src/fx-instance.js +54 -10
- package/src/fx-model.js +175 -38
- package/src/fx-submission.js +235 -53
- package/src/getInScopeContext.js +2 -3
- package/src/ui/abstract-control.js +23 -44
- package/src/ui/fx-alert.js +20 -19
- package/src/ui/fx-container.js +9 -4
- package/src/ui/fx-control.js +92 -37
- package/src/ui/fx-inspector.js +44 -0
- package/src/ui/fx-items.js +104 -20
- package/src/ui/fx-output.js +92 -3
- package/src/ui/fx-repeat.js +87 -80
- package/src/ui/fx-repeatitem.js +38 -48
- package/src/ui/fx-trigger.js +49 -27
- package/src/xpath-evaluation.js +533 -235
- package/src/xpath-util.js +50 -12
package/src/fx-submission.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { Fore } from './fore.js';
|
|
1
2
|
import { foreElementMixin } from './ForeElementMixin.js';
|
|
2
|
-
import { evaluateXPathToString } from './xpath-evaluation.js';
|
|
3
|
+
import { evaluateXPathToString, evaluateXPath } from './xpath-evaluation.js';
|
|
3
4
|
import getInScopeContext from './getInScopeContext.js';
|
|
4
5
|
|
|
6
|
+
/**
|
|
7
|
+
* todo: validate='false'
|
|
8
|
+
*/
|
|
5
9
|
export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
6
10
|
constructor() {
|
|
7
11
|
super();
|
|
@@ -9,16 +13,22 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
9
13
|
}
|
|
10
14
|
|
|
11
15
|
connectedCallback() {
|
|
12
|
-
this.style.display = 'none';
|
|
16
|
+
// this.style.display = 'none';
|
|
17
|
+
this.methods = ['get', 'put', 'post', 'delete', 'head', 'urlencoded-post'];
|
|
18
|
+
|
|
13
19
|
this.model = this.parentNode;
|
|
14
20
|
|
|
15
21
|
// ### initialize properties with defaults
|
|
16
|
-
if (!this.hasAttribute('id')) throw new Error('id is required');
|
|
22
|
+
// if (!this.hasAttribute('id')) throw new Error('id is required');
|
|
23
|
+
if (!this.hasAttribute('id')) console.warn('id is required');
|
|
17
24
|
this.id = this.getAttribute('id');
|
|
18
25
|
|
|
19
26
|
/** if present should be a existing instance id */
|
|
20
27
|
this.instance = this.hasAttribute('instance') ? this.getAttribute('instance') : null;
|
|
21
28
|
|
|
29
|
+
/** if present will determine XPath where to insert a response into when mode is 'replace' */
|
|
30
|
+
this.into = this.hasAttribute('into') ? this.getAttribute('into') : null;
|
|
31
|
+
|
|
22
32
|
/** http method */
|
|
23
33
|
this.method = this.hasAttribute('method') ? this.getAttribute('method') : 'get';
|
|
24
34
|
|
|
@@ -30,7 +40,12 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
30
40
|
/** replace might be 'all', 'instance' or 'none' */
|
|
31
41
|
this.replace = this.hasAttribute('replace') ? this.getAttribute('replace') : 'all';
|
|
32
42
|
|
|
33
|
-
|
|
43
|
+
this.serialization = this.hasAttribute('serialization')
|
|
44
|
+
? this.getAttribute('serialization')
|
|
45
|
+
: 'xml';
|
|
46
|
+
|
|
47
|
+
// if (!this.hasAttribute('url')) throw new Error(`url is required for submission: ${this.id}`);
|
|
48
|
+
if (!this.hasAttribute('url')) console.warn(`url is required for submission: ${this.id}`);
|
|
34
49
|
this.url = this.getAttribute('url');
|
|
35
50
|
|
|
36
51
|
this.targetref = this.hasAttribute('targetref') ? this.getAttribute('targetref') : null;
|
|
@@ -40,10 +55,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
40
55
|
: 'application/xml';
|
|
41
56
|
|
|
42
57
|
this.validate = this.getAttribute('validate') ? this.getAttribute('validate') : 'true';
|
|
43
|
-
|
|
44
58
|
this.shadowRoot.innerHTML = this.renderHTML();
|
|
45
|
-
|
|
46
|
-
this.addEventListener('submit', () => this._submit());
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
// eslint-disable-next-line class-methods-use-this
|
|
@@ -53,17 +65,12 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
53
65
|
`;
|
|
54
66
|
}
|
|
55
67
|
|
|
56
|
-
submit() {
|
|
57
|
-
this.
|
|
58
|
-
|
|
59
|
-
composed: true,
|
|
60
|
-
bubbles: true,
|
|
61
|
-
detail: {},
|
|
62
|
-
}),
|
|
63
|
-
);
|
|
68
|
+
async submit() {
|
|
69
|
+
await this.dispatch('submit', { submission: this });
|
|
70
|
+
this._submit();
|
|
64
71
|
}
|
|
65
72
|
|
|
66
|
-
_submit() {
|
|
73
|
+
async _submit() {
|
|
67
74
|
console.log('submitting....');
|
|
68
75
|
this.evalInContext();
|
|
69
76
|
const model = this.getModel();
|
|
@@ -73,11 +80,12 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
73
80
|
if (this.validate) {
|
|
74
81
|
const valid = model.revalidate();
|
|
75
82
|
if (!valid) {
|
|
83
|
+
console.log('validation failed. Bubmission stopped');
|
|
76
84
|
return;
|
|
77
85
|
}
|
|
78
86
|
}
|
|
79
|
-
|
|
80
|
-
this._serializeAndSend();
|
|
87
|
+
console.log('model updated....');
|
|
88
|
+
await this._serializeAndSend();
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
/**
|
|
@@ -96,7 +104,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
96
104
|
const inscope = getInScopeContext(node, naked);
|
|
97
105
|
const result = evaluateXPathToString(naked, inscope, this.getOwnerForm());
|
|
98
106
|
const replaced = expr.replaceAll(match, result);
|
|
99
|
-
console.log('
|
|
107
|
+
console.log('replacing ', expr, ' with ', replaced);
|
|
100
108
|
expr = replaced;
|
|
101
109
|
});
|
|
102
110
|
}
|
|
@@ -111,34 +119,74 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
111
119
|
*/
|
|
112
120
|
async _serializeAndSend() {
|
|
113
121
|
const resolvedUrl = this._evaluateAttributeTemplateExpression(this.url, this);
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
|
|
123
|
+
const instance = this.getInstance();
|
|
124
|
+
if (instance.type !== 'xml') {
|
|
125
|
+
console.error('JSON serialization is not supported yet');
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// let serialized = serializer.serializeToString(this.nodeset);
|
|
130
|
+
let serialized;
|
|
131
|
+
if (this.serialization === 'none') {
|
|
132
|
+
serialized = undefined;
|
|
133
|
+
} else {
|
|
134
|
+
const relevant = this.selectRelevant();
|
|
135
|
+
serialized = this._serialize(instance.type, relevant);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// let serialized = serializer.serializeToString(relevant);
|
|
116
139
|
if (this.method.toLowerCase() === 'get') {
|
|
117
140
|
serialized = undefined;
|
|
118
141
|
}
|
|
142
|
+
// console.log('data being send', serialized);
|
|
143
|
+
// console.log('submitting data',serialized);
|
|
144
|
+
|
|
145
|
+
if (resolvedUrl === '#echo') {
|
|
146
|
+
let doc;
|
|
147
|
+
if (serialized) {
|
|
148
|
+
doc = new DOMParser().parseFromString(serialized, 'application/xml');
|
|
149
|
+
} else {
|
|
150
|
+
doc = undefined;
|
|
151
|
+
}
|
|
152
|
+
// const doc = new DOMParser().parseFromString(serialized, 'application/xml');
|
|
153
|
+
// const newDoc = doc.replaceChild(relevant, doc.firstElementChild);
|
|
154
|
+
this._handleResponse(doc);
|
|
155
|
+
this.dispatch('submit-done', {});
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// ### setting headers
|
|
159
|
+
const headers = this._getHeaders();
|
|
160
|
+
console.log('headers', headers);
|
|
161
|
+
|
|
162
|
+
// ### map urlencoded-post to post for fetch
|
|
163
|
+
if (this.method === 'urlencoded-post') {
|
|
164
|
+
this.method = 'post';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (!this.methods.includes(this.method.toLowerCase())) {
|
|
168
|
+
this.dispatch('error', { message: `Unknown method ${this.method}` });
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
119
171
|
const response = await fetch(resolvedUrl, {
|
|
120
172
|
method: this.method,
|
|
121
173
|
mode: 'cors',
|
|
122
|
-
credentials: '
|
|
123
|
-
headers
|
|
124
|
-
'Content-type': 'application/xml; charset=UTF-8',
|
|
125
|
-
},
|
|
174
|
+
credentials: 'include',
|
|
175
|
+
headers,
|
|
126
176
|
body: serialized,
|
|
127
177
|
});
|
|
128
178
|
|
|
129
|
-
if (!response.ok) {
|
|
130
|
-
this.
|
|
131
|
-
|
|
132
|
-
composed: true,
|
|
133
|
-
bubbles: true,
|
|
134
|
-
detail: { message: `Error while submitting ${this.id}` },
|
|
135
|
-
}),
|
|
136
|
-
);
|
|
179
|
+
if (!response.ok || response.status > 400) {
|
|
180
|
+
this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
|
|
181
|
+
return;
|
|
137
182
|
}
|
|
138
183
|
|
|
139
184
|
const contentType = response.headers.get('content-type').toLowerCase();
|
|
140
|
-
|
|
141
|
-
|
|
185
|
+
if (
|
|
186
|
+
contentType.startsWith('text/plain') ||
|
|
187
|
+
contentType.startsWith('text/html') ||
|
|
188
|
+
contentType.startsWith('text/markdown')
|
|
189
|
+
) {
|
|
142
190
|
const text = await response.text();
|
|
143
191
|
this._handleResponse(text);
|
|
144
192
|
} else if (contentType.startsWith('application/json')) {
|
|
@@ -152,6 +200,53 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
152
200
|
const blob = await response.blob();
|
|
153
201
|
this._handleResponse(blob);
|
|
154
202
|
}
|
|
203
|
+
|
|
204
|
+
this.dispatch('submit-done', {});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
_serialize(instanceType, relevantNodes) {
|
|
208
|
+
if (this.method === 'urlencoded-post') {
|
|
209
|
+
// this.method = 'post';
|
|
210
|
+
const params = new URLSearchParams();
|
|
211
|
+
// console.log('nodes to serialize', relevantNodes);
|
|
212
|
+
Array.from(relevantNodes.children).forEach(child => {
|
|
213
|
+
params.append(child.nodeName, child.textContent);
|
|
214
|
+
});
|
|
215
|
+
return params;
|
|
216
|
+
}
|
|
217
|
+
if (instanceType === 'xml') {
|
|
218
|
+
const serializer = new XMLSerializer();
|
|
219
|
+
return serializer.serializeToString(relevantNodes);
|
|
220
|
+
}
|
|
221
|
+
/*
|
|
222
|
+
if(instanceType === 'json'){
|
|
223
|
+
console.warn('JSON serialization is not yet supported')
|
|
224
|
+
}
|
|
225
|
+
*/
|
|
226
|
+
throw new Error('unknown instance type ', instanceType);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
_getHeaders() {
|
|
230
|
+
const headers = new Headers();
|
|
231
|
+
|
|
232
|
+
// ### set content-type header according to type of instance
|
|
233
|
+
const instance = this.getInstance();
|
|
234
|
+
const contentType = Fore.getContentType(instance, this.method);
|
|
235
|
+
headers.append('Content-Type', contentType);
|
|
236
|
+
// ### needed to overwrite browsers' setting of 'Accept' header
|
|
237
|
+
if (headers.has('Accept')) {
|
|
238
|
+
headers.delete('Accept');
|
|
239
|
+
}
|
|
240
|
+
// headers.append('Accept', 'application/xml');
|
|
241
|
+
|
|
242
|
+
// ### add header defined by fx-header elements
|
|
243
|
+
const headerElems = this.querySelectorAll('fx-header');
|
|
244
|
+
Array.from(headerElems).forEach(header => {
|
|
245
|
+
const { name } = header;
|
|
246
|
+
const val = header.getValue();
|
|
247
|
+
headers.append(name, val);
|
|
248
|
+
});
|
|
249
|
+
return headers;
|
|
155
250
|
}
|
|
156
251
|
|
|
157
252
|
_getUrlExpr() {
|
|
@@ -176,9 +271,31 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
176
271
|
if (this.replace === 'instance') {
|
|
177
272
|
const targetInstance = this._getTargetInstance();
|
|
178
273
|
if (targetInstance) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
274
|
+
if (this.targetref) {
|
|
275
|
+
const theTarget = evaluateXPath(
|
|
276
|
+
this.targetref,
|
|
277
|
+
targetInstance.instanceData.firstElementChild,
|
|
278
|
+
this,
|
|
279
|
+
);
|
|
280
|
+
console.log('theTarget', theTarget);
|
|
281
|
+
const clone = data.firstElementChild;
|
|
282
|
+
const parent = theTarget.parentNode;
|
|
283
|
+
parent.replaceChild(clone, theTarget);
|
|
284
|
+
console.log('finally ', parent);
|
|
285
|
+
} else if (this.into) {
|
|
286
|
+
const theTarget = evaluateXPath(
|
|
287
|
+
this.into,
|
|
288
|
+
targetInstance.instanceData.firstElementChild,
|
|
289
|
+
this,
|
|
290
|
+
);
|
|
291
|
+
console.log('theTarget', theTarget);
|
|
292
|
+
theTarget.innerHTML = data;
|
|
293
|
+
} else {
|
|
294
|
+
const instanceData = data;
|
|
295
|
+
targetInstance.instanceData = instanceData;
|
|
296
|
+
console.log('### replaced instance ', targetInstance.instanceData);
|
|
297
|
+
}
|
|
298
|
+
|
|
182
299
|
this.model.updateModel(); // force update
|
|
183
300
|
// this.model.formElement.refresh();
|
|
184
301
|
this.getOwnerForm().refresh();
|
|
@@ -199,24 +316,89 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
199
316
|
window.location.href = data;
|
|
200
317
|
}
|
|
201
318
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
319
|
+
/*
|
|
320
|
+
const event = new CustomEvent('submit-done', {
|
|
321
|
+
composed: true,
|
|
322
|
+
bubbles: true,
|
|
323
|
+
detail: {},
|
|
324
|
+
});
|
|
325
|
+
console.log('firing',event);
|
|
326
|
+
this.dispatchEvent(event);
|
|
327
|
+
*/
|
|
328
|
+
// this.dispatch('submit-done', {});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* select relevant nodes
|
|
333
|
+
*
|
|
334
|
+
* todo: support for 'empty'
|
|
335
|
+
* @returns {*}
|
|
336
|
+
*/
|
|
337
|
+
selectRelevant() {
|
|
338
|
+
// ### no relevance selection - current nodeset is used 'as-is'
|
|
339
|
+
if (this.nonrelevant === 'keep') {
|
|
340
|
+
return this.nodeset;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// first check if nodeset of submission is relevant - otherwise bail out
|
|
344
|
+
const mi = this.getModel().getModelItem(this.nodeset);
|
|
345
|
+
if (mi && !mi.relevant) return null;
|
|
346
|
+
|
|
347
|
+
const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
348
|
+
const root = doc.firstElementChild;
|
|
349
|
+
|
|
350
|
+
if (this.nodeset.children.length === 0 && this._isRelevant(this.nodeset)) {
|
|
351
|
+
return this.nodeset;
|
|
352
|
+
}
|
|
353
|
+
const result = this._filterRelevant(this.nodeset, root);
|
|
354
|
+
return result;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
_filterRelevant(node, result) {
|
|
358
|
+
const { childNodes } = node;
|
|
359
|
+
Array.from(childNodes).forEach(n => {
|
|
360
|
+
if (this._isRelevant(n)) {
|
|
361
|
+
const clone = n.cloneNode(false);
|
|
362
|
+
result.appendChild(clone);
|
|
363
|
+
const { attributes } = n;
|
|
364
|
+
if (attributes) {
|
|
365
|
+
Array.from(attributes).forEach(attr => {
|
|
366
|
+
if (this._isRelevant(attr)) {
|
|
367
|
+
clone.setAttribute(attr.nodeName, attr.value);
|
|
368
|
+
} else if (this.nonrelevant === 'empty') {
|
|
369
|
+
clone.setAttribute(attr.nodeName, '');
|
|
370
|
+
} else {
|
|
371
|
+
clone.removeAttribute(attr.nodeName);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
return this._filterRelevant(n, clone);
|
|
376
|
+
}
|
|
377
|
+
return null;
|
|
378
|
+
});
|
|
379
|
+
return result;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
_isRelevant(node) {
|
|
383
|
+
const mi = this.getModel().getModelItem(node);
|
|
384
|
+
if (!mi || mi.relevant) {
|
|
385
|
+
return true;
|
|
386
|
+
}
|
|
387
|
+
return false;
|
|
209
388
|
}
|
|
210
389
|
|
|
211
390
|
_handleError() {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
391
|
+
this.dispatch('submit-error', {});
|
|
392
|
+
/*
|
|
393
|
+
console.log('ERRRORRRRR');
|
|
394
|
+
this.dispatchEvent(
|
|
395
|
+
new CustomEvent('submit-error', {
|
|
396
|
+
composed: true,
|
|
397
|
+
bubbles: true,
|
|
398
|
+
detail: {},
|
|
399
|
+
}),
|
|
400
|
+
);
|
|
401
|
+
*/
|
|
220
402
|
}
|
|
221
403
|
}
|
|
222
404
|
|
package/src/getInScopeContext.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import { evaluateXPathToNodes, evaluateXPathToFirstNode } from './xpath-evaluation.js';
|
|
1
|
+
import { evaluateXPathToFirstNode } from './xpath-evaluation.js';
|
|
3
2
|
|
|
4
3
|
import { XPathUtil } from './xpath-util.js';
|
|
5
4
|
|
|
@@ -32,7 +31,7 @@ function _getInitialContext(node, ref) {
|
|
|
32
31
|
const instanceId = XPathUtil.getInstanceId(ref);
|
|
33
32
|
return model.getInstance(instanceId).getDefaultContext();
|
|
34
33
|
}
|
|
35
|
-
if (model.getDefaultInstance() !== null) {
|
|
34
|
+
if (model.getDefaultInstance() !== null && model.inited) {
|
|
36
35
|
return model.getDefaultInstance().getDefaultContext();
|
|
37
36
|
}
|
|
38
37
|
return [];
|
|
@@ -8,20 +8,6 @@ import { ModelItem } from '../modelitem.js';
|
|
|
8
8
|
*
|
|
9
9
|
*/
|
|
10
10
|
export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
11
|
-
/*
|
|
12
|
-
static get properties() {
|
|
13
|
-
return {
|
|
14
|
-
...super.properties,
|
|
15
|
-
value: {
|
|
16
|
-
type: String,
|
|
17
|
-
},
|
|
18
|
-
widget: {
|
|
19
|
-
type: Object,
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
11
|
constructor() {
|
|
26
12
|
super();
|
|
27
13
|
this.value = '';
|
|
@@ -34,14 +20,14 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
34
20
|
|
|
35
21
|
// eslint-disable-next-line class-methods-use-this
|
|
36
22
|
getWidget() {
|
|
37
|
-
throw new Error('You have to implement the method
|
|
23
|
+
throw new Error('You have to implement the method getWidget!');
|
|
38
24
|
}
|
|
39
25
|
|
|
40
26
|
/**
|
|
41
27
|
* (re)apply all modelItem state properties to this control. model -> UI
|
|
42
28
|
*/
|
|
43
|
-
async refresh() {
|
|
44
|
-
console.log('### AbstractControl.refresh on : ', this);
|
|
29
|
+
async refresh(force) {
|
|
30
|
+
// console.log('### AbstractControl.refresh on : ', this);
|
|
45
31
|
|
|
46
32
|
const currentVal = this.value;
|
|
47
33
|
|
|
@@ -76,29 +62,31 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
76
62
|
if (currentVal !== this.value) {
|
|
77
63
|
// console.log('dispatching value-changed for ', this);
|
|
78
64
|
// console.log('value-changed path ', this.modelItem.path);
|
|
79
|
-
this.
|
|
80
|
-
new CustomEvent('value-changed', {
|
|
81
|
-
composed: true,
|
|
82
|
-
bubbles: true,
|
|
83
|
-
detail: { path: this.modelItem.path },
|
|
84
|
-
}),
|
|
85
|
-
);
|
|
65
|
+
this.dispatch('value-changed', { path: this.modelItem.path });
|
|
86
66
|
}
|
|
87
67
|
// this.requestUpdate();
|
|
88
68
|
}
|
|
89
69
|
}
|
|
70
|
+
// Fore.refreshChildren(this,force);
|
|
90
71
|
// await this.updateComplete;
|
|
91
72
|
}
|
|
92
73
|
|
|
74
|
+
/**
|
|
75
|
+
*
|
|
76
|
+
* @returns {Promise<void>}
|
|
77
|
+
*/
|
|
93
78
|
// eslint-disable-next-line class-methods-use-this
|
|
94
79
|
async updateWidgetValue() {
|
|
95
80
|
throw new Error('You have to implement the method updateWidgetValue!');
|
|
96
81
|
}
|
|
97
82
|
|
|
98
83
|
handleModelItemProperties() {
|
|
84
|
+
// console.log('form ready', this.getOwnerForm().ready);
|
|
99
85
|
this.handleRequired();
|
|
100
86
|
this.handleReadonly();
|
|
101
|
-
this.
|
|
87
|
+
if (this.getOwnerForm().ready) {
|
|
88
|
+
this.handleValid();
|
|
89
|
+
}
|
|
102
90
|
this.handleRelevant();
|
|
103
91
|
}
|
|
104
92
|
|
|
@@ -108,7 +96,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
108
96
|
|
|
109
97
|
_dispatchEvent(event) {
|
|
110
98
|
if (this.getOwnerForm().ready) {
|
|
111
|
-
this.
|
|
99
|
+
this.dispatch(event, {});
|
|
112
100
|
}
|
|
113
101
|
}
|
|
114
102
|
|
|
@@ -121,21 +109,13 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
121
109
|
if (this.modelItem.required) {
|
|
122
110
|
this.widget.setAttribute('required', 'required');
|
|
123
111
|
this.classList.add('required');
|
|
124
|
-
// this.dispatchEvent(new CustomEvent('required', {}));
|
|
125
|
-
|
|
126
|
-
/*
|
|
127
|
-
if(this.getOwnerForm().ready){
|
|
128
|
-
this.dispatchEvent(new CustomEvent('required', {}));
|
|
129
|
-
}
|
|
130
|
-
*/
|
|
131
112
|
this._dispatchEvent('required');
|
|
132
113
|
} else {
|
|
133
114
|
this.widget.removeAttribute('required');
|
|
134
115
|
this.required = false;
|
|
135
116
|
// this.removeAttribute('required');
|
|
136
117
|
this.classList.toggle('required');
|
|
137
|
-
|
|
138
|
-
this.dispatchEvent(new CustomEvent('optional', {}));
|
|
118
|
+
this._dispatchEvent('optional');
|
|
139
119
|
}
|
|
140
120
|
}
|
|
141
121
|
}
|
|
@@ -147,15 +127,13 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
147
127
|
this.widget.setAttribute('readonly', 'readonly');
|
|
148
128
|
// this.setAttribute('readonly','readonly');
|
|
149
129
|
this.classList.toggle('readonly');
|
|
150
|
-
// this.dispatchEvent(new CustomEvent('readonly', {}));
|
|
151
130
|
this._dispatchEvent('readonly');
|
|
152
131
|
}
|
|
153
132
|
if (!this.modelItem.readonly) {
|
|
154
133
|
this.widget.removeAttribute('readonly');
|
|
155
134
|
// this.removeAttribute('readonly');
|
|
156
135
|
this.classList.toggle('readonly');
|
|
157
|
-
|
|
158
|
-
this.dispatchEvent(new CustomEvent('readwrite', {}));
|
|
136
|
+
this._dispatchEvent('readwrite');
|
|
159
137
|
}
|
|
160
138
|
}
|
|
161
139
|
}
|
|
@@ -168,8 +146,8 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
168
146
|
if (this.isValid() !== this.modelItem.constraint) {
|
|
169
147
|
if (this.modelItem.constraint) {
|
|
170
148
|
this.classList.remove('invalid');
|
|
171
|
-
alert.style.display = 'none';
|
|
172
|
-
this.
|
|
149
|
+
if (alert) alert.style.display = 'none';
|
|
150
|
+
this._dispatchEvent('valid');
|
|
173
151
|
} else {
|
|
174
152
|
// ### constraint is invalid - handle alerts
|
|
175
153
|
this.classList.add('invalid');
|
|
@@ -201,12 +179,13 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
201
179
|
// console.log('mip valid', this.modelItem.enabled);
|
|
202
180
|
if (this.isEnabled() !== this.modelItem.relevant) {
|
|
203
181
|
if (this.modelItem.relevant) {
|
|
204
|
-
this.
|
|
205
|
-
this._fadeIn(this, this.display);
|
|
182
|
+
this._dispatchEvent('relevant');
|
|
183
|
+
// this._fadeIn(this, this.display);
|
|
184
|
+
this.style.display = this.display;
|
|
206
185
|
} else {
|
|
207
|
-
// this.dispatchEvent(new CustomEvent('nonrelevant', {}));
|
|
208
186
|
this._dispatchEvent('nonrelevant');
|
|
209
|
-
this._fadeOut(this);
|
|
187
|
+
// this._fadeOut(this);
|
|
188
|
+
this.style.display = 'none';
|
|
210
189
|
}
|
|
211
190
|
}
|
|
212
191
|
}
|
package/src/ui/fx-alert.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import AbstractControl from './abstract-control.js';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export class FxAlert extends AbstractControl {
|
|
4
|
+
constructor() {
|
|
5
|
+
super();
|
|
6
|
+
this.attachShadow({ mode: 'open' });
|
|
7
|
+
}
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
return css`
|
|
9
|
+
connectedCallback() {
|
|
10
|
+
const style = `
|
|
8
11
|
:host {
|
|
9
|
-
display: block;
|
|
10
12
|
height: auto;
|
|
11
13
|
font-size: 0.8em;
|
|
12
14
|
font-weight: 400;
|
|
@@ -14,23 +16,22 @@ export class FxAlert extends XfAbstractControl {
|
|
|
14
16
|
display: none;
|
|
15
17
|
}
|
|
16
18
|
`;
|
|
17
|
-
}
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
20
|
+
const html = `
|
|
21
|
+
<slot></slot>
|
|
22
|
+
`;
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
this.shadowRoot.innerHTML = `
|
|
25
|
+
<style>
|
|
26
|
+
${style}
|
|
27
|
+
</style>
|
|
28
|
+
${html}
|
|
29
|
+
`;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
`;
|
|
32
|
+
async updateWidgetValue() {
|
|
33
|
+
console.log('alert update', this);
|
|
34
|
+
this.innerHTML = this.value;
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
customElements.define('fx-alert', FxAlert);
|
package/src/ui/fx-container.js
CHANGED
|
@@ -30,18 +30,21 @@ export class FxContainer extends foreElementMixin(HTMLElement) {
|
|
|
30
30
|
</style>
|
|
31
31
|
${html}
|
|
32
32
|
`;
|
|
33
|
+
|
|
34
|
+
this.getOwnerForm().registerLazyElement(this);
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
/**
|
|
36
38
|
* (re)apply all state properties to this control.
|
|
37
39
|
*/
|
|
38
|
-
refresh() {
|
|
39
|
-
|
|
40
|
+
refresh(force) {
|
|
41
|
+
if (!force && this.hasAttribute('refresh-on-view')) return;
|
|
42
|
+
// console.log('### FxContainer.refresh on : ', this);
|
|
40
43
|
|
|
41
44
|
if (this.isBound()) {
|
|
42
45
|
this.evalInContext();
|
|
43
46
|
this.modelItem = this.getModelItem();
|
|
44
|
-
this.value = this.modelItem.value;
|
|
47
|
+
// this.value = this.modelItem.value;
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
// await this.updateComplete;
|
|
@@ -50,7 +53,7 @@ export class FxContainer extends foreElementMixin(HTMLElement) {
|
|
|
50
53
|
if (this._getForm().ready) {
|
|
51
54
|
this.handleModelItemProperties();
|
|
52
55
|
}
|
|
53
|
-
Fore.refreshChildren(this);
|
|
56
|
+
Fore.refreshChildren(this, force);
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
handleModelItemProperties() {
|
|
@@ -78,6 +81,8 @@ export class FxContainer extends foreElementMixin(HTMLElement) {
|
|
|
78
81
|
|
|
79
82
|
handleRelevant() {
|
|
80
83
|
// console.log('mip valid', this.modelItem.enabled);
|
|
84
|
+
if (!this.modelItem) return;
|
|
85
|
+
|
|
81
86
|
if (this.isEnabled() !== this.modelItem.enabled) {
|
|
82
87
|
if (this.modelItem.enabled) {
|
|
83
88
|
this.dispatchEvent(new CustomEvent('enabled', {}));
|