@jinntec/fore 1.2.0 → 1.3.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/dist/fore-dev.js +8 -8
- package/dist/fore-dev.js.map +1 -1
- package/dist/fore.js +7 -7
- package/dist/fore.js.map +1 -1
- package/index.js +1 -0
- package/package.json +2 -2
- package/resources/fore.css +95 -72
- package/src/actions/abstract-action.js +48 -6
- package/src/actions/fx-action.js +1 -2
- package/src/actions/fx-confirm.js +2 -2
- package/src/actions/fx-delete.js +53 -62
- package/src/actions/fx-hide.js +3 -1
- package/src/actions/fx-message.js +25 -1
- package/src/actions/fx-reload.js +30 -0
- package/src/actions/fx-send.js +11 -1
- package/src/actions/fx-setfocus.js +32 -5
- package/src/actions/fx-setvalue.js +4 -4
- package/src/actions/fx-show.js +1 -0
- package/src/actions/fx-toggle.js +5 -0
- package/src/events.js +24 -0
- package/src/fore.js +71 -8
- package/src/fx-bind.js +1 -1
- package/src/fx-fore.js +65 -14
- package/src/fx-instance.js +33 -8
- package/src/fx-model.js +435 -441
- package/src/fx-submission.js +76 -62
- package/src/getInScopeContext.js +91 -83
- package/src/modelitem.js +2 -2
- package/src/relevance.js +1 -1
- package/src/ui/abstract-control.js +108 -22
- package/src/ui/fx-alert.js +0 -1
- package/src/ui/fx-container.js +22 -26
- package/src/ui/fx-control.js +84 -34
- package/src/ui/fx-group.js +5 -0
- package/src/ui/fx-inspector.js +5 -0
- package/src/ui/fx-output.js +14 -14
- package/src/ui/fx-repeat.js +2 -2
- package/src/ui/fx-repeatitem.js +5 -3
- package/src/ui/fx-switch.js +11 -7
- package/src/ui/fx-trigger.js +15 -9
- package/src/xpath-evaluation.js +28 -17
- package/src/xpath-util.js +13 -0
package/src/ui/fx-container.js
CHANGED
|
@@ -37,7 +37,7 @@ export class FxContainer extends foreElementMixin(HTMLElement) {
|
|
|
37
37
|
/**
|
|
38
38
|
* (re)apply all state properties to this control.
|
|
39
39
|
*/
|
|
40
|
-
refresh(force) {
|
|
40
|
+
async refresh(force) {
|
|
41
41
|
if (!force && this.hasAttribute('refresh-on-view')) return;
|
|
42
42
|
// console.log('### FxContainer.refresh on : ', this);
|
|
43
43
|
|
|
@@ -47,21 +47,20 @@ export class FxContainer extends foreElementMixin(HTMLElement) {
|
|
|
47
47
|
if (this.modelItem && !this.modelItem.boundControls.includes(this)) {
|
|
48
48
|
this.modelItem.boundControls.push(this);
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
// this.value = this.modelItem.value;
|
|
50
|
+
this.handleModelItemProperties();
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
// await this.updateComplete;
|
|
55
|
-
|
|
56
53
|
// state change event do not fire during init phase (initial refresh)
|
|
57
|
-
if (this._getForm().ready) {
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
Fore.refreshChildren(this, force);
|
|
54
|
+
// if (this._getForm().ready) {
|
|
55
|
+
// this.handleModelItemProperties();
|
|
56
|
+
// }
|
|
57
|
+
// Fore.refreshChildren(this, force);
|
|
61
58
|
}
|
|
62
59
|
|
|
60
|
+
/**
|
|
61
|
+
* anly relevance is processed for container controls
|
|
62
|
+
*/
|
|
63
63
|
handleModelItemProperties() {
|
|
64
|
-
this.handleReadonly();
|
|
65
64
|
this.handleRelevant();
|
|
66
65
|
}
|
|
67
66
|
|
|
@@ -69,28 +68,25 @@ export class FxContainer extends foreElementMixin(HTMLElement) {
|
|
|
69
68
|
return this.getModel().parentNode;
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
handleReadonly() {
|
|
73
|
-
// console.log('mip readonly', this.modelItem.isReadonly);
|
|
74
|
-
if (this.isReadonly() !== this.modelItem.readonly) {
|
|
75
|
-
if (this.modelItem.readonly) {
|
|
76
|
-
this.setAttribute('readonly', 'readonly');
|
|
77
|
-
this.dispatchEvent(new CustomEvent('readonly', {}));
|
|
78
|
-
}
|
|
79
|
-
if (!this.modelItem.readonly) {
|
|
80
|
-
this.removeAttribute('readonly');
|
|
81
|
-
this.dispatchEvent(new CustomEvent('readwrite', {}));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
71
|
handleRelevant() {
|
|
87
72
|
// console.log('mip valid', this.modelItem.enabled);
|
|
88
|
-
if (!this.modelItem)
|
|
73
|
+
if (!this.modelItem) {
|
|
74
|
+
console.log('container is not relevant');
|
|
75
|
+
this.removeAttribute('relevant','');
|
|
76
|
+
this.setAttribute('nonrelevant','');
|
|
77
|
+
this.dispatchEvent(new CustomEvent('disabled', {}));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
89
80
|
|
|
90
81
|
if (this.isEnabled() !== this.modelItem.enabled) {
|
|
91
|
-
if (this.modelItem.
|
|
82
|
+
if (this.modelItem.relevant) {
|
|
83
|
+
// this.style.display = 'block';
|
|
84
|
+
this.removeAttribute('nonrelevant','');
|
|
85
|
+
this.setAttribute('relevant','');
|
|
92
86
|
this.dispatchEvent(new CustomEvent('enabled', {}));
|
|
93
87
|
} else {
|
|
88
|
+
this.removeAttribute('relevant','');
|
|
89
|
+
this.setAttribute('nonrelevant','');
|
|
94
90
|
this.dispatchEvent(new CustomEvent('disabled', {}));
|
|
95
91
|
}
|
|
96
92
|
}
|
package/src/ui/fx-control.js
CHANGED
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
import getInScopeContext from '../getInScopeContext.js';
|
|
8
8
|
import { Fore } from '../fore.js';
|
|
9
9
|
import {ModelItem} from "../modelitem.js";
|
|
10
|
+
import {debounce} from "../events.js";
|
|
11
|
+
import {FxModel} from "../fx-model";
|
|
10
12
|
|
|
11
13
|
const WIDGETCLASS = 'widget';
|
|
12
14
|
|
|
@@ -20,7 +22,8 @@ const WIDGETCLASS = 'widget';
|
|
|
20
22
|
* @demo demo/index.html
|
|
21
23
|
*/
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
/*
|
|
26
|
+
function debounce( func, timeout = 300) {
|
|
24
27
|
let timer;
|
|
25
28
|
return (...args) => {
|
|
26
29
|
clearTimeout(timer);
|
|
@@ -29,6 +32,7 @@ function debounce(func, timeout = 300) {
|
|
|
29
32
|
}, timeout);
|
|
30
33
|
};
|
|
31
34
|
}
|
|
35
|
+
*/
|
|
32
36
|
export default class FxControl extends XfAbstractControl {
|
|
33
37
|
constructor() {
|
|
34
38
|
super();
|
|
@@ -72,10 +76,16 @@ export default class FxControl extends XfAbstractControl {
|
|
|
72
76
|
listenOn = target;
|
|
73
77
|
}
|
|
74
78
|
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
this.addEventListener('keyup', event => {
|
|
82
|
+
FxModel.dataChanged = true;
|
|
83
|
+
});
|
|
75
84
|
// ### convenience marker event
|
|
76
85
|
if (this.updateEvent === 'enter') {
|
|
77
86
|
this.widget.addEventListener('keyup', event => {
|
|
78
87
|
if (event.keyCode === 13) {
|
|
88
|
+
// console.info('handling Event:', event.type, listenOn);
|
|
79
89
|
// Cancel the default action, if needed
|
|
80
90
|
event.preventDefault();
|
|
81
91
|
this.setValue(this.widget[this.valueProp]);
|
|
@@ -86,14 +96,15 @@ export default class FxControl extends XfAbstractControl {
|
|
|
86
96
|
if (this.debounceDelay) {
|
|
87
97
|
listenOn.addEventListener(
|
|
88
98
|
this.updateEvent,
|
|
89
|
-
debounce(() => {
|
|
90
|
-
console.log('eventlistener ', this.updateEvent);
|
|
99
|
+
debounce(this,() => {
|
|
100
|
+
// console.log('eventlistener ', this.updateEvent);
|
|
101
|
+
// console.info('handling Event:', event.type, listenOn);
|
|
91
102
|
this.setValue(this.widget[this.valueProp]);
|
|
92
103
|
}, this.debounceDelay),
|
|
93
104
|
);
|
|
94
105
|
} else {
|
|
95
106
|
listenOn.addEventListener(this.updateEvent, () => {
|
|
96
|
-
console.
|
|
107
|
+
// console.info('handling Event:', event.type, listenOn);
|
|
97
108
|
this.setValue(this.widget[this.valueProp]);
|
|
98
109
|
});
|
|
99
110
|
}
|
|
@@ -125,6 +136,8 @@ export default class FxControl extends XfAbstractControl {
|
|
|
125
136
|
});
|
|
126
137
|
|
|
127
138
|
this.template = this.querySelector('template');
|
|
139
|
+
this.boundInitialized = false;
|
|
140
|
+
this.static = this.widget.hasAttribute('static')? true:false;
|
|
128
141
|
// console.log('template',this.template);
|
|
129
142
|
}
|
|
130
143
|
|
|
@@ -150,6 +163,8 @@ export default class FxControl extends XfAbstractControl {
|
|
|
150
163
|
setValue(val) {
|
|
151
164
|
const modelitem = this.getModelItem();
|
|
152
165
|
|
|
166
|
+
this.classList.add('visited');
|
|
167
|
+
|
|
153
168
|
if (modelitem?.readonly){
|
|
154
169
|
console.warn('attempt to change readonly node', modelitem);
|
|
155
170
|
return; // do nothing when modelItem is readonly
|
|
@@ -161,6 +176,7 @@ export default class FxControl extends XfAbstractControl {
|
|
|
161
176
|
replace.replace(this.nodeset, this.getWidget().value);
|
|
162
177
|
if (modelitem && widgetValue && widgetValue !== modelitem.value) {
|
|
163
178
|
modelitem.value = widgetValue;
|
|
179
|
+
FxModel.dataChanged = true;
|
|
164
180
|
replace.actionPerformed();
|
|
165
181
|
}
|
|
166
182
|
return;
|
|
@@ -173,6 +189,7 @@ export default class FxControl extends XfAbstractControl {
|
|
|
173
189
|
}
|
|
174
190
|
|
|
175
191
|
setval.actionPerformed();
|
|
192
|
+
this.visited = true;
|
|
176
193
|
}
|
|
177
194
|
|
|
178
195
|
_replaceNode(node) {
|
|
@@ -268,7 +285,7 @@ export default class FxControl extends XfAbstractControl {
|
|
|
268
285
|
widget.value = this.nodeset.cloneNode(true);
|
|
269
286
|
// todo: should be more like below but that can cause infinite loop when controll trigger update event due to calling a setter for property
|
|
270
287
|
// widget[this.valueProp] = this.nodeset.cloneNode(true);
|
|
271
|
-
console.log('passed value to widget', widget.value);
|
|
288
|
+
// console.log('passed value to widget', widget.value);
|
|
272
289
|
}
|
|
273
290
|
|
|
274
291
|
return;
|
|
@@ -277,6 +294,7 @@ export default class FxControl extends XfAbstractControl {
|
|
|
277
294
|
// ### when there's a url Fore is used as widget and will be loaded from external file
|
|
278
295
|
if (this.url && !this.loaded) {
|
|
279
296
|
// ### evaluate initial data if necessary
|
|
297
|
+
|
|
280
298
|
if (this.initial) {
|
|
281
299
|
this.initialNode = evaluateXPathToFirstNode(this.initial, this.nodeset, this);
|
|
282
300
|
console.log('initialNodes', this.initialNode);
|
|
@@ -315,7 +333,11 @@ export default class FxControl extends XfAbstractControl {
|
|
|
315
333
|
* @private
|
|
316
334
|
*/
|
|
317
335
|
async _loadForeFromUrl() {
|
|
318
|
-
console.log('########## loading Fore from ', this.
|
|
336
|
+
console.log('########## loading Fore from ', this.url, '##########');
|
|
337
|
+
console.info(
|
|
338
|
+
`%cFore is processing URL ${this.url}`,
|
|
339
|
+
"background:#64b5f6; color:white; padding:1rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;",
|
|
340
|
+
);
|
|
319
341
|
try {
|
|
320
342
|
const response = await fetch(this.url, {
|
|
321
343
|
method: 'GET',
|
|
@@ -325,6 +347,7 @@ export default class FxControl extends XfAbstractControl {
|
|
|
325
347
|
'Content-Type': 'text/html',
|
|
326
348
|
},
|
|
327
349
|
});
|
|
350
|
+
|
|
328
351
|
const responseContentType = response.headers.get('content-type').toLowerCase();
|
|
329
352
|
console.log('********** responseContentType *********', responseContentType);
|
|
330
353
|
let data;
|
|
@@ -338,37 +361,42 @@ export default class FxControl extends XfAbstractControl {
|
|
|
338
361
|
}
|
|
339
362
|
// const theFore = fxEvaluateXPathToFirstNode('//fx-fore', data.firstElementChild);
|
|
340
363
|
const theFore = data.querySelector('fx-fore');
|
|
364
|
+
const imported = document.importNode(theFore,true);
|
|
365
|
+
|
|
341
366
|
// console.log('thefore', theFore)
|
|
342
|
-
|
|
367
|
+
imported.classList.add('widget'); // is the new widget
|
|
368
|
+
console.log(`########## loaded fore as component ##### ${this.url}`);
|
|
369
|
+
imported.addEventListener(
|
|
370
|
+
'model-construct-done',
|
|
371
|
+
e => {
|
|
372
|
+
console.log('subcomponent ready', e.target);
|
|
373
|
+
const defaultInst = imported.querySelector('fx-instance');
|
|
374
|
+
// console.log('defaultInst', defaultInst);
|
|
375
|
+
if(this.initialNode){
|
|
376
|
+
const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
377
|
+
// Note: Clone the input to prevent the inner fore from editing the outer node
|
|
378
|
+
doc.firstElementChild.appendChild(this.initialNode.cloneNode(true));
|
|
379
|
+
// defaultinst.setInstanceData(this.initialNode);
|
|
380
|
+
defaultInst.setInstanceData(doc);
|
|
381
|
+
}
|
|
382
|
+
// console.log('new data', defaultInst.getInstanceData());
|
|
383
|
+
// theFore.getModel().modelConstruct();
|
|
384
|
+
imported.getModel().updateModel();
|
|
385
|
+
imported.refresh();
|
|
386
|
+
},
|
|
387
|
+
{ once: true },
|
|
388
|
+
);
|
|
389
|
+
|
|
343
390
|
const dummy = this.querySelector('input');
|
|
344
391
|
if (this.hasAttribute('shadow')) {
|
|
345
392
|
dummy.parentNode.removeChild(dummy);
|
|
346
|
-
this.shadowRoot.appendChild(
|
|
393
|
+
this.shadowRoot.appendChild(imported);
|
|
347
394
|
} else {
|
|
348
|
-
|
|
395
|
+
console.log(this, 'replacing widget with',theFore);
|
|
396
|
+
dummy.replaceWith(imported);
|
|
397
|
+
// this.appendChild(imported);
|
|
349
398
|
}
|
|
350
399
|
|
|
351
|
-
console.log(`########## loaded fore as component ##### ${this.url}`);
|
|
352
|
-
theFore.addEventListener(
|
|
353
|
-
'model-construct-done',
|
|
354
|
-
e => {
|
|
355
|
-
console.log('subcomponent ready', e.target);
|
|
356
|
-
const defaultInst = theFore.querySelector('fx-instance');
|
|
357
|
-
console.log('defaultInst', defaultInst);
|
|
358
|
-
if(this.initialNode){
|
|
359
|
-
const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
360
|
-
// Note: Clone the input to prevent the inner fore from editing the outer node
|
|
361
|
-
doc.firstElementChild.appendChild(this.initialNode.cloneNode(true));
|
|
362
|
-
// defaultinst.setInstanceData(this.initialNode);
|
|
363
|
-
defaultInst.setInstanceData(doc);
|
|
364
|
-
}
|
|
365
|
-
console.log('new data', defaultInst.getInstanceData());
|
|
366
|
-
// theFore.getModel().modelConstruct();
|
|
367
|
-
theFore.getModel().updateModel();
|
|
368
|
-
theFore.refresh();
|
|
369
|
-
},
|
|
370
|
-
{ once: true },
|
|
371
|
-
);
|
|
372
400
|
|
|
373
401
|
if (!theFore) {
|
|
374
402
|
this.dispatchEvent(
|
|
@@ -414,6 +442,8 @@ export default class FxControl extends XfAbstractControl {
|
|
|
414
442
|
* @private
|
|
415
443
|
*/
|
|
416
444
|
_handleBoundWidget(widget) {
|
|
445
|
+
if(this.boundInitialized && this.static) return;
|
|
446
|
+
|
|
417
447
|
if (widget && widget.hasAttribute('ref')) {
|
|
418
448
|
// ### eval nodeset for list control
|
|
419
449
|
const ref = widget.getAttribute('ref');
|
|
@@ -451,18 +481,36 @@ export default class FxControl extends XfAbstractControl {
|
|
|
451
481
|
|
|
452
482
|
if (nodeset.length) {
|
|
453
483
|
// console.log('nodeset', nodeset);
|
|
484
|
+
const fragment = document.createDocumentFragment();
|
|
485
|
+
console.time('offscreen');
|
|
486
|
+
/*
|
|
487
|
+
Array.from(nodeset).forEach(node => {
|
|
488
|
+
// console.log('#### node', node);
|
|
489
|
+
const newEntry = this.createEntry();
|
|
490
|
+
this.template.parentNode.appendChild(newEntry);
|
|
491
|
+
// ### initialize new entry
|
|
492
|
+
// ### set value
|
|
493
|
+
this.updateEntry(newEntry, node);
|
|
494
|
+
});
|
|
495
|
+
*/
|
|
496
|
+
// this should actually perform better than the above but does not seem to make a measurable difference.
|
|
454
497
|
Array.from(nodeset).forEach(node => {
|
|
455
498
|
// console.log('#### node', node);
|
|
456
499
|
const newEntry = this.createEntry();
|
|
500
|
+
fragment.appendChild(newEntry);
|
|
457
501
|
|
|
458
502
|
// ### initialize new entry
|
|
459
503
|
// ### set value
|
|
460
504
|
this.updateEntry(newEntry, node);
|
|
461
505
|
});
|
|
506
|
+
this.template.parentNode.appendChild(fragment);
|
|
507
|
+
console.timeEnd('offscreen');
|
|
462
508
|
} else {
|
|
463
509
|
const newEntry = this.createEntry();
|
|
510
|
+
this.template.parentNode.appendChild(newEntry);
|
|
464
511
|
this.updateEntry(newEntry, nodeset);
|
|
465
512
|
}
|
|
513
|
+
this.boundInitialized = true;
|
|
466
514
|
}
|
|
467
515
|
}
|
|
468
516
|
}
|
|
@@ -491,10 +539,12 @@ export default class FxControl extends XfAbstractControl {
|
|
|
491
539
|
}
|
|
492
540
|
|
|
493
541
|
createEntry() {
|
|
494
|
-
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
542
|
+
return this.template.content.firstElementChild.cloneNode(true);
|
|
543
|
+
// const content = this.template.content.firstElementChild.cloneNode(true);
|
|
544
|
+
// return content;
|
|
545
|
+
// const newEntry = document.importNode(content, true);
|
|
546
|
+
// this.template.parentNode.appendChild(newEntry);
|
|
547
|
+
// return newEntry;
|
|
498
548
|
}
|
|
499
549
|
|
|
500
550
|
// eslint-disable-next-line class-methods-use-this
|
package/src/ui/fx-group.js
CHANGED
package/src/ui/fx-inspector.js
CHANGED
|
@@ -25,6 +25,7 @@ export class FxInspector extends HTMLElement {
|
|
|
25
25
|
/*max-height: 33%;*/
|
|
26
26
|
overflow: scroll;
|
|
27
27
|
transition:width 0.3s ease;
|
|
28
|
+
z-index:100;
|
|
28
29
|
}
|
|
29
30
|
:host([open]){
|
|
30
31
|
width: 30%;
|
|
@@ -134,6 +135,10 @@ export class FxInspector extends HTMLElement {
|
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
serializeDOM(data) {
|
|
138
|
+
if(!data){
|
|
139
|
+
console.warn('no data to serialize');
|
|
140
|
+
return ;
|
|
141
|
+
}
|
|
137
142
|
// console.log('serializeDOM', data);
|
|
138
143
|
const ser = new XMLSerializer().serializeToString(data);
|
|
139
144
|
return Fore.prettifyXml(ser);
|
package/src/ui/fx-output.js
CHANGED
|
@@ -51,8 +51,9 @@ export class FxOutput extends XfAbstractControl {
|
|
|
51
51
|
|
|
52
52
|
const outputHtml = `
|
|
53
53
|
<slot name="label"></slot>
|
|
54
|
+
|
|
54
55
|
<span id="value">
|
|
55
|
-
<slot
|
|
56
|
+
<slot></slot>
|
|
56
57
|
</span>
|
|
57
58
|
`;
|
|
58
59
|
|
|
@@ -117,10 +118,11 @@ export class FxOutput extends XfAbstractControl {
|
|
|
117
118
|
// console.log('updateWidgetValue');
|
|
118
119
|
const valueWrapper = this.shadowRoot.getElementById('value');
|
|
119
120
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
|
|
122
|
+
// if (this.mediatype === 'markdown') {
|
|
123
|
+
// const md = markdown(this.nodeset);
|
|
124
|
+
// this.innerHtml = md;
|
|
125
|
+
// }
|
|
124
126
|
|
|
125
127
|
if (this.mediatype === 'html') {
|
|
126
128
|
if (this.modelItem.node) {
|
|
@@ -132,16 +134,7 @@ export class FxOutput extends XfAbstractControl {
|
|
|
132
134
|
const { node } = this.modelItem;
|
|
133
135
|
|
|
134
136
|
if (node.nodeType) {
|
|
135
|
-
// const mainSlot = this.shadowRoot.querySelector('#main');
|
|
136
|
-
// valueWrapper.appendChild(node);
|
|
137
|
-
|
|
138
|
-
// todo: checking if ownerDocument of node and ownerDocument of this are the same - otherwise import first
|
|
139
|
-
// const imported = this.ownerDocument.importNode(node,true);
|
|
140
|
-
// const clone = node.cloneNode(true);
|
|
141
|
-
|
|
142
137
|
this.appendChild(node);
|
|
143
|
-
// this.innerHtml = node;
|
|
144
|
-
// this.innerHTML = node;
|
|
145
138
|
return;
|
|
146
139
|
}
|
|
147
140
|
Object.entries(node).map(obj => {
|
|
@@ -158,6 +151,13 @@ export class FxOutput extends XfAbstractControl {
|
|
|
158
151
|
return;
|
|
159
152
|
}
|
|
160
153
|
|
|
154
|
+
if(this.mediatype === 'image'){
|
|
155
|
+
const img = document.createElement('img');
|
|
156
|
+
img.setAttribute('src',this.value);
|
|
157
|
+
this.appendChild(img);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
161
|
valueWrapper.innerHTML = this.value;
|
|
162
162
|
}
|
|
163
163
|
|
package/src/ui/fx-repeat.js
CHANGED
|
@@ -212,7 +212,7 @@ export class FxRepeat extends foreElementMixin(HTMLElement) {
|
|
|
212
212
|
// console.group('fx-repeat.refresh on', this.id);
|
|
213
213
|
|
|
214
214
|
if (!this.inited) this.init();
|
|
215
|
-
console.time('repeat-refresh', this);
|
|
215
|
+
// console.time('repeat-refresh', this);
|
|
216
216
|
this._evalNodeset();
|
|
217
217
|
// console.log('repeat refresh nodeset ', this.nodeset);
|
|
218
218
|
// console.log('repeatCount', this.repeatCount);
|
|
@@ -275,7 +275,7 @@ export class FxRepeat extends foreElementMixin(HTMLElement) {
|
|
|
275
275
|
// this.style.display = 'block';
|
|
276
276
|
// this.style.display = this.display;
|
|
277
277
|
this.setIndex(this.index);
|
|
278
|
-
console.timeEnd('repeat-refresh');
|
|
278
|
+
// console.timeEnd('repeat-refresh');
|
|
279
279
|
|
|
280
280
|
// this.replaceWith(clone);
|
|
281
281
|
|
package/src/ui/fx-repeatitem.js
CHANGED
|
@@ -43,7 +43,7 @@ export class FxRepeatitem extends foreElementMixin(HTMLElement) {
|
|
|
43
43
|
// console.log('_dispatchIndexChange on index ', this.index);
|
|
44
44
|
if (this.parentNode) {
|
|
45
45
|
this.parentNode.dispatchEvent(
|
|
46
|
-
new CustomEvent('item-changed', { composed:
|
|
46
|
+
new CustomEvent('item-changed', { composed: false, bubbles: true, detail: { item: this , index:this.index } }),
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -90,12 +90,14 @@ export class FxRepeatitem extends foreElementMixin(HTMLElement) {
|
|
|
90
90
|
|
|
91
91
|
if (this.modelItem && !this.modelItem.relevant) {
|
|
92
92
|
// await Fore.fadeOutElement(this)
|
|
93
|
-
this.style.display = 'none';
|
|
93
|
+
// this.style.display = 'none';
|
|
94
|
+
this.classList.add('nonrelevant');
|
|
94
95
|
} else {
|
|
95
96
|
// if(this.hasAttribute('repeat-index')){
|
|
96
97
|
// Fore.fadeInElement(this);
|
|
97
98
|
// }
|
|
98
|
-
this.style.display = this.display;
|
|
99
|
+
// this.style.display = this.display;
|
|
100
|
+
this.classList.remove('nonrelevant');
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
/*
|
package/src/ui/fx-switch.js
CHANGED
|
@@ -36,28 +36,31 @@ class FxSwitch extends FxContainer {
|
|
|
36
36
|
`;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
refresh() {
|
|
39
|
+
async refresh(force) {
|
|
40
40
|
super.refresh();
|
|
41
|
-
console.log('refresh on switch ');
|
|
41
|
+
// console.log('refresh on switch ');
|
|
42
42
|
const cases = this.querySelectorAll(':scope > fx-case');
|
|
43
|
+
let selectedCase;
|
|
43
44
|
if (this.isBound()) {
|
|
44
45
|
Array.from(cases).forEach(caseElem => {
|
|
45
46
|
const name = caseElem.getAttribute('name');
|
|
46
47
|
if (name === this.modelItem.value) {
|
|
47
48
|
caseElem.classList.add('selected-case');
|
|
49
|
+
selectedCase = caseElem;
|
|
48
50
|
} else {
|
|
49
51
|
caseElem.classList.remove('selected-case');
|
|
50
52
|
}
|
|
51
53
|
});
|
|
52
54
|
} else {
|
|
53
|
-
|
|
54
|
-
if
|
|
55
|
-
|
|
55
|
+
selectedCase = this.querySelector(':scope > .selected-case');
|
|
56
|
+
// if none is selected select the first as default
|
|
57
|
+
if (!selectedCase) {
|
|
58
|
+
selectedCase = cases[0];
|
|
59
|
+
selectedCase.classList.add('selected-case');
|
|
56
60
|
}
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
Fore.refreshChildren(
|
|
60
|
-
// console.log('value ', this.value);
|
|
63
|
+
Fore.refreshChildren(selectedCase,force);
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
toggle(caseElement) {
|
|
@@ -66,6 +69,7 @@ class FxSwitch extends FxContainer {
|
|
|
66
69
|
if (caseElement === c) {
|
|
67
70
|
// eslint-disable-next-line no-param-reassign
|
|
68
71
|
c.classList.add('selected-case');
|
|
72
|
+
this.refresh();
|
|
69
73
|
} else {
|
|
70
74
|
// eslint-disable-next-line no-param-reassign
|
|
71
75
|
c.classList.remove('selected-case');
|
package/src/ui/fx-trigger.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import XfAbstractControl from './abstract-control.js';
|
|
2
|
+
import {leadingDebounce} from "../events.js";
|
|
2
3
|
|
|
3
4
|
export class FxTrigger extends XfAbstractControl {
|
|
4
5
|
connectedCallback() {
|
|
5
6
|
this.attachShadow({ mode: 'open' });
|
|
6
7
|
this.ref = this.hasAttribute('ref') ? this.getAttribute('ref') : null;
|
|
8
|
+
this.debounceDelay = this.hasAttribute('debounce') ? this.getAttribute('debounce') : null;
|
|
9
|
+
|
|
7
10
|
const style = `
|
|
8
11
|
:host {
|
|
9
12
|
cursor:pointer;
|
|
@@ -24,7 +27,17 @@ export class FxTrigger extends XfAbstractControl {
|
|
|
24
27
|
elements[0].setAttribute('role', 'button');
|
|
25
28
|
|
|
26
29
|
const element = elements[0];
|
|
27
|
-
|
|
30
|
+
|
|
31
|
+
if(this.debounceDelay){
|
|
32
|
+
this.addEventListener(
|
|
33
|
+
'click',
|
|
34
|
+
leadingDebounce(this,(e) => {
|
|
35
|
+
this.performActions(e)
|
|
36
|
+
}, this.debounceDelay),
|
|
37
|
+
);
|
|
38
|
+
}else{
|
|
39
|
+
element.addEventListener('click', e => this.performActions(e));
|
|
40
|
+
}
|
|
28
41
|
this.widget = element;
|
|
29
42
|
// # terrible hack but browser behaves strange - seems to fire a 'click' for a button when it receives a
|
|
30
43
|
// # 'Space' or 'Enter' key
|
|
@@ -36,14 +49,6 @@ export class FxTrigger extends XfAbstractControl {
|
|
|
36
49
|
});
|
|
37
50
|
}
|
|
38
51
|
});
|
|
39
|
-
/*
|
|
40
|
-
this.addEventListener('click', e => this.performActions(e));
|
|
41
|
-
this.addEventListener('keypress', (e) => {
|
|
42
|
-
if(e.code === 'Space' || e.code === 'Enter'){
|
|
43
|
-
this.performActions(e);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
*/
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
// eslint-disable-next-line class-methods-use-this
|
|
@@ -89,6 +94,7 @@ export class FxTrigger extends XfAbstractControl {
|
|
|
89
94
|
if (typeof child.execute === 'function') {
|
|
90
95
|
// eslint-disable-next-line no-await-in-loop
|
|
91
96
|
await child.execute(e);
|
|
97
|
+
// child.execute(e);
|
|
92
98
|
}
|
|
93
99
|
}
|
|
94
100
|
};
|
package/src/xpath-evaluation.js
CHANGED
|
@@ -146,6 +146,30 @@ export function resolveId(id, sourceObject, nodeName = null) {
|
|
|
146
146
|
// Make namespace resolving use the `instance` element that is related to here
|
|
147
147
|
const xmlDocument = new DOMParser().parseFromString('<xml />', 'text/xml');
|
|
148
148
|
|
|
149
|
+
function findInstanceReferences(xpathQuery) {
|
|
150
|
+
if (!xpathQuery.includes('instance')) {
|
|
151
|
+
// No call to the instance function anyway: short-circuit and prevent AST processing
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
const xpathAST = parseScript(xpathQuery, {}, xmlDocument);
|
|
155
|
+
const instanceReferences = fxEvaluateXPathToStrings(
|
|
156
|
+
`descendant::xqx:functionCallExpr
|
|
157
|
+
[xqx:functionName = "instance"]
|
|
158
|
+
/xqx:arguments
|
|
159
|
+
/xqx:stringConstantExpr
|
|
160
|
+
/xqx:value`,
|
|
161
|
+
xpathAST,
|
|
162
|
+
null,
|
|
163
|
+
{},
|
|
164
|
+
{
|
|
165
|
+
namespaceResolver: prefix =>
|
|
166
|
+
prefix === 'xqx' ? 'http://www.w3.org/2005/XQueryX' : undefined,
|
|
167
|
+
},
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
return instanceReferences;
|
|
171
|
+
}
|
|
172
|
+
|
|
149
173
|
/**
|
|
150
174
|
* Resolve a namespace. Needs a namespace prefix and the element that is most closely related to the
|
|
151
175
|
* XPath in which the namespace is being resolved. The prefix will be resolved by using the
|
|
@@ -165,25 +189,12 @@ function createNamespaceResolver(xpathQuery, formElement) {
|
|
|
165
189
|
if (cachedResolver) {
|
|
166
190
|
return cachedResolver;
|
|
167
191
|
}
|
|
168
|
-
|
|
169
|
-
const xpathAST = parseScript(xpathQuery, {}, xmlDocument);
|
|
170
|
-
let instanceReferences = fxEvaluateXPathToStrings(
|
|
171
|
-
`descendant::xqx:functionCallExpr
|
|
172
|
-
[xqx:functionName = "instance"]
|
|
173
|
-
/xqx:arguments
|
|
174
|
-
/xqx:stringConstantExpr
|
|
175
|
-
/xqx:value`,
|
|
176
|
-
xpathAST,
|
|
177
|
-
null,
|
|
178
|
-
{},
|
|
179
|
-
{
|
|
180
|
-
namespaceResolver: prefix =>
|
|
181
|
-
prefix === 'xqx' ? 'http://www.w3.org/2005/XQueryX' : undefined,
|
|
182
|
-
},
|
|
183
|
-
);
|
|
192
|
+
let instanceReferences = findInstanceReferences(xpathQuery);
|
|
184
193
|
if (instanceReferences.length === 0) {
|
|
185
194
|
// No instance functions. Look up further in the hierarchy to see if we can deduce the intended context from there
|
|
186
|
-
const ancestorComponent =
|
|
195
|
+
const ancestorComponent = formElement.parentNode &&
|
|
196
|
+
formElement.parentNode.nodeType === formElement.ELEMENT &&
|
|
197
|
+
formElement.parentNode.closest('[ref]');
|
|
187
198
|
if (ancestorComponent) {
|
|
188
199
|
const resolver = createNamespaceResolver(
|
|
189
200
|
ancestorComponent.getAttribute('ref'),
|
package/src/xpath-util.js
CHANGED
|
@@ -76,6 +76,19 @@ export class XPathUtil {
|
|
|
76
76
|
return null;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
static resolveInstance(boundElement){
|
|
80
|
+
const instanceId = XPathUtil.getInstanceId(boundElement.getAttribute('ref'));
|
|
81
|
+
if(instanceId !== null){
|
|
82
|
+
return instanceId;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const parentBinding = XPathUtil.getParentBindingElement(boundElement);
|
|
86
|
+
if(parentBinding){
|
|
87
|
+
return this.resolveInstance(parentBinding);
|
|
88
|
+
}
|
|
89
|
+
return 'default';
|
|
90
|
+
}
|
|
91
|
+
|
|
79
92
|
// todo: certainly not ideal to rely on duplicating instance id on instance document - better way later ;)
|
|
80
93
|
static getPath(node) {
|
|
81
94
|
const path = fx.evaluateXPathToString('path()', node);
|