@jinntec/fore 1.10.0 → 1.10.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/dist/fore-dev.js +2 -2
- package/dist/fore-dev.js.map +1 -1
- package/dist/fore.js +2 -2
- package/dist/fore.js.map +1 -1
- package/package.json +1 -1
- package/resources/fore.css +2 -41
- package/src/actions/abstract-action.js +51 -62
- package/src/actions/fx-call.js +9 -0
- package/src/actions/fx-delete.js +1 -1
- package/src/actions/fx-insert.js +8 -4
- package/src/actions/fx-load.js +5 -2
- package/src/actions/fx-reload.js +1 -1
- package/src/actions/fx-send.js +8 -3
- package/src/actions/fx-setfocus.js +6 -1
- package/src/actions/fx-toggle.js +1 -0
- package/src/fore.js +3 -222
- package/src/fx-bind.js +1 -1
- package/src/fx-fore.js +96 -89
- package/src/fx-model.js +31 -7
- package/src/fx-submission.js +5 -0
- package/src/tools/fx-action-log.js +1 -1
- package/src/ui/abstract-control.js +18 -39
- package/src/ui/fx-control.js +12 -12
- package/src/ui/fx-repeat-attributes.js +2 -2
- package/src/ui/fx-repeat.js +12 -1
- package/src/ui/fx-repeatitem.js +2 -8
- package/src/ui/fx-switch.js +63 -40
- package/src/ui/fx-trigger.js +3 -13
- package/src/xpath-evaluation.js +215 -83
- package/src/xpath-util.js +138 -130
package/src/fx-bind.js
CHANGED
|
@@ -80,7 +80,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
80
80
|
_buildBindGraph() {
|
|
81
81
|
if (this.bindType === 'xml') {
|
|
82
82
|
this.nodeset.forEach(node => {
|
|
83
|
-
const instance = XPathUtil.resolveInstance(this);
|
|
83
|
+
const instance = XPathUtil.resolveInstance(this,this.ref);
|
|
84
84
|
|
|
85
85
|
const path = XPathUtil.getPath(node, instance);
|
|
86
86
|
this.model.mainGraph.addNode(path, node);
|
package/src/fx-fore.js
CHANGED
|
@@ -85,9 +85,10 @@ export class FxFore extends HTMLElement {
|
|
|
85
85
|
// this.addEventListener('model-construct-done', this._handleModelConstructDone);
|
|
86
86
|
// todo: refactoring - these should rather go into connectedcallback
|
|
87
87
|
this.addEventListener('message', this._displayMessage);
|
|
88
|
-
this.addEventListener('error', this._displayError);
|
|
88
|
+
// this.addEventListener('error', this._displayError);
|
|
89
|
+
this.addEventListener('error', this._logError);
|
|
89
90
|
this.addEventListener('warn', this._displayWarning);
|
|
90
|
-
this.addEventListener('log', this._logError);
|
|
91
|
+
// this.addEventListener('log', this._logError);
|
|
91
92
|
window.addEventListener('compute-exception', e => {
|
|
92
93
|
console.error('circular dependency: ', e);
|
|
93
94
|
});
|
|
@@ -176,7 +177,7 @@ export class FxFore extends HTMLElement {
|
|
|
176
177
|
|
|
177
178
|
const html = `
|
|
178
179
|
<noscript>This page uses Web Components and needs JavaScript to be enabled..</noscript>
|
|
179
|
-
|
|
180
|
+
<!-- <slot name="errors"></slot> -->
|
|
180
181
|
<jinn-toast id="message" gravity="bottom" position="left"></jinn-toast>
|
|
181
182
|
<jinn-toast id="sticky" gravity="bottom" position="left" duration="-1" close="true" data-class="sticky-message"></jinn-toast>
|
|
182
183
|
<jinn-toast id="error" text="error" duration="-1" data-class="error" close="true" position="right" gravity="top" escape-markup="false"></jinn-toast>
|
|
@@ -324,9 +325,9 @@ export class FxFore extends HTMLElement {
|
|
|
324
325
|
* Will extract the `fx-fore` element from that target file and use and replace current `fx-fore` element with the loaded one.
|
|
325
326
|
* @private
|
|
326
327
|
*/
|
|
327
|
-
_loadFromSrc() {
|
|
328
|
+
async _loadFromSrc() {
|
|
328
329
|
// console.log('########## loading Fore from ', this.src, '##########');
|
|
329
|
-
fetch(this.src, {
|
|
330
|
+
await fetch(this.src, {
|
|
330
331
|
method: 'GET',
|
|
331
332
|
mode: 'cors',
|
|
332
333
|
credentials: 'include',
|
|
@@ -450,42 +451,50 @@ export class FxFore extends HTMLElement {
|
|
|
450
451
|
// console.timeEnd('refresh');
|
|
451
452
|
}
|
|
452
453
|
|
|
453
|
-
async refresh(force, changedPaths) {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
454
|
+
// async refresh(force, changedPaths) {
|
|
455
|
+
async refresh(force) {
|
|
456
|
+
|
|
457
|
+
/*
|
|
458
|
+
|
|
459
|
+
if (!changedPaths) {
|
|
460
|
+
changedPaths = this.toRefresh.map(item => item.path);
|
|
461
|
+
} else {
|
|
462
|
+
this.toRefresh.push(
|
|
463
|
+
...changedPaths
|
|
464
|
+
.map(
|
|
465
|
+
path =>
|
|
466
|
+
this.getModel()
|
|
467
|
+
.modelItems
|
|
468
|
+
.find(item => item.path === path)
|
|
469
|
+
)
|
|
470
|
+
.filter(Boolean)
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
for(const changedPath of changedPaths) {
|
|
474
|
+
for (const repeat of this.querySelectorAll('fx-repeat')) {
|
|
475
|
+
if (repeat.closest('fx-fore') !== this) {
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (repeat.touchedPaths && repeat.touchedPaths.has(changedPath)) {
|
|
480
|
+
// Make a temporary model-item-like structure for this
|
|
481
|
+
this.toRefresh.push({
|
|
482
|
+
path: changedPath,
|
|
483
|
+
boundControls: [repeat]
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
console.log('Found a repeat to update!!!', repeat)
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
485
490
|
}
|
|
491
|
+
*/
|
|
486
492
|
if (this.isRefreshing) {
|
|
487
493
|
return;
|
|
488
494
|
}
|
|
495
|
+
this.isRefreshing = true;
|
|
496
|
+
console.log('### <<<<< refresh() >>>>>');
|
|
497
|
+
|
|
489
498
|
// refresh () {
|
|
490
499
|
// ### refresh Fore UI elements
|
|
491
500
|
// if (!this.initialRun && this.toRefresh.length !== 0) {
|
|
@@ -556,10 +565,12 @@ export class FxFore extends HTMLElement {
|
|
|
556
565
|
this.style.visibility='visible';
|
|
557
566
|
Fore.dispatch(this, 'refresh-done', {});
|
|
558
567
|
|
|
559
|
-
this.isRefreshing = true;
|
|
560
|
-
this.parentNode.closest('fx-fore')?.refresh(false, changedPaths);
|
|
568
|
+
// this.isRefreshing = true;
|
|
569
|
+
// this.parentNode.closest('fx-fore')?.refresh(false, changedPaths);
|
|
570
|
+
this.parentNode.closest('fx-fore')?.refresh(false);
|
|
561
571
|
for (const subFore of this.querySelectorAll('fx-fore')) {
|
|
562
|
-
subFore.refresh(false, changedPaths);
|
|
572
|
+
// subFore.refresh(false, changedPaths);
|
|
573
|
+
subFore.refresh(false);
|
|
563
574
|
}
|
|
564
575
|
this.isRefreshing = false;
|
|
565
576
|
}
|
|
@@ -649,6 +660,13 @@ export class FxFore extends HTMLElement {
|
|
|
649
660
|
* @param node the node which will get updated with evaluation result
|
|
650
661
|
*/
|
|
651
662
|
evaluateTemplateExpression(expr, node) {
|
|
663
|
+
|
|
664
|
+
// ### do not evaluate template expressions with nonrelevant sections
|
|
665
|
+
if(node.nodeType === Node.ATTRIBUTE_NODE && node.ownerElement.closest('[nonrelevant]')) return;
|
|
666
|
+
if(node.nodeType === Node.TEXT_NODE && node.parentNode.closest('[nonrelevant]')) return;
|
|
667
|
+
if(node.nodeType === Node.ELEMENT_NODE && node.closest('[nonrelevant]')) return;
|
|
668
|
+
|
|
669
|
+
// if(node.closest('[nonrelevant]')) return;
|
|
652
670
|
const replaced = expr.replace(/{[^}]*}/g, match => {
|
|
653
671
|
if (match === '{}') return match;
|
|
654
672
|
const naked = match.substring(1, match.length - 1);
|
|
@@ -750,30 +768,31 @@ export class FxFore extends HTMLElement {
|
|
|
750
768
|
*/
|
|
751
769
|
async _lazyCreateInstance() {
|
|
752
770
|
const model = this.querySelector('fx-model');
|
|
753
|
-
// Inherit shared models from the parent component
|
|
754
771
|
|
|
772
|
+
// ##### lazy creation should NOT take place if there's a parent Fore using shared instances
|
|
755
773
|
const parentFore = this.parentNode.closest('fx-fore');
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
}
|
|
761
|
-
this.getModel().updateModel();
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
if (model.instances.length === 0) {
|
|
766
|
-
// console.log('### lazy creation of instance');
|
|
767
|
-
const generatedInstance = document.createElement('fx-instance');
|
|
768
|
-
model.appendChild(generatedInstance);
|
|
774
|
+
if(parentFore){
|
|
775
|
+
const shared = parentFore.getModel().instances.filter(shared => shared.hasAttribute('shared'));
|
|
776
|
+
if(shared.length !==0) return;
|
|
777
|
+
}
|
|
769
778
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
779
|
+
// still need to catch just in case...
|
|
780
|
+
try{
|
|
781
|
+
if (model.instances.length === 0) {
|
|
782
|
+
// console.log('### lazy creation of instance');
|
|
783
|
+
const generatedInstance = document.createElement('fx-instance');
|
|
784
|
+
model.appendChild(generatedInstance);
|
|
785
|
+
|
|
786
|
+
const generated = document.implementation.createDocument(null, 'data', null);
|
|
787
|
+
// const newData = this._generateInstance(this, generated.firstElementChild);
|
|
788
|
+
this._generateInstance(this, generated.firstElementChild);
|
|
789
|
+
generatedInstance.instanceData = generated;
|
|
790
|
+
model.instances.push(generatedInstance);
|
|
791
|
+
// console.log('generatedInstance ', this.getModel().getDefaultInstanceData());
|
|
792
|
+
Fore.dispatch(this,'instance-loaded',{instance:this});
|
|
793
|
+
}
|
|
794
|
+
}catch (e) {
|
|
795
|
+
console.warn('lazyCreateInstance created an error attempting to create a document', e.message);
|
|
777
796
|
}
|
|
778
797
|
}
|
|
779
798
|
|
|
@@ -869,6 +888,8 @@ export class FxFore extends HTMLElement {
|
|
|
869
888
|
*/
|
|
870
889
|
async _initUI() {
|
|
871
890
|
// console.log('### _initUI()');
|
|
891
|
+
console.log('### <<<<< _initUI >>>>>');
|
|
892
|
+
|
|
872
893
|
if (!this.initialRun) return;
|
|
873
894
|
this.classList.add('initialRun');
|
|
874
895
|
await this._lazyCreateInstance();
|
|
@@ -902,6 +923,8 @@ export class FxFore extends HTMLElement {
|
|
|
902
923
|
this.ready = true;
|
|
903
924
|
this.initialRun = false;
|
|
904
925
|
// console.log('### >>>>> dispatching ready >>>>>', this);
|
|
926
|
+
console.log(`### <<<<< ${this.id} ready >>>>>`);
|
|
927
|
+
|
|
905
928
|
// console.log('### modelItems: ', this.getModel().modelItems);
|
|
906
929
|
Fore.dispatch(this, 'ready', {});
|
|
907
930
|
// console.log('dataChanged', FxModel.dataChanged);
|
|
@@ -953,39 +976,23 @@ export class FxFore extends HTMLElement {
|
|
|
953
976
|
toast.showToast(`WARN: ${path}:${msg}`);
|
|
954
977
|
}
|
|
955
978
|
|
|
979
|
+
|
|
956
980
|
_logError(e) {
|
|
957
981
|
e.stopPropagation();
|
|
958
982
|
e.preventDefault();
|
|
959
983
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
const path = document.createElement('div');
|
|
969
|
-
const pathExpr = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
|
|
970
|
-
// console.log('pathExpr',pathExpr)
|
|
971
|
-
path.textContent = pathExpr;
|
|
972
|
-
div.appendChild(path);
|
|
973
|
-
|
|
974
|
-
const message = document.createElement('div');
|
|
975
|
-
message.textContent = e.detail.message;
|
|
976
|
-
div.appendChild(message);
|
|
977
|
-
|
|
978
|
-
/*
|
|
979
|
-
const path = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
|
|
980
|
-
div.innerText = `${path} :: ${e.detail.message}`;
|
|
981
|
-
*/
|
|
982
|
-
this.appendChild(div);
|
|
983
|
-
div.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"});
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
const errorElement = evaluateXPathToFirstNode(`/${pathExpr}`,document,null);
|
|
987
|
-
errorElement.classList.add('fore-error');
|
|
984
|
+
console.error('ERROR',e.detail.message);
|
|
985
|
+
console.error(e.detail.origin);
|
|
986
|
+
if(e.detail.expr){
|
|
987
|
+
console.error('Failing expression',e.detail.expr);
|
|
988
|
+
}
|
|
989
|
+
console.error('---');
|
|
990
|
+
this._displayError(e);
|
|
991
|
+
}
|
|
988
992
|
|
|
993
|
+
_copyToClipboard(target){
|
|
994
|
+
console.log('copyToClipboard' , target.value)
|
|
995
|
+
navigator.clipboard.writeText(target.value);
|
|
989
996
|
|
|
990
997
|
}
|
|
991
998
|
|
package/src/fx-model.js
CHANGED
|
@@ -30,6 +30,7 @@ export class FxModel extends HTMLElement {
|
|
|
30
30
|
this.modelConstructed = false;
|
|
31
31
|
this.attachShadow({mode: 'open'});
|
|
32
32
|
this.computes = 0;
|
|
33
|
+
this.fore = {};
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
get formElement() {
|
|
@@ -49,6 +50,7 @@ export class FxModel extends HTMLElement {
|
|
|
49
50
|
}, {once: true});
|
|
50
51
|
|
|
51
52
|
this.skipUpdate = false;
|
|
53
|
+
this.fore = this.parentNode;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
static lazyCreateModelItem(model, ref, node) {
|
|
@@ -104,7 +106,7 @@ export class FxModel extends HTMLElement {
|
|
|
104
106
|
*
|
|
105
107
|
*/
|
|
106
108
|
async modelConstruct() {
|
|
107
|
-
|
|
109
|
+
console.log('### <<<<< dispatching model-construct >>>>>');
|
|
108
110
|
// this.dispatchEvent(new CustomEvent('model-construct', { detail: this }));
|
|
109
111
|
Fore.dispatch(this, 'model-construct', {model: this});
|
|
110
112
|
|
|
@@ -122,12 +124,12 @@ export class FxModel extends HTMLElement {
|
|
|
122
124
|
this.instances = Array.from(instances);
|
|
123
125
|
// console.log('_modelConstruct this.instances ', this.instances);
|
|
124
126
|
// Await until the model-construct-done event is handled off
|
|
125
|
-
|
|
126
127
|
await Fore.dispatch(this, 'model-construct-done', {model: this});
|
|
127
128
|
this.inited = true;
|
|
128
129
|
this.updateModel();
|
|
129
130
|
} else {
|
|
130
131
|
// ### if there's no instance one will created
|
|
132
|
+
console.log('### <<<<< dispatching model-construct-done >>>>>');
|
|
131
133
|
await this.dispatchEvent(
|
|
132
134
|
new CustomEvent('model-construct-done', {
|
|
133
135
|
composed: false,
|
|
@@ -165,6 +167,8 @@ export class FxModel extends HTMLElement {
|
|
|
165
167
|
}
|
|
166
168
|
|
|
167
169
|
rebuild() {
|
|
170
|
+
console.log('### <<<<< rebuild() >>>>>');
|
|
171
|
+
|
|
168
172
|
this.mainGraph = new DepGraph(false); // do: should be moved down below binds.length check but causes errors in tests.
|
|
169
173
|
this.modelItems = [];
|
|
170
174
|
|
|
@@ -194,10 +198,13 @@ export class FxModel extends HTMLElement {
|
|
|
194
198
|
* todo: use 'changed' flag on modelItems to determine subgraph for recalculation. Flag already exists but is not used.
|
|
195
199
|
*/
|
|
196
200
|
recalculate() {
|
|
201
|
+
|
|
197
202
|
if (!this.mainGraph) {
|
|
198
203
|
return;
|
|
199
204
|
}
|
|
200
205
|
|
|
206
|
+
console.log('### <<<<< recalculate() >>>>>');
|
|
207
|
+
|
|
201
208
|
// console.log('changed nodes ', this.changed);
|
|
202
209
|
this.computes = 0;
|
|
203
210
|
|
|
@@ -361,14 +368,13 @@ export class FxModel extends HTMLElement {
|
|
|
361
368
|
|
|
362
369
|
if (this.modelItems.length === 0) return true;
|
|
363
370
|
|
|
364
|
-
console.
|
|
371
|
+
console.log('### <<<<< revalidate() >>>>>');
|
|
365
372
|
|
|
366
373
|
// reset submission validation
|
|
367
374
|
// this.parentNode.classList.remove('submit-validation-failed')
|
|
368
375
|
let valid = true;
|
|
369
376
|
this.modelItems.forEach(modelItem => {
|
|
370
377
|
// console.log('validating node ', modelItem.node);
|
|
371
|
-
|
|
372
378
|
const {bind} = modelItem;
|
|
373
379
|
if (bind) {
|
|
374
380
|
/*
|
|
@@ -382,7 +388,10 @@ export class FxModel extends HTMLElement {
|
|
|
382
388
|
// console.log('modelItem validity computed: ', compute);
|
|
383
389
|
modelItem.constraint = compute;
|
|
384
390
|
this.formElement.addToRefresh(modelItem); // let fore know that modelItem needs refresh
|
|
385
|
-
if (!compute)
|
|
391
|
+
if (!compute) {
|
|
392
|
+
console.log('validation failed on modelitem ', modelItem);
|
|
393
|
+
valid = false;
|
|
394
|
+
}
|
|
386
395
|
}
|
|
387
396
|
}
|
|
388
397
|
if (typeof bind.hasAttribute === 'function' && bind.hasAttribute('required')) {
|
|
@@ -393,6 +402,7 @@ export class FxModel extends HTMLElement {
|
|
|
393
402
|
modelItem.required = compute;
|
|
394
403
|
this.formElement.addToRefresh(modelItem); // let fore know that modelItem needs refresh
|
|
395
404
|
if (!modelItem.node.textContent) {
|
|
405
|
+
console.log('validation failed on modelitem ', modelItem);
|
|
396
406
|
valid = false;
|
|
397
407
|
}
|
|
398
408
|
// if (!compute) valid = false;
|
|
@@ -450,9 +460,23 @@ export class FxModel extends HTMLElement {
|
|
|
450
460
|
// console.log('instances array ',Array.from(this.instances));
|
|
451
461
|
|
|
452
462
|
const instArray = Array.from(this.instances);
|
|
453
|
-
|
|
463
|
+
let found = instArray.find(inst => inst.id === id);
|
|
464
|
+
if(!found) {
|
|
465
|
+
const parentFore = this.fore.parentNode.closest('fx-fore');
|
|
466
|
+
if (parentFore) {
|
|
467
|
+
console.log('shared instances from parent', this.parentNode.id);
|
|
468
|
+
const parentInstances = parentFore.getModel().instances;
|
|
469
|
+
const shared = parentInstances.filter(shared => shared.hasAttribute('shared'));
|
|
470
|
+
found = shared.find(found => found.id === id);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
454
473
|
if(!found){
|
|
455
|
-
return this.getDefaultInstance(); // if id is not found always defaults to first in doc order
|
|
474
|
+
// return this.getDefaultInstance(); // if id is not found always defaults to first in doc order
|
|
475
|
+
Fore.dispatch(this, 'error', {
|
|
476
|
+
origin: this,
|
|
477
|
+
message: `Instance '${id}' does not exist`,
|
|
478
|
+
level:'Error'
|
|
479
|
+
});
|
|
456
480
|
}
|
|
457
481
|
return found;
|
|
458
482
|
}
|
package/src/fx-submission.js
CHANGED
|
@@ -144,6 +144,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
144
144
|
const data = this._parse(serialized, instance);
|
|
145
145
|
this._handleResponse(data);
|
|
146
146
|
// this.dispatch('submit-done', {});
|
|
147
|
+
console.log('### <<<<< submit-done >>>>>');
|
|
147
148
|
Fore.dispatch(this, 'submit-done', {});
|
|
148
149
|
this.parameters.clear();
|
|
149
150
|
return;
|
|
@@ -166,6 +167,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
166
167
|
if (this.method === 'consume') {
|
|
167
168
|
localStorage.removeItem(key);
|
|
168
169
|
}
|
|
170
|
+
console.log('### <<<<< submit-done >>>>>');
|
|
169
171
|
Fore.dispatch(this, 'submit-done', {});
|
|
170
172
|
}
|
|
171
173
|
if (this.method === 'post') {
|
|
@@ -173,6 +175,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
173
175
|
const key = resolvedUrl.substring(resolvedUrl.indexOf(':') + 1);
|
|
174
176
|
localStorage.setItem(key, serialized);
|
|
175
177
|
this._handleResponse(instance.instanceData);
|
|
178
|
+
console.log('### <<<<< submit-done >>>>>');
|
|
176
179
|
Fore.dispatch(this, 'submit-done', {});
|
|
177
180
|
}
|
|
178
181
|
if (this.method === 'delete') {
|
|
@@ -180,6 +183,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
180
183
|
localStorage.removeItem(key);
|
|
181
184
|
const newInst = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
182
185
|
this._handleResponse(newInst);
|
|
186
|
+
console.log('### <<<<< submit-done >>>>>');
|
|
183
187
|
Fore.dispatch(this, 'submit-done', {});
|
|
184
188
|
}
|
|
185
189
|
|
|
@@ -228,6 +232,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
228
232
|
}
|
|
229
233
|
|
|
230
234
|
// this.dispatch('submit-done', {});
|
|
235
|
+
console.log(`### <<<<< ${this.id} submit-done >>>>>`);
|
|
231
236
|
Fore.dispatch(this, 'submit-done', {});
|
|
232
237
|
} catch (error) {
|
|
233
238
|
Fore.dispatch(this, 'submit-error', {error: error.message});
|
|
@@ -459,7 +459,7 @@ export class FxActionLog extends HTMLElement {
|
|
|
459
459
|
*/
|
|
460
460
|
_logDetails(e) {
|
|
461
461
|
const eventType = e.type;
|
|
462
|
-
const path = XPathUtil.
|
|
462
|
+
const path = XPathUtil.getDocPath(e.target);
|
|
463
463
|
// console.log('>>>> _logDetails', path);
|
|
464
464
|
const cut = path.substring(path.indexOf('/fx-fore'), path.length);
|
|
465
465
|
const xpath = `/${cut}`;
|
|
@@ -14,7 +14,7 @@ import { evaluateXPathToFirstNode} from '../xpath-evaluation.js';
|
|
|
14
14
|
export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
15
15
|
constructor() {
|
|
16
16
|
super();
|
|
17
|
-
this.value =
|
|
17
|
+
this.value = null;
|
|
18
18
|
this.display = this.style.display;
|
|
19
19
|
this.required = false;
|
|
20
20
|
this.readonly = false;
|
|
@@ -24,27 +24,6 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
24
24
|
// this.attachShadow({ mode: 'open' });
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
// todo: discuss - this is a hack to circumvent that modelItems in toRefresh diverge from the modelItems in
|
|
29
|
-
// the model in some situations. This code first looks for refresh
|
|
30
|
-
/*
|
|
31
|
-
getModelItem() {
|
|
32
|
-
console.log('toRefreshModelItems', this.getOwnerForm().toRefresh);
|
|
33
|
-
const s = this.modelItem.path;
|
|
34
|
-
console.log('toRefreshModelItems path', s);
|
|
35
|
-
|
|
36
|
-
const toRefresh = this.getOwnerForm().toRefresh;
|
|
37
|
-
let mi;
|
|
38
|
-
if(toRefresh){
|
|
39
|
-
mi = this.getOwnerForm().toRefresh.find(m => m.path === s);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return mi? mi: super.getModelItem();
|
|
43
|
-
// console.log('toRefreshModelItems realitem', mi);
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
*/
|
|
47
|
-
|
|
48
27
|
// eslint-disable-next-line class-methods-use-this
|
|
49
28
|
getWidget() {
|
|
50
29
|
throw new Error('You have to implement the method getWidget!');
|
|
@@ -65,6 +44,8 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
65
44
|
// await this.updateComplete;
|
|
66
45
|
// await this.getWidget();
|
|
67
46
|
this.oldVal = this.nodeset ? this.nodeset : null;
|
|
47
|
+
// console.log('oldVal',this.oldVal);
|
|
48
|
+
|
|
68
49
|
this.evalInContext();
|
|
69
50
|
|
|
70
51
|
// todo this if should be removed - see above
|
|
@@ -105,7 +86,8 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
105
86
|
}else{
|
|
106
87
|
// ### this actually makes the control nonrelevant
|
|
107
88
|
// todo: we should call a template function here to allow detachment of event-listeners and resetting eventual state
|
|
108
|
-
this.style.display = 'none';
|
|
89
|
+
// this.style.display = 'none';
|
|
90
|
+
this.setAttribute('nonrelevant','');
|
|
109
91
|
}
|
|
110
92
|
return;
|
|
111
93
|
}
|
|
@@ -124,6 +106,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
124
106
|
} else {
|
|
125
107
|
this.value = this.modelItem.value;
|
|
126
108
|
}
|
|
109
|
+
// console.log('newVal',this.value);
|
|
127
110
|
|
|
128
111
|
// console.log('value of widget',this.value);
|
|
129
112
|
|
|
@@ -160,9 +143,8 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
160
143
|
Fore.dispatch(this,'init',{});
|
|
161
144
|
}
|
|
162
145
|
if (!this.getOwnerForm().ready) return; // state change event do not fire during init phase (initial refresh)
|
|
163
|
-
if
|
|
164
|
-
|
|
165
|
-
// if (currentVal !== this.value && this.visited) {
|
|
146
|
+
// if oldVal is null we haven't received a concrete value yet
|
|
147
|
+
if (this.oldVal !== null && currentVal !== this.value) {
|
|
166
148
|
Fore.dispatch(this, 'value-changed', { path: this.modelItem.path , value:this.modelItem.value});
|
|
167
149
|
}
|
|
168
150
|
}
|
|
@@ -337,20 +319,25 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
337
319
|
handleRelevant() {
|
|
338
320
|
// console.log('mip valid', this.modelItem.enabled);
|
|
339
321
|
const item = this.modelItem.node;
|
|
322
|
+
this.removeAttribute('relevant');
|
|
323
|
+
this.removeAttribute('nonrelevant');
|
|
340
324
|
if (Array.isArray(item) && item.length === 0) {
|
|
341
325
|
this._dispatchEvent('nonrelevant');
|
|
342
|
-
this.
|
|
326
|
+
this.setAttribute('nonrelevant','');
|
|
327
|
+
// this.style.display = 'none';
|
|
343
328
|
return;
|
|
344
329
|
}
|
|
345
330
|
if (this.isEnabled() !== this.modelItem.relevant) {
|
|
346
331
|
if (this.modelItem.relevant) {
|
|
347
332
|
this._dispatchEvent('relevant');
|
|
348
333
|
// this._fadeIn(this, this.display);
|
|
349
|
-
this.
|
|
334
|
+
this.setAttribute('relevant','');
|
|
335
|
+
// this.style.display = this.display;
|
|
350
336
|
} else {
|
|
351
337
|
this._dispatchEvent('nonrelevant');
|
|
352
338
|
// this._fadeOut(this);
|
|
353
|
-
this.
|
|
339
|
+
this.setAttribute('nonrelevant','');
|
|
340
|
+
// this.style.display = 'none';
|
|
354
341
|
}
|
|
355
342
|
}
|
|
356
343
|
}
|
|
@@ -360,11 +347,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
360
347
|
}
|
|
361
348
|
|
|
362
349
|
isValid() {
|
|
363
|
-
|
|
364
|
-
if (this.hasAttribute('invalid')) {
|
|
365
|
-
return false;
|
|
366
|
-
}
|
|
367
|
-
return true;
|
|
350
|
+
return this.hasAttribute('invalid') ? false : true;
|
|
368
351
|
}
|
|
369
352
|
|
|
370
353
|
isReadonly() {
|
|
@@ -373,11 +356,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
373
356
|
}
|
|
374
357
|
|
|
375
358
|
isEnabled() {
|
|
376
|
-
|
|
377
|
-
if (this.style.display === 'none') {
|
|
378
|
-
return false;
|
|
379
|
-
}
|
|
380
|
-
return true;
|
|
359
|
+
return !this.hasAttribute('nonrelevant');
|
|
381
360
|
}
|
|
382
361
|
|
|
383
362
|
// eslint-disable-next-line class-methods-use-this
|
package/src/ui/fx-control.js
CHANGED
|
@@ -123,12 +123,8 @@ export default class FxControl extends XfAbstractControl {
|
|
|
123
123
|
|
|
124
124
|
this.addEventListener('keyup', () => {
|
|
125
125
|
FxModel.dataChanged = true;
|
|
126
|
-
/*
|
|
127
|
-
if (!this.classList.contains('visited')) {
|
|
128
|
-
this.classList.add('visited');
|
|
129
|
-
}
|
|
130
|
-
*/
|
|
131
126
|
});
|
|
127
|
+
|
|
132
128
|
// ### convenience marker event
|
|
133
129
|
if (this.updateEvent === 'enter') {
|
|
134
130
|
this.widget.addEventListener('keyup', event => {
|
|
@@ -494,9 +490,13 @@ export default class FxControl extends XfAbstractControl {
|
|
|
494
490
|
this.dispatchEvent(new CustomEvent('loaded', {detail: {fore: theFore}}));
|
|
495
491
|
} catch (error) {
|
|
496
492
|
// console.log('error', error);
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
493
|
+
Fore.dispatch(this, 'error', {
|
|
494
|
+
origin: this,
|
|
495
|
+
message: `control couldn't be loaded from url '${this.url}'`,
|
|
496
|
+
expr:xpath,
|
|
497
|
+
level:'Error'
|
|
498
|
+
});
|
|
499
|
+
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
502
|
|
|
@@ -550,9 +550,6 @@ export default class FxControl extends XfAbstractControl {
|
|
|
550
550
|
// const nodeset = evaluateXPathToNodes(ref, inscope, this);
|
|
551
551
|
const nodeset = evaluateXPath(ref, inscope, this);
|
|
552
552
|
|
|
553
|
-
// ### bail out when nodeset is array and empty
|
|
554
|
-
if (Array.isArray(nodeset) && nodeset.length === 0) return;
|
|
555
|
-
|
|
556
553
|
// ### clear items
|
|
557
554
|
const {children} = widget;
|
|
558
555
|
Array.from(children).forEach(child => {
|
|
@@ -561,6 +558,9 @@ export default class FxControl extends XfAbstractControl {
|
|
|
561
558
|
}
|
|
562
559
|
});
|
|
563
560
|
|
|
561
|
+
// ### bail out when nodeset is array and empty
|
|
562
|
+
if (Array.isArray(nodeset) && nodeset.length === 0) return;
|
|
563
|
+
|
|
564
564
|
// ### build the items
|
|
565
565
|
const {template} = this;
|
|
566
566
|
if (template) {
|
|
@@ -574,7 +574,7 @@ export default class FxControl extends XfAbstractControl {
|
|
|
574
574
|
this.widget.insertBefore(option, firstTemplateChild);
|
|
575
575
|
}
|
|
576
576
|
|
|
577
|
-
if (nodeset.length) {
|
|
577
|
+
if (nodeset.length !== 0) {
|
|
578
578
|
// console.log('nodeset', nodeset);
|
|
579
579
|
const fragment = document.createDocumentFragment();
|
|
580
580
|
// console.time('offscreen');
|
|
@@ -135,9 +135,9 @@ export class FxRepeatAttributes extends foreElementMixin(HTMLElement) {
|
|
|
135
135
|
if (mutations[0].type === 'childList') {
|
|
136
136
|
const added = mutations[0].addedNodes[0];
|
|
137
137
|
if (added) {
|
|
138
|
-
const instance = XPathUtil.resolveInstance(this);
|
|
139
138
|
|
|
140
|
-
|
|
139
|
+
const instance = XPathUtil.resolveInstance(this,this.ref);
|
|
140
|
+
const path = XPathUtil.getPath(added, instance);
|
|
141
141
|
// this.dispatch('path-mutated',{'path':path,'nodeset':this.nodeset,'index': this.index});
|
|
142
142
|
// this.index = index;
|
|
143
143
|
// const prev = mutations[0].previousSibling.previousElementSibling;
|