@jinntec/fore 1.0.0-3 → 1.0.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/README.md +25 -34
- package/dist/fore-dev.js +43 -0
- package/dist/fore-dev.js.map +1 -0
- package/dist/fore.js +36 -1
- package/dist/fore.js.map +1 -0
- package/index.js +3 -0
- package/package.json +34 -38
- package/resources/fore.css +35 -50
- package/src/DependencyNotifyingDomFacade.js +10 -16
- package/src/ForeElementMixin.js +25 -18
- package/src/actions/abstract-action.js +17 -9
- package/src/actions/fx-action.js +6 -4
- package/src/actions/fx-append.js +8 -17
- package/src/actions/fx-confirm.js +3 -1
- package/src/actions/fx-delete.js +6 -3
- package/src/actions/fx-dispatch.js +9 -8
- package/src/actions/fx-hide.js +10 -6
- package/src/actions/fx-insert.js +49 -39
- package/src/actions/fx-message.js +3 -1
- package/src/actions/fx-refresh.js +11 -1
- package/src/actions/fx-replace.js +68 -0
- package/src/actions/fx-return.js +42 -0
- package/src/actions/fx-send.js +3 -1
- package/src/actions/fx-setvalue.js +58 -51
- package/src/actions/fx-show.js +8 -4
- package/src/actions/fx-toggle.js +15 -10
- package/src/actions/fx-update.js +3 -1
- package/src/dep_graph.js +4 -2
- package/src/drawdown.js +67 -82
- package/src/fore.js +158 -11
- package/src/functions/fx-function.js +11 -3
- package/src/fx-bind.js +42 -202
- package/src/fx-fore.js +105 -70
- package/src/fx-header.js +3 -1
- package/src/fx-instance.js +9 -1
- package/src/fx-model.js +31 -23
- package/src/fx-submission.js +73 -47
- package/src/fx-var.js +7 -4
- package/src/getInScopeContext.js +37 -11
- package/src/modelitem.js +4 -4
- package/src/relevance.js +65 -0
- package/src/ui/abstract-control.js +55 -35
- package/src/ui/fx-alert.js +7 -1
- package/src/ui/fx-case.js +3 -1
- package/src/ui/fx-container.js +7 -1
- package/src/ui/fx-control.js +283 -33
- package/src/ui/fx-dialog.js +54 -40
- package/src/ui/fx-group.js +3 -1
- package/src/ui/fx-hint.js +4 -1
- package/src/ui/fx-inspector.js +117 -17
- package/src/ui/fx-items.js +8 -8
- package/src/ui/fx-output.js +14 -5
- package/src/ui/fx-repeat.js +33 -41
- package/src/ui/fx-repeatitem.js +10 -4
- package/src/ui/fx-switch.js +3 -1
- package/src/ui/fx-trigger.js +3 -1
- package/src/xpath-evaluation.js +121 -131
- package/src/xpath-util.js +14 -7
- package/dist/fore-all.js +0 -140
- package/src/.DS_Store +0 -0
- package/src/actions/.DS_Store +0 -0
- package/src/ui/.DS_Store +0 -0
package/src/fx-submission.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Fore } from './fore.js';
|
|
2
|
+
import { Relevance } from './relevance.js';
|
|
2
3
|
import { foreElementMixin } from './ForeElementMixin.js';
|
|
3
4
|
import { evaluateXPathToString, evaluateXPath } from './xpath-evaluation.js';
|
|
4
5
|
import getInScopeContext from './getInScopeContext.js';
|
|
@@ -66,7 +67,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
async submit() {
|
|
69
|
-
await
|
|
70
|
+
await Fore.dispatch(this, 'submit', { submission: this });
|
|
70
71
|
this._submit();
|
|
71
72
|
}
|
|
72
73
|
|
|
@@ -82,7 +83,8 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
82
83
|
if (!valid) {
|
|
83
84
|
console.log('validation failed. Bubmission stopped');
|
|
84
85
|
// ### allow alerts to pop up
|
|
85
|
-
this.dispatch('submit-error', {});
|
|
86
|
+
// this.dispatch('submit-error', {});
|
|
87
|
+
Fore.dispatch(this, 'submit-error', {});
|
|
86
88
|
this.getModel().parentNode.refresh();
|
|
87
89
|
return;
|
|
88
90
|
}
|
|
@@ -117,24 +119,20 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
117
119
|
/**
|
|
118
120
|
* sends the data after evaluating
|
|
119
121
|
*
|
|
120
|
-
* todo: can send only XML at the moment
|
|
121
122
|
* @private
|
|
122
123
|
*/
|
|
123
124
|
async _serializeAndSend() {
|
|
124
125
|
const resolvedUrl = this._evaluateAttributeTemplateExpression(this.url, this);
|
|
125
126
|
|
|
126
127
|
const instance = this.getInstance();
|
|
127
|
-
|
|
128
|
-
console.error('JSON serialization is not supported yet');
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
128
|
+
console.log('instance type', instance.type);
|
|
131
129
|
|
|
132
|
-
// let serialized = serializer.serializeToString(this.nodeset);
|
|
133
130
|
let serialized;
|
|
134
131
|
if (this.serialization === 'none') {
|
|
135
132
|
serialized = undefined;
|
|
136
133
|
} else {
|
|
137
|
-
const relevant = this.selectRelevant();
|
|
134
|
+
// const relevant = this.selectRelevant(instance.type);
|
|
135
|
+
const relevant = Relevance.selectRelevant(this, instance.type);
|
|
138
136
|
serialized = this._serialize(instance.type, relevant);
|
|
139
137
|
}
|
|
140
138
|
|
|
@@ -145,17 +143,18 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
145
143
|
// console.log('data being send', serialized);
|
|
146
144
|
// console.log('submitting data',serialized);
|
|
147
145
|
|
|
148
|
-
if (resolvedUrl === '#echo') {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
146
|
+
// if (resolvedUrl === '#echo') {
|
|
147
|
+
if (resolvedUrl.startsWith('#echo')) {
|
|
148
|
+
let data = null;
|
|
149
|
+
if (serialized && instance.type === 'xml') {
|
|
150
|
+
data = new DOMParser().parseFromString(serialized, 'application/xml');
|
|
151
|
+
}
|
|
152
|
+
if (serialized && instance.type === 'json') {
|
|
153
|
+
data = JSON.parse(serialized);
|
|
154
154
|
}
|
|
155
|
-
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
this.dispatch('submit-done', {});
|
|
155
|
+
this._handleResponse(data);
|
|
156
|
+
// this.dispatch('submit-done', {});
|
|
157
|
+
Fore.dispatch(this, 'submit-done', {});
|
|
159
158
|
return;
|
|
160
159
|
}
|
|
161
160
|
// ### setting headers
|
|
@@ -168,7 +167,8 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
168
167
|
}
|
|
169
168
|
|
|
170
169
|
if (!this.methods.includes(this.method.toLowerCase())) {
|
|
171
|
-
this.dispatch('error', { message: `Unknown method ${this.method}` });
|
|
170
|
+
// this.dispatch('error', { message: `Unknown method ${this.method}` });
|
|
171
|
+
Fore.dispatch(this, 'error', { message: `Unknown method ${this.method}` });
|
|
172
172
|
return;
|
|
173
173
|
}
|
|
174
174
|
const response = await fetch(resolvedUrl, {
|
|
@@ -180,7 +180,8 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
180
180
|
});
|
|
181
181
|
|
|
182
182
|
if (!response.ok || response.status > 400) {
|
|
183
|
-
this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
|
|
183
|
+
// this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
|
|
184
|
+
Fore.dispatch(this, 'submit-error', { message: `Error while submitting ${this.id}` });
|
|
184
185
|
return;
|
|
185
186
|
}
|
|
186
187
|
|
|
@@ -204,7 +205,8 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
204
205
|
this._handleResponse(blob);
|
|
205
206
|
}
|
|
206
207
|
|
|
207
|
-
this.dispatch('submit-done', {});
|
|
208
|
+
// this.dispatch('submit-done', {});
|
|
209
|
+
Fore.dispatch(this, 'submit-done', {});
|
|
208
210
|
}
|
|
209
211
|
|
|
210
212
|
_serialize(instanceType, relevantNodes) {
|
|
@@ -221,11 +223,10 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
221
223
|
const serializer = new XMLSerializer();
|
|
222
224
|
return serializer.serializeToString(relevantNodes);
|
|
223
225
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
*/
|
|
226
|
+
if (instanceType === 'json') {
|
|
227
|
+
// console.warn('JSON serialization is not yet supported')
|
|
228
|
+
return JSON.stringify(relevantNodes);
|
|
229
|
+
}
|
|
229
230
|
throw new Error('unknown instance type ', instanceType);
|
|
230
231
|
}
|
|
231
232
|
|
|
@@ -269,13 +270,28 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
269
270
|
return targetInstance;
|
|
270
271
|
}
|
|
271
272
|
|
|
273
|
+
/**
|
|
274
|
+
* handles replacement of instance data from response data.
|
|
275
|
+
*
|
|
276
|
+
* Please note that data might be
|
|
277
|
+
* @param data
|
|
278
|
+
* @private
|
|
279
|
+
*/
|
|
272
280
|
_handleResponse(data) {
|
|
273
281
|
console.log('_handleResponse ', data);
|
|
282
|
+
|
|
283
|
+
/*
|
|
284
|
+
// ### responses need to be handled depending on their type.
|
|
285
|
+
if(this.type === 'json'){
|
|
286
|
+
|
|
287
|
+
}
|
|
288
|
+
*/
|
|
289
|
+
|
|
274
290
|
if (this.replace === 'instance') {
|
|
275
291
|
const targetInstance = this._getTargetInstance();
|
|
276
292
|
if (targetInstance) {
|
|
277
293
|
if (this.targetref) {
|
|
278
|
-
const theTarget = evaluateXPath(
|
|
294
|
+
const [theTarget] = evaluateXPath(
|
|
279
295
|
this.targetref,
|
|
280
296
|
targetInstance.instanceData.firstElementChild,
|
|
281
297
|
this,
|
|
@@ -286,7 +302,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
286
302
|
parent.replaceChild(clone, theTarget);
|
|
287
303
|
console.log('finally ', parent);
|
|
288
304
|
} else if (this.into) {
|
|
289
|
-
const theTarget = evaluateXPath(
|
|
305
|
+
const [theTarget] = evaluateXPath(
|
|
290
306
|
this.into,
|
|
291
307
|
targetInstance.instanceData.firstElementChild,
|
|
292
308
|
this,
|
|
@@ -296,6 +312,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
296
312
|
} else {
|
|
297
313
|
const instanceData = data;
|
|
298
314
|
targetInstance.instanceData = instanceData;
|
|
315
|
+
console.log('### replaced instance ', this.getModel().instances);
|
|
299
316
|
console.log('### replaced instance ', targetInstance.instanceData);
|
|
300
317
|
}
|
|
301
318
|
|
|
@@ -318,26 +335,29 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
318
335
|
if (this.replace === 'redirect') {
|
|
319
336
|
window.location.href = data;
|
|
320
337
|
}
|
|
321
|
-
|
|
322
|
-
/*
|
|
323
|
-
const event = new CustomEvent('submit-done', {
|
|
324
|
-
composed: true,
|
|
325
|
-
bubbles: true,
|
|
326
|
-
detail: {},
|
|
327
|
-
});
|
|
328
|
-
console.log('firing',event);
|
|
329
|
-
this.dispatchEvent(event);
|
|
330
|
-
*/
|
|
331
|
-
// this.dispatch('submit-done', {});
|
|
332
338
|
}
|
|
333
339
|
|
|
334
340
|
/**
|
|
335
341
|
* select relevant nodes
|
|
336
342
|
*
|
|
337
|
-
* todo: support for 'empty'
|
|
338
343
|
* @returns {*}
|
|
339
344
|
*/
|
|
340
|
-
|
|
345
|
+
/*
|
|
346
|
+
selectRelevant(type) {
|
|
347
|
+
console.log('selectRelevant' ,type)
|
|
348
|
+
switch (type){
|
|
349
|
+
case 'xml':
|
|
350
|
+
return this._relevantXmlNodes();
|
|
351
|
+
default:
|
|
352
|
+
console.warn(`relevance selection not supported for type:${this.type}`);
|
|
353
|
+
return this.nodeset;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
*/
|
|
357
|
+
|
|
358
|
+
// todo: support for 'empty'
|
|
359
|
+
/*
|
|
360
|
+
_relevantXmlNodes() {
|
|
341
361
|
// ### no relevance selection - current nodeset is used 'as-is'
|
|
342
362
|
if (this.nonrelevant === 'keep') {
|
|
343
363
|
return this.nodeset;
|
|
@@ -353,10 +373,11 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
353
373
|
if (this.nodeset.children.length === 0 && this._isRelevant(this.nodeset)) {
|
|
354
374
|
return this.nodeset;
|
|
355
375
|
}
|
|
356
|
-
|
|
357
|
-
return result;
|
|
376
|
+
return this._filterRelevant(this.nodeset, root);
|
|
358
377
|
}
|
|
378
|
+
*/
|
|
359
379
|
|
|
380
|
+
/*
|
|
360
381
|
_filterRelevant(node, result) {
|
|
361
382
|
const { childNodes } = node;
|
|
362
383
|
Array.from(childNodes).forEach(n => {
|
|
@@ -381,7 +402,9 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
381
402
|
});
|
|
382
403
|
return result;
|
|
383
404
|
}
|
|
405
|
+
*/
|
|
384
406
|
|
|
407
|
+
/*
|
|
385
408
|
_isRelevant(node) {
|
|
386
409
|
const mi = this.getModel().getModelItem(node);
|
|
387
410
|
if (!mi || mi.relevant) {
|
|
@@ -389,9 +412,11 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
389
412
|
}
|
|
390
413
|
return false;
|
|
391
414
|
}
|
|
415
|
+
*/
|
|
392
416
|
|
|
393
417
|
_handleError() {
|
|
394
|
-
this.dispatch('submit-error', {});
|
|
418
|
+
// this.dispatch('submit-error', {});
|
|
419
|
+
Fore.dispatch(this, 'submit-error', {});
|
|
395
420
|
/*
|
|
396
421
|
console.log('ERRRORRRRR');
|
|
397
422
|
this.dispatchEvent(
|
|
@@ -404,5 +429,6 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
404
429
|
*/
|
|
405
430
|
}
|
|
406
431
|
}
|
|
407
|
-
|
|
408
|
-
customElements.define('fx-submission', FxSubmission);
|
|
432
|
+
if (!customElements.get('fx-submission')) {
|
|
433
|
+
customElements.define('fx-submission', FxSubmission);
|
|
434
|
+
}
|
package/src/fx-var.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Fore } from './fore.js';
|
|
1
2
|
import './fx-instance.js';
|
|
2
3
|
import { evaluateXPath } from './xpath-evaluation.js';
|
|
3
4
|
import { foreElementMixin } from './ForeElementMixin.js';
|
|
@@ -24,13 +25,14 @@ export class FxVariable extends foreElementMixin(HTMLElement) {
|
|
|
24
25
|
refresh() {
|
|
25
26
|
const inscope = getInScopeContext(this, this.valueQuery);
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
const values = evaluateXPath(this.valueQuery, inscope, this, this.precedingVariables);
|
|
29
|
+
[this.value] = values;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
setInScopeVariables(inScopeVariables) {
|
|
31
33
|
if (inScopeVariables.has(this.name)) {
|
|
32
34
|
console.error(`The variable ${this.name} is declared more than once`);
|
|
33
|
-
|
|
35
|
+
Fore.dispatch(this, 'xforms-binding-error', {});
|
|
34
36
|
return;
|
|
35
37
|
}
|
|
36
38
|
inScopeVariables.set(this.name, this);
|
|
@@ -39,5 +41,6 @@ export class FxVariable extends foreElementMixin(HTMLElement) {
|
|
|
39
41
|
this.inScopeVariables = new Map(inScopeVariables);
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
|
-
|
|
43
|
-
customElements.define('fx-var', FxVariable);
|
|
44
|
+
if (!customElements.get('fx-var')) {
|
|
45
|
+
customElements.define('fx-var', FxVariable);
|
|
46
|
+
}
|
package/src/getInScopeContext.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { evaluateXPathToFirstNode } from './xpath-evaluation.js';
|
|
2
|
+
import { Fore } from './fore.js';
|
|
2
3
|
|
|
3
4
|
import { XPathUtil } from './xpath-util.js';
|
|
4
5
|
|
|
5
6
|
function _getElement(node) {
|
|
6
|
-
if (node.nodeType === Node.ATTRIBUTE_NODE) {
|
|
7
|
+
if (node && node.nodeType && node.nodeType === Node.ATTRIBUTE_NODE) {
|
|
7
8
|
// The context of an attribute is the ref of the element it's defined on
|
|
8
9
|
return node.ownerElement;
|
|
9
10
|
}
|
|
@@ -28,16 +29,28 @@ function _getModelInContext(node) {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
function _getInitialContext(node, ref) {
|
|
31
|
-
const parentBind =
|
|
32
|
+
const parentBind = Fore.getClosest('[ref]', node);
|
|
33
|
+
const localFore = Fore.getClosest('fx-fore', node);
|
|
34
|
+
|
|
35
|
+
const model = _getModelInContext(node);
|
|
32
36
|
|
|
33
37
|
if (parentBind !== null) {
|
|
34
|
-
|
|
38
|
+
/*
|
|
39
|
+
make sure that the closest ref belongs to the same fx-fore element
|
|
40
|
+
*/
|
|
41
|
+
const parentBindFore = parentBind.closest('fx-fore');
|
|
42
|
+
if (localFore === parentBindFore) {
|
|
43
|
+
return parentBind.nodeset;
|
|
44
|
+
}
|
|
45
|
+
return model.getDefaultInstance().getDefaultContext();
|
|
35
46
|
}
|
|
36
47
|
|
|
37
|
-
const model = _getModelInContext(node);
|
|
38
48
|
if (XPathUtil.isAbsolutePath(ref)) {
|
|
39
49
|
const instanceId = XPathUtil.getInstanceId(ref);
|
|
40
|
-
|
|
50
|
+
if (instanceId) {
|
|
51
|
+
return model.getInstance(instanceId).getDefaultContext();
|
|
52
|
+
}
|
|
53
|
+
return model.getDefaultInstance().getDefaultContext();
|
|
41
54
|
}
|
|
42
55
|
if (model.getDefaultInstance() !== null && model.inited) {
|
|
43
56
|
return model.getDefaultInstance().getDefaultContext();
|
|
@@ -47,17 +60,30 @@ function _getInitialContext(node, ref) {
|
|
|
47
60
|
|
|
48
61
|
export default function getInScopeContext(node, ref) {
|
|
49
62
|
const parentElement = _getElement(node);
|
|
50
|
-
/*
|
|
51
|
-
if(parentElement.nodeName.toUpperCase() === 'FX-REPEATITEM'){
|
|
52
|
-
return parentElement.nodeset;
|
|
53
|
-
}
|
|
54
|
-
*/
|
|
55
63
|
|
|
56
|
-
const repeatItem =
|
|
64
|
+
const repeatItem = Fore.getClosest('fx-repeatitem', parentElement);
|
|
57
65
|
if (repeatItem) {
|
|
66
|
+
if (node.nodeName === 'context') {
|
|
67
|
+
return evaluateXPathToFirstNode(
|
|
68
|
+
node.nodeValue,
|
|
69
|
+
repeatItem.nodeset,
|
|
70
|
+
_getForeContext(parentElement),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
58
73
|
return repeatItem.nodeset;
|
|
59
74
|
}
|
|
60
75
|
|
|
76
|
+
if (parentElement.hasAttribute('context')) {
|
|
77
|
+
const initialContext = _getInitialContext(parentElement.parentNode, ref);
|
|
78
|
+
const contextAttr = parentElement.getAttribute('context');
|
|
79
|
+
return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (node.nodeType === Node.ATTRIBUTE_NODE && node.nodeName === 'context') {
|
|
83
|
+
const initialContext = _getInitialContext(node.ownerElement.parentNode, ref);
|
|
84
|
+
const contextAttr = node.ownerElement.getAttribute('context');
|
|
85
|
+
return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
|
|
86
|
+
}
|
|
61
87
|
if (node.nodeType === Node.ATTRIBUTE_NODE && node.nodeName === 'ref') {
|
|
62
88
|
// Note: do not consider the ref of the owner element since it should not be used to define the
|
|
63
89
|
// context
|
package/src/modelitem.js
CHANGED
|
@@ -54,11 +54,11 @@ export class ModelItem {
|
|
|
54
54
|
console.log('modelitem.setvalue newVal', newVal);
|
|
55
55
|
|
|
56
56
|
if (newVal.nodeType === Node.DOCUMENT_NODE) {
|
|
57
|
-
|
|
58
|
-
this.node.appendChild(newVal.firstElementChild);
|
|
57
|
+
this.node.replaceWith(newVal.firstElementChild);
|
|
58
|
+
// this.node.appendChild(newVal.firstElementChild);
|
|
59
59
|
} else if (newVal.nodeType === Node.ELEMENT_NODE) {
|
|
60
|
-
|
|
61
|
-
this.node.appendChild(newVal);
|
|
60
|
+
this.node.replaceWith(newVal);
|
|
61
|
+
// this.node.appendChild(newVal);
|
|
62
62
|
} else if (this.node.nodeType === Node.ATTRIBUTE_NODE) {
|
|
63
63
|
this.node.nodeValue = newVal;
|
|
64
64
|
} else {
|
package/src/relevance.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export class Relevance {
|
|
2
|
+
static selectRelevant(element, type) {
|
|
3
|
+
console.log('selectRelevant', type);
|
|
4
|
+
switch (type) {
|
|
5
|
+
case 'xml':
|
|
6
|
+
return Relevance._relevantXmlNodes(element);
|
|
7
|
+
default:
|
|
8
|
+
console.warn(`relevance selection not supported for type:${element.type}`);
|
|
9
|
+
return element.nodeset;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static _relevantXmlNodes(element) {
|
|
14
|
+
// ### no relevance selection - current nodeset is used 'as-is'
|
|
15
|
+
const nonrelevant = element.getAttribute('nonrelevant');
|
|
16
|
+
if (nonrelevant === 'keep') {
|
|
17
|
+
return element.nodeset;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// first check if nodeset of submission is relevant - otherwise bail out
|
|
21
|
+
const mi = element.getModel().getModelItem(element.nodeset);
|
|
22
|
+
if (mi && !mi.relevant) return null;
|
|
23
|
+
|
|
24
|
+
const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
25
|
+
const root = doc.firstElementChild;
|
|
26
|
+
|
|
27
|
+
if (element.nodeset.children.length === 0 && Relevance._isRelevant(element, element.nodeset)) {
|
|
28
|
+
return element.nodeset;
|
|
29
|
+
}
|
|
30
|
+
return Relevance._filterRelevant(element, element.nodeset, root);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static _filterRelevant(element, node, result) {
|
|
34
|
+
const { childNodes } = node;
|
|
35
|
+
Array.from(childNodes).forEach(n => {
|
|
36
|
+
if (Relevance._isRelevant(element, n)) {
|
|
37
|
+
const clone = n.cloneNode(false);
|
|
38
|
+
result.appendChild(clone);
|
|
39
|
+
const { attributes } = n;
|
|
40
|
+
if (attributes) {
|
|
41
|
+
Array.from(attributes).forEach(attr => {
|
|
42
|
+
if (Relevance._isRelevant(element, attr)) {
|
|
43
|
+
clone.setAttribute(attr.nodeName, attr.value);
|
|
44
|
+
} else if (element.nonrelevant === 'empty') {
|
|
45
|
+
clone.setAttribute(attr.nodeName, '');
|
|
46
|
+
} else {
|
|
47
|
+
clone.removeAttribute(attr.nodeName);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return Relevance._filterRelevant(element, n, clone);
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
});
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static _isRelevant(element, node) {
|
|
59
|
+
const mi = element.getModel().getModelItem(node);
|
|
60
|
+
if (!mi || mi.relevant) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import '../fx-model.js';
|
|
2
2
|
import { foreElementMixin } from '../ForeElementMixin.js';
|
|
3
3
|
import { ModelItem } from '../modelitem.js';
|
|
4
|
+
import { Fore } from '../fore.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* `AbstractControl` -
|
|
@@ -26,7 +27,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
26
27
|
/**
|
|
27
28
|
* (re)apply all modelItem state properties to this control. model -> UI
|
|
28
29
|
*/
|
|
29
|
-
async refresh(
|
|
30
|
+
async refresh() {
|
|
30
31
|
// console.log('### AbstractControl.refresh on : ', this);
|
|
31
32
|
|
|
32
33
|
const currentVal = this.value;
|
|
@@ -36,6 +37,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
36
37
|
|
|
37
38
|
// await this.updateComplete;
|
|
38
39
|
// await this.getWidget();
|
|
40
|
+
this.oldVal = this.nodeset ? this.nodeset : null;
|
|
39
41
|
this.evalInContext();
|
|
40
42
|
|
|
41
43
|
if (this.isBound()) {
|
|
@@ -51,12 +53,36 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
51
53
|
if (this.modelItem instanceof ModelItem) {
|
|
52
54
|
// console.log('### XfAbstractControl.refresh modelItem : ', this.modelItem);
|
|
53
55
|
|
|
54
|
-
this.
|
|
56
|
+
if (this.hasAttribute('as') && this.getAttribute('as') === 'node') {
|
|
57
|
+
console.log('as', this.nodeset);
|
|
58
|
+
this.modelItem.value = this.nodeset;
|
|
59
|
+
this.value = this.modelItem.value;
|
|
60
|
+
} else {
|
|
61
|
+
this.value = this.modelItem.value;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// console.log('value of widget',this.value);
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
* todo: find out on which foreign modelitems we might be dependant on when no binds are used.
|
|
68
|
+
*
|
|
69
|
+
* e.g. filter expr on 'ref' 'instance('countries')//country[@continent = instance('default')/continent]'
|
|
70
|
+
*
|
|
71
|
+
* the country node is dependant on instance('default')/continent here (foreign node).
|
|
72
|
+
*
|
|
73
|
+
* possible approach:
|
|
74
|
+
* - pipe ref expression through DependencyNotifyingDomFacade to get referred nodes.
|
|
75
|
+
* - lookup modelItems of referred nodes
|
|
76
|
+
* - add ourselves to boundControls of foreign modelItem -> this control will then get refreshed when the foreign modelItem is changed.
|
|
77
|
+
*/
|
|
78
|
+
|
|
79
|
+
// const touched = FxBind.getReferencesForRef(this.ref,Array.from(this.nodeset));
|
|
80
|
+
// console.log('touched',touched);
|
|
55
81
|
|
|
56
82
|
/*
|
|
57
83
|
this is another case that highlights the fact that an init() function might make sense in general.
|
|
58
84
|
*/
|
|
59
|
-
if(!this.modelItem.boundControls.includes(this)){
|
|
85
|
+
if (!this.modelItem.boundControls.includes(this)) {
|
|
60
86
|
this.modelItem.boundControls.push(this);
|
|
61
87
|
}
|
|
62
88
|
|
|
@@ -68,15 +94,10 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
68
94
|
// if(!this.closest('fx-fore').ready) return; // state change event do not fire during init phase (initial refresh)
|
|
69
95
|
if (!this.getOwnerForm().ready) return; // state change event do not fire during init phase (initial refresh)
|
|
70
96
|
if (currentVal !== this.value) {
|
|
71
|
-
|
|
72
|
-
// console.log('value-changed path ', this.modelItem.path);
|
|
73
|
-
this.dispatch('value-changed', { path: this.modelItem.path });
|
|
97
|
+
Fore.dispatch(this, 'value-changed', { path: this.modelItem.path });
|
|
74
98
|
}
|
|
75
|
-
// this.requestUpdate();
|
|
76
99
|
}
|
|
77
100
|
}
|
|
78
|
-
// Fore.refreshChildren(this,force);
|
|
79
|
-
// await this.updateComplete;
|
|
80
101
|
}
|
|
81
102
|
|
|
82
103
|
/**
|
|
@@ -89,13 +110,14 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
89
110
|
}
|
|
90
111
|
|
|
91
112
|
handleModelItemProperties() {
|
|
92
|
-
// console.log('
|
|
113
|
+
// console.log('handleModelItemProperties',this.modelItem);
|
|
93
114
|
this.handleRequired();
|
|
94
115
|
this.handleReadonly();
|
|
95
116
|
if (this.getOwnerForm().ready) {
|
|
96
117
|
this.handleValid();
|
|
97
118
|
}
|
|
98
119
|
this.handleRelevant();
|
|
120
|
+
// todo: handleType()
|
|
99
121
|
}
|
|
100
122
|
|
|
101
123
|
_getForm() {
|
|
@@ -104,25 +126,23 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
104
126
|
|
|
105
127
|
_dispatchEvent(event) {
|
|
106
128
|
if (this.getOwnerForm().ready) {
|
|
107
|
-
|
|
129
|
+
Fore.dispatch(this, event, {});
|
|
108
130
|
}
|
|
109
131
|
}
|
|
110
132
|
|
|
111
133
|
// eslint-disable-next-line class-methods-use-this
|
|
112
134
|
handleRequired() {
|
|
113
135
|
// console.log('mip required', this.modelItem.required);
|
|
114
|
-
// const control = this.querySelector('#control');
|
|
115
136
|
this.widget = this.getWidget();
|
|
137
|
+
// if (this.required !== this.modelItem.required) {
|
|
116
138
|
if (this.isRequired() !== this.modelItem.required) {
|
|
117
139
|
if (this.modelItem.required) {
|
|
118
|
-
this.widget.setAttribute('required', '
|
|
119
|
-
this.
|
|
140
|
+
this.widget.setAttribute('required', '');
|
|
141
|
+
this.setAttribute('required', '');
|
|
120
142
|
this._dispatchEvent('required');
|
|
121
143
|
} else {
|
|
122
144
|
this.widget.removeAttribute('required');
|
|
123
|
-
this.required
|
|
124
|
-
// this.removeAttribute('required');
|
|
125
|
-
this.classList.toggle('required');
|
|
145
|
+
this.removeAttribute('required');
|
|
126
146
|
this._dispatchEvent('optional');
|
|
127
147
|
}
|
|
128
148
|
}
|
|
@@ -132,15 +152,13 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
132
152
|
// console.log('mip readonly', this.modelItem.isReadonly);
|
|
133
153
|
if (this.isReadonly() !== this.modelItem.readonly) {
|
|
134
154
|
if (this.modelItem.readonly) {
|
|
135
|
-
this.widget.setAttribute('readonly', '
|
|
136
|
-
|
|
137
|
-
this.classList.toggle('readonly');
|
|
155
|
+
this.widget.setAttribute('readonly', '');
|
|
156
|
+
this.setAttribute('readonly', '');
|
|
138
157
|
this._dispatchEvent('readonly');
|
|
139
158
|
}
|
|
140
159
|
if (!this.modelItem.readonly) {
|
|
141
160
|
this.widget.removeAttribute('readonly');
|
|
142
|
-
|
|
143
|
-
this.classList.toggle('readonly');
|
|
161
|
+
this.removeAttribute('readonly');
|
|
144
162
|
this._dispatchEvent('readwrite');
|
|
145
163
|
}
|
|
146
164
|
}
|
|
@@ -153,12 +171,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
153
171
|
|
|
154
172
|
if (this.isValid() !== this.modelItem.constraint) {
|
|
155
173
|
if (this.modelItem.constraint) {
|
|
156
|
-
this.classList.remove('invalid');
|
|
157
174
|
if (alert) alert.style.display = 'none';
|
|
158
175
|
this._dispatchEvent('valid');
|
|
176
|
+
this.removeAttribute('invalid');
|
|
159
177
|
} else {
|
|
178
|
+
this.setAttribute('invalid', '');
|
|
160
179
|
// ### constraint is invalid - handle alerts
|
|
161
|
-
this.classList.add('invalid');
|
|
162
180
|
if (alert) {
|
|
163
181
|
alert.style.display = 'block';
|
|
164
182
|
}
|
|
@@ -185,6 +203,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
185
203
|
|
|
186
204
|
handleRelevant() {
|
|
187
205
|
// console.log('mip valid', this.modelItem.enabled);
|
|
206
|
+
const item = this.modelItem.node;
|
|
207
|
+
if (Array.isArray(item) && item.length === 0) {
|
|
208
|
+
this._dispatchEvent('nonrelevant');
|
|
209
|
+
this.style.display = 'none';
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
188
212
|
if (this.isEnabled() !== this.modelItem.relevant) {
|
|
189
213
|
if (this.modelItem.relevant) {
|
|
190
214
|
this._dispatchEvent('relevant');
|
|
@@ -199,14 +223,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
199
223
|
}
|
|
200
224
|
|
|
201
225
|
isRequired() {
|
|
202
|
-
|
|
203
|
-
return true;
|
|
204
|
-
}
|
|
205
|
-
return false;
|
|
226
|
+
return this.hasAttribute('required');
|
|
206
227
|
}
|
|
207
228
|
|
|
208
229
|
isValid() {
|
|
209
|
-
|
|
230
|
+
// return this.valid;
|
|
231
|
+
if (this.hasAttribute('invalid')) {
|
|
210
232
|
return false;
|
|
211
233
|
}
|
|
212
234
|
return true;
|
|
@@ -214,10 +236,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
214
236
|
|
|
215
237
|
isReadonly() {
|
|
216
238
|
// const widget = this.querySelector('#widget');
|
|
217
|
-
|
|
218
|
-
return true;
|
|
219
|
-
}
|
|
220
|
-
return false;
|
|
239
|
+
return this.hasAttribute('readonly');
|
|
221
240
|
}
|
|
222
241
|
|
|
223
242
|
isEnabled() {
|
|
@@ -257,5 +276,6 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
257
276
|
})();
|
|
258
277
|
}
|
|
259
278
|
}
|
|
260
|
-
|
|
261
|
-
window.customElements.define('fx-abstract-control', AbstractControl);
|
|
279
|
+
if (!customElements.get('fx-abstract-control')) {
|
|
280
|
+
window.customElements.define('fx-abstract-control', AbstractControl);
|
|
281
|
+
}
|
package/src/ui/fx-alert.js
CHANGED
|
@@ -29,9 +29,15 @@ export class FxAlert extends AbstractControl {
|
|
|
29
29
|
`;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
getWidget() {
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
|
|
32
36
|
async updateWidgetValue() {
|
|
33
37
|
console.log('alert update', this);
|
|
34
38
|
this.innerHTML = this.value;
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
|
-
customElements.
|
|
41
|
+
if (!customElements.get('fx-alert')) {
|
|
42
|
+
customElements.define('fx-alert', FxAlert);
|
|
43
|
+
}
|