@jinntec/fore 1.3.0 → 1.5.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 +1 -1
- package/resources/fore.css +6 -1
- package/src/ForeElementMixin.js +4 -0
- package/src/actions/abstract-action.js +117 -48
- package/src/actions/fx-action.js +9 -9
- package/src/actions/fx-append.js +1 -1
- package/src/actions/fx-confirm.js +1 -1
- package/src/actions/fx-copy.js +68 -0
- package/src/actions/fx-delete.js +1 -1
- package/src/actions/fx-dispatch.js +1 -1
- package/src/actions/fx-hide.js +1 -1
- package/src/actions/fx-insert.js +1 -1
- package/src/actions/fx-message.js +1 -1
- package/src/actions/fx-refresh.js +2 -2
- package/src/actions/fx-reload.js +1 -1
- package/src/actions/fx-replace.js +1 -1
- package/src/actions/fx-return.js +1 -1
- package/src/actions/fx-send.js +2 -2
- package/src/actions/fx-setfocus.js +1 -1
- package/src/actions/fx-setvalue.js +1 -1
- package/src/actions/fx-show.js +1 -1
- package/src/actions/fx-toggle.js +1 -1
- package/src/actions/fx-update.js +1 -1
- package/src/fore.js +59 -10
- package/src/fx-bind.js +5 -0
- package/src/fx-fore.js +92 -35
- package/src/fx-instance.js +70 -70
- package/src/fx-model.js +12 -17
- package/src/fx-submission.js +420 -416
- package/src/getInScopeContext.js +19 -5
- package/src/modelitem.js +3 -1
- package/src/ui/abstract-control.js +1 -1
- package/src/ui/fx-control.js +2 -2
- package/src/ui/fx-repeat-attributes.js +442 -0
- package/src/ui/fx-repeat.js +8 -0
- package/src/ui/fx-switch.js +9 -1
- package/src/ui/fx-trigger.js +19 -18
- package/src/xpath-evaluation.js +21 -9
- package/src/xpath-util.js +13 -28
package/src/fore.js
CHANGED
|
@@ -9,6 +9,16 @@ export class Fore {
|
|
|
9
9
|
|
|
10
10
|
static TYPE_DEFAULT = 'xs:string';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* returns the next `fx-fore` element upwards in tree
|
|
14
|
+
*
|
|
15
|
+
* @param start
|
|
16
|
+
* @returns {*}
|
|
17
|
+
*/
|
|
18
|
+
static getFore(start) {
|
|
19
|
+
return start.nodeType === Node.TEXT_NODE ? start.parentNode.closest('fx-fore'):start.closest('fx-fore');
|
|
20
|
+
}
|
|
21
|
+
|
|
12
22
|
static get ACTION_ELEMENTS() {
|
|
13
23
|
return [
|
|
14
24
|
'FX-ACTION',
|
|
@@ -76,6 +86,7 @@ export class Fore {
|
|
|
76
86
|
'FX-RANGE',
|
|
77
87
|
'FX-REPEAT',
|
|
78
88
|
'FX-REPEATITEM',
|
|
89
|
+
'FX-REPEAT-ATTRIBUTES',
|
|
79
90
|
'FX-SWITCH',
|
|
80
91
|
'FX-SECRET',
|
|
81
92
|
'FX-SELECT',
|
|
@@ -285,14 +296,23 @@ export class Fore {
|
|
|
285
296
|
return fadeOut();
|
|
286
297
|
}
|
|
287
298
|
|
|
288
|
-
static dispatch(target, eventName, detail) {
|
|
299
|
+
static async dispatch(target, eventName, detail) {
|
|
289
300
|
const event = new CustomEvent(eventName, {
|
|
290
301
|
composed: false,
|
|
291
302
|
bubbles: true,
|
|
292
303
|
detail,
|
|
293
304
|
});
|
|
294
|
-
|
|
295
|
-
|
|
305
|
+
event.listenerPromises = [];
|
|
306
|
+
// console.info('dispatching', event.type, target);
|
|
307
|
+
// console.log('!!! DISPATCH_START', eventName);
|
|
308
|
+
|
|
309
|
+
target.dispatchEvent(event);
|
|
310
|
+
|
|
311
|
+
// By now, all listeners for the event should have registered their completion promises to us.
|
|
312
|
+
if (event.listenerPromises.length) {
|
|
313
|
+
await Promise.all(event.listenerPromises);
|
|
314
|
+
}
|
|
315
|
+
// console.log('!!! DISPATCH_DONE', eventName);
|
|
296
316
|
}
|
|
297
317
|
|
|
298
318
|
static prettifyXml(source) {
|
|
@@ -409,13 +429,42 @@ export class Fore {
|
|
|
409
429
|
}),
|
|
410
430
|
);
|
|
411
431
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
432
|
+
const imported = document.importNode(theFore,true);
|
|
433
|
+
console.log(`########## loaded fore as component ##### ${hostElement.url}`);
|
|
434
|
+
imported.addEventListener(
|
|
435
|
+
'model-construct-done',
|
|
436
|
+
e => {
|
|
437
|
+
console.log('subcomponent ready', e.target);
|
|
438
|
+
const defaultInst = imported.querySelector('fx-instance');
|
|
439
|
+
// console.log('defaultInst', defaultInst);
|
|
440
|
+
if(hostElement.initialNode){
|
|
441
|
+
const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
442
|
+
// Note: Clone the input to prevent the inner fore from editing the outer node
|
|
443
|
+
doc.firstElementChild.appendChild(hostElement.initialNode.cloneNode(true));
|
|
444
|
+
// defaultinst.setInstanceData(this.initialNode);
|
|
445
|
+
defaultInst.setInstanceData(doc);
|
|
446
|
+
}
|
|
447
|
+
// console.log('new data', defaultInst.getInstanceData());
|
|
448
|
+
// theFore.getModel().modelConstruct();
|
|
449
|
+
imported.getModel().updateModel();
|
|
450
|
+
imported.refresh();
|
|
451
|
+
return 'done';
|
|
452
|
+
|
|
453
|
+
},
|
|
454
|
+
{ once: true },
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
const dummy = hostElement.querySelector('input');
|
|
458
|
+
if (hostElement.hasAttribute('shadow')) {
|
|
459
|
+
dummy.parentNode.removeChild(dummy);
|
|
460
|
+
hostElement.shadowRoot.appendChild(imported);
|
|
461
|
+
} else {
|
|
462
|
+
console.log(this, 'replacing widget with',theFore);
|
|
463
|
+
dummy.replaceWith(imported);
|
|
464
|
+
// this.appendChild(imported);
|
|
465
|
+
}
|
|
417
466
|
})
|
|
418
|
-
|
|
467
|
+
/*.catch(error => {
|
|
419
468
|
hostElement.dispatchEvent(
|
|
420
469
|
new CustomEvent('error', {
|
|
421
470
|
composed: false,
|
|
@@ -426,7 +475,7 @@ export class Fore {
|
|
|
426
475
|
},
|
|
427
476
|
}),
|
|
428
477
|
);
|
|
429
|
-
})
|
|
478
|
+
});*/
|
|
430
479
|
}
|
|
431
480
|
|
|
432
481
|
/**
|
package/src/fx-bind.js
CHANGED
package/src/fx-fore.js
CHANGED
|
@@ -5,7 +5,8 @@ import '@jinntec/jinn-toast';
|
|
|
5
5
|
import {evaluateXPathToBoolean, evaluateXPathToNodes, evaluateXPathToString} from './xpath-evaluation.js';
|
|
6
6
|
import getInScopeContext from './getInScopeContext.js';
|
|
7
7
|
import {XPathUtil} from './xpath-util.js';
|
|
8
|
-
import {
|
|
8
|
+
// import {FxRepeat} from "./ui/fx-repeat";
|
|
9
|
+
import {FxRepeatAttributes} from './ui/fx-repeat-attributes.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Main class for Fore.Outermost container element for each Fore application.
|
|
@@ -15,9 +16,9 @@ import {AbstractAction} from "./actions/abstract-action";
|
|
|
15
16
|
* fx-fore is the outermost container for each form. A form can have exactly one model
|
|
16
17
|
* with arbitrary number of instances.
|
|
17
18
|
*
|
|
18
|
-
* Main
|
|
19
|
+
* Main responsibilities are initialization and updating of model and instances, update of UI (refresh) and global messaging.
|
|
19
20
|
*
|
|
20
|
-
* @event compute-exception - dispatched in case the dependency graph is
|
|
21
|
+
* @event compute-exception - dispatched in case the dependency graph is circular
|
|
21
22
|
* @event refresh-done - dispatched after a refresh() run
|
|
22
23
|
* @event ready - dispatched after Fore has fully been initialized
|
|
23
24
|
* @event error - dispatches error when template expression fails to evaluate
|
|
@@ -56,7 +57,7 @@ export class FxFore extends HTMLElement {
|
|
|
56
57
|
constructor() {
|
|
57
58
|
super();
|
|
58
59
|
this.model = {};
|
|
59
|
-
this.addEventListener('model-construct-done', this._handleModelConstructDone);
|
|
60
|
+
// this.addEventListener('model-construct-done', this._handleModelConstructDone);
|
|
60
61
|
this.addEventListener('message', this._displayMessage);
|
|
61
62
|
this.addEventListener('error', this._displayError);
|
|
62
63
|
window.addEventListener('compute-exception', e => {
|
|
@@ -68,19 +69,11 @@ export class FxFore extends HTMLElement {
|
|
|
68
69
|
|
|
69
70
|
const style = `
|
|
70
71
|
:host {
|
|
71
|
-
|
|
72
|
-
height:auto;
|
|
73
|
-
padding:var(--model-element-padding);
|
|
74
|
-
font-family:Roboto, sans-serif;
|
|
75
|
-
color:var(--paper-grey-900);
|
|
72
|
+
display: block;
|
|
76
73
|
}
|
|
77
74
|
:host ::slotted(fx-model){
|
|
78
75
|
display:none;
|
|
79
76
|
}
|
|
80
|
-
// :host(.fx-ready){
|
|
81
|
-
// animation: fadein .4s forwards;
|
|
82
|
-
// display:block;
|
|
83
|
-
// }
|
|
84
77
|
|
|
85
78
|
#modalMessage .dialogActions{
|
|
86
79
|
text-align:center;
|
|
@@ -144,14 +137,6 @@ export class FxFore extends HTMLElement {
|
|
|
144
137
|
#messageContent{
|
|
145
138
|
margin-top:40px;
|
|
146
139
|
}
|
|
147
|
-
@keyframes fadein {
|
|
148
|
-
0% {
|
|
149
|
-
opacity:0;
|
|
150
|
-
}
|
|
151
|
-
100% {
|
|
152
|
-
opacity:1;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
140
|
`;
|
|
156
141
|
|
|
157
142
|
const html = `
|
|
@@ -179,11 +164,12 @@ export class FxFore extends HTMLElement {
|
|
|
179
164
|
this.toRefresh = [];
|
|
180
165
|
this.initialRun = true;
|
|
181
166
|
this.someInstanceDataStructureChanged = false;
|
|
167
|
+
this.repeatsFromAttributesCreated = false;
|
|
182
168
|
}
|
|
183
169
|
|
|
184
170
|
connectedCallback() {
|
|
185
171
|
this.style.visibility = 'hidden';
|
|
186
|
-
|
|
172
|
+
console.time('init');
|
|
187
173
|
/*
|
|
188
174
|
document.addEventListener('ready', (e) =>{
|
|
189
175
|
if(e.target !== this){
|
|
@@ -220,7 +206,7 @@ export class FxFore extends HTMLElement {
|
|
|
220
206
|
}
|
|
221
207
|
|
|
222
208
|
const slot = this.shadowRoot.querySelector('slot');
|
|
223
|
-
slot.addEventListener('slotchange', event => {
|
|
209
|
+
slot.addEventListener('slotchange', async event => {
|
|
224
210
|
|
|
225
211
|
// preliminary addition for auto-conversion of non-prefixed element into prefixed elements. See fore.js
|
|
226
212
|
if(this.hasAttribute('convert')){
|
|
@@ -239,19 +225,23 @@ export class FxFore extends HTMLElement {
|
|
|
239
225
|
modelElement = generatedModel;
|
|
240
226
|
}
|
|
241
227
|
if (!modelElement.inited) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
228
|
+
console.info(
|
|
229
|
+
`%cFore is processing URL ${window.location.href}`,
|
|
230
|
+
"background:#64b5f6; color:white; padding:1rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;",
|
|
231
|
+
);
|
|
246
232
|
|
|
247
233
|
if (this.src) {
|
|
248
234
|
console.log('########## FORE: loaded from ... ', this.src, '##########');
|
|
249
235
|
}
|
|
250
|
-
modelElement.modelConstruct();
|
|
236
|
+
await modelElement.modelConstruct();
|
|
237
|
+
this._handleModelConstructDone();
|
|
251
238
|
}
|
|
252
239
|
this.model = modelElement;
|
|
240
|
+
|
|
241
|
+
this._createRepeatsFromAttributes();
|
|
242
|
+
|
|
253
243
|
});
|
|
254
|
-
this.addEventListener('path-mutated',
|
|
244
|
+
this.addEventListener('path-mutated', () => {
|
|
255
245
|
// console.log('path-mutated event received', e.detail.path, e.detail.index);
|
|
256
246
|
this.someInstanceDataStructureChanged = true;
|
|
257
247
|
});
|
|
@@ -300,7 +290,7 @@ export class FxFore extends HTMLElement {
|
|
|
300
290
|
|
|
301
291
|
// console.log('thefore', theFore)
|
|
302
292
|
if (!theFore) {
|
|
303
|
-
Fore.
|
|
293
|
+
Fore.dispatch(this, 'error', {
|
|
304
294
|
detail: {
|
|
305
295
|
message: `Fore element not found in '${this.src}'. Maybe wrapped within 'template' element?`,
|
|
306
296
|
},
|
|
@@ -324,9 +314,13 @@ export class FxFore extends HTMLElement {
|
|
|
324
314
|
*/
|
|
325
315
|
handleIntersect(entries, observer) {
|
|
326
316
|
console.time('refreshLazy');
|
|
317
|
+
|
|
327
318
|
entries.forEach(entry => {
|
|
328
319
|
const {target} = entry;
|
|
329
320
|
|
|
321
|
+
const fore = Fore.getFore(target);
|
|
322
|
+
if(fore.initialRun) return;
|
|
323
|
+
|
|
330
324
|
if (entry.isIntersecting) {
|
|
331
325
|
console.log('in view', entry);
|
|
332
326
|
// console.log('repeat in view entry', entry.target);
|
|
@@ -497,7 +491,18 @@ export class FxFore extends HTMLElement {
|
|
|
497
491
|
}
|
|
498
492
|
|
|
499
493
|
_processTemplateExpressions() {
|
|
500
|
-
for (const node of this.storedTemplateExpressionByNode.keys()) {
|
|
494
|
+
for (const node of Array.from(this.storedTemplateExpressionByNode.keys())) {
|
|
495
|
+
if (node.nodeType === Node.ATTRIBUTE_NODE) {
|
|
496
|
+
// Attribute nodes are not contained by the document, but their owner elements are!
|
|
497
|
+
if (!node.ownerDocument.contains(node.ownerElement)) {
|
|
498
|
+
this.storedTemplateExpressionByNode.delete(node);
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
} else if (!node.ownerDocument.contains(node)) {
|
|
502
|
+
// For all other nodes, if the document does not contain them, they are dead
|
|
503
|
+
this.storedTemplateExpressionByNode.delete(node);
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
501
506
|
this._processTemplateExpression({
|
|
502
507
|
node,
|
|
503
508
|
expr: this.storedTemplateExpressionByNode.get(node),
|
|
@@ -512,7 +517,7 @@ export class FxFore extends HTMLElement {
|
|
|
512
517
|
const {expr} = exprObj;
|
|
513
518
|
const {node} = exprObj;
|
|
514
519
|
// console.log('expr ', expr);
|
|
515
|
-
this.evaluateTemplateExpression(expr, node
|
|
520
|
+
this.evaluateTemplateExpression(expr, node);
|
|
516
521
|
}
|
|
517
522
|
|
|
518
523
|
/**
|
|
@@ -567,7 +572,7 @@ export class FxFore extends HTMLElement {
|
|
|
567
572
|
|
|
568
573
|
/**
|
|
569
574
|
* called when `model-construct-done` event is received to
|
|
570
|
-
* start initing
|
|
575
|
+
* start initing the UI.
|
|
571
576
|
*
|
|
572
577
|
* @private
|
|
573
578
|
*/
|
|
@@ -583,7 +588,7 @@ export class FxFore extends HTMLElement {
|
|
|
583
588
|
&& condition !== 'true'
|
|
584
589
|
&& condition !== ''){
|
|
585
590
|
window.addEventListener('beforeunload', event => {
|
|
586
|
-
const mustDisplay = evaluateXPathToBoolean(
|
|
591
|
+
const mustDisplay = evaluateXPathToBoolean(condition, this.getModel().getDefaultContext(), this)
|
|
587
592
|
if(mustDisplay){
|
|
588
593
|
console.log('have to display confirmation')
|
|
589
594
|
return event.returnValue = 'are you sure';
|
|
@@ -747,7 +752,8 @@ export class FxFore extends HTMLElement {
|
|
|
747
752
|
};
|
|
748
753
|
*/
|
|
749
754
|
|
|
750
|
-
|
|
755
|
+
// First refresh should be forced
|
|
756
|
+
await this.refresh(true);
|
|
751
757
|
// this.style.display='block'
|
|
752
758
|
this.classList.add('fx-ready');
|
|
753
759
|
document.body.classList.add('fx-ready');
|
|
@@ -761,6 +767,7 @@ export class FxFore extends HTMLElement {
|
|
|
761
767
|
`%cPage Initialization done`,
|
|
762
768
|
"background:#64b5f6; color:white; padding:1rem; display:block; white-space: nowrap; border-radius:0.3rem;width:100%;",
|
|
763
769
|
);
|
|
770
|
+
console.timeEnd('init');
|
|
764
771
|
console.log('dataChanged', FxModel.dataChanged);
|
|
765
772
|
}
|
|
766
773
|
|
|
@@ -817,6 +824,56 @@ export class FxFore extends HTMLElement {
|
|
|
817
824
|
toast.showToast(msg);
|
|
818
825
|
}
|
|
819
826
|
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* wraps the element having a 'data-ref' attribute with an fx-repeat-attributes element.
|
|
830
|
+
* @private
|
|
831
|
+
*/
|
|
832
|
+
_createRepeatsFromAttributes() {
|
|
833
|
+
if(this.repeatsFromAttributesCreated) return;
|
|
834
|
+
const repeats = this.querySelectorAll('[data-ref]');
|
|
835
|
+
if(repeats){
|
|
836
|
+
Array.from(repeats).forEach(item =>{
|
|
837
|
+
|
|
838
|
+
const table = item.parentNode.closest('table');
|
|
839
|
+
let host;
|
|
840
|
+
if(table){
|
|
841
|
+
host = table.cloneNode(true);
|
|
842
|
+
}else{
|
|
843
|
+
host = item.cloneNode(true);
|
|
844
|
+
}
|
|
845
|
+
// ### clone original item to move it into fx-repeat-attributes
|
|
846
|
+
// const host = item.cloneNode(true);
|
|
847
|
+
|
|
848
|
+
// ### create wrapper element
|
|
849
|
+
const repeatFromAttr = new FxRepeatAttributes();
|
|
850
|
+
// const repeatFromAttr = document.createElement('fx-repeat-attributes');
|
|
851
|
+
|
|
852
|
+
// ### copy the value of 'data-ref' to 'ref' on fx-repeat-attributes
|
|
853
|
+
repeatFromAttr.setAttribute('ref',item.getAttribute('data-ref'));
|
|
854
|
+
// item.removeAttribute('data-ref');
|
|
855
|
+
|
|
856
|
+
// ### append the cloned original element to fx-repeat-attributes
|
|
857
|
+
repeatFromAttr.appendChild(host);
|
|
858
|
+
|
|
859
|
+
// ### insert fx-repeat-attributes element before element with the 'data-ref'
|
|
860
|
+
// repeats[0].parentNode.insertBefore(repeatFromAttr,repeats[0]);
|
|
861
|
+
|
|
862
|
+
if(table){
|
|
863
|
+
table.parentNode.insertBefore(repeatFromAttr,table);
|
|
864
|
+
table.parentNode.removeChild(table);
|
|
865
|
+
}else{
|
|
866
|
+
item.parentNode.insertBefore(repeatFromAttr,item);
|
|
867
|
+
item.parentNode.removeChild(item);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// ### remove original item from DOM
|
|
871
|
+
item.setAttribute('insertPoint','');
|
|
872
|
+
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
this.repeatsFromAttributesCreated = true;
|
|
876
|
+
}
|
|
820
877
|
}
|
|
821
878
|
|
|
822
879
|
if (!customElements.get('fx-fore')) {
|
package/src/fx-instance.js
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
import { Fore } from './fore.js';
|
|
2
2
|
import { evaluateXPathToFirstNode } from './xpath-evaluation.js';
|
|
3
3
|
|
|
4
|
+
async function handleResponse(response) {
|
|
5
|
+
const { status } = response;
|
|
6
|
+
if (status >= 400) {
|
|
7
|
+
// console.log('response status', status);
|
|
8
|
+
alert(`response status: ${status} - failed to load data for '${this.src}' - stopping.`);
|
|
9
|
+
throw new Error(`failed to load data - status: ${status}`);
|
|
10
|
+
}
|
|
11
|
+
const responseContentType = response.headers.get('content-type').toLowerCase();
|
|
12
|
+
// console.log('********** responseContentType *********', responseContentType);
|
|
13
|
+
if (responseContentType.startsWith('text/html')) {
|
|
14
|
+
// const htmlResponse = response.text();
|
|
15
|
+
// return new DOMParser().parseFromString(htmlResponse, 'text/html');
|
|
16
|
+
// return response.text();
|
|
17
|
+
return response.text().then(result =>
|
|
18
|
+
// console.log('xml ********', result);
|
|
19
|
+
new DOMParser().parseFromString(result, 'text/html'),
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
if (
|
|
23
|
+
responseContentType.startsWith('text/plain') ||
|
|
24
|
+
responseContentType.startsWith('text/markdown')
|
|
25
|
+
) {
|
|
26
|
+
// console.log("********** inside res plain *********");
|
|
27
|
+
return response.text();
|
|
28
|
+
}
|
|
29
|
+
if (responseContentType.startsWith('application/json')) {
|
|
30
|
+
// console.log("********** inside res json *********");
|
|
31
|
+
return response.json();
|
|
32
|
+
}
|
|
33
|
+
if (responseContentType.startsWith('application/xml')) {
|
|
34
|
+
const text = await response.text();
|
|
35
|
+
// console.log('xml ********', result);
|
|
36
|
+
return new DOMParser().parseFromString(text, 'application/xml');
|
|
37
|
+
}
|
|
38
|
+
return 'done';
|
|
39
|
+
}
|
|
40
|
+
|
|
4
41
|
/**
|
|
5
42
|
* Container for data instances.
|
|
6
43
|
*
|
|
@@ -59,16 +96,15 @@ export class FxInstance extends HTMLElement {
|
|
|
59
96
|
*/
|
|
60
97
|
async init() {
|
|
61
98
|
// console.log('fx-instance init');
|
|
62
|
-
await this._initInstance()
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
99
|
+
await this._initInstance();
|
|
100
|
+
this.dispatchEvent(
|
|
101
|
+
new CustomEvent('instance-loaded', {
|
|
102
|
+
composed: true,
|
|
103
|
+
bubbles: true,
|
|
104
|
+
detail: { instance: this },
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
return this;
|
|
72
108
|
}
|
|
73
109
|
|
|
74
110
|
evalXPath(xpath) {
|
|
@@ -155,22 +191,21 @@ export class FxInstance extends HTMLElement {
|
|
|
155
191
|
|
|
156
192
|
async _loadData() {
|
|
157
193
|
const url = `${this.src}`;
|
|
158
|
-
const contentType = Fore.getContentType(this, 'get');
|
|
159
194
|
|
|
160
|
-
if(url.startsWith('localStore')){
|
|
161
|
-
const key = url.substring(url.indexOf(':')+1);
|
|
195
|
+
if (url.startsWith('localStore')) {
|
|
196
|
+
const key = url.substring(url.indexOf(':') + 1);
|
|
162
197
|
|
|
163
198
|
const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
164
199
|
const root = doc.firstElementChild;
|
|
165
200
|
this.instanceData = doc;
|
|
166
201
|
|
|
167
|
-
if(!key){
|
|
202
|
+
if (!key) {
|
|
168
203
|
console.warn('no key specified for localStore');
|
|
169
204
|
return;
|
|
170
205
|
}
|
|
171
206
|
|
|
172
207
|
const serialized = localStorage.getItem(key);
|
|
173
|
-
if(!serialized){
|
|
208
|
+
if (!serialized) {
|
|
174
209
|
console.warn(`Data for key ${key} cannot be found`);
|
|
175
210
|
this._useInlineData();
|
|
176
211
|
return;
|
|
@@ -181,63 +216,28 @@ export class FxInstance extends HTMLElement {
|
|
|
181
216
|
doc.firstElementChild.replaceWith(data.firstElementChild);
|
|
182
217
|
return;
|
|
183
218
|
}
|
|
219
|
+
const contentType = Fore.getContentType(this, 'get');
|
|
184
220
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
.then(response => {
|
|
194
|
-
const { status } = response;
|
|
195
|
-
if (status >= 400) {
|
|
196
|
-
// console.log('response status', status);
|
|
197
|
-
alert(`response status: ${status} - failed to load data for '${this.src}' - stopping.`);
|
|
198
|
-
throw new Error(`failed to load data - status: ${status}`);
|
|
199
|
-
}
|
|
200
|
-
const responseContentType = response.headers.get('content-type').toLowerCase();
|
|
201
|
-
// console.log('********** responseContentType *********', responseContentType);
|
|
202
|
-
if (responseContentType.startsWith('text/html')) {
|
|
203
|
-
// const htmlResponse = response.text();
|
|
204
|
-
// return new DOMParser().parseFromString(htmlResponse, 'text/html');
|
|
205
|
-
// return response.text();
|
|
206
|
-
return response.text().then(result =>
|
|
207
|
-
// console.log('xml ********', result);
|
|
208
|
-
new DOMParser().parseFromString(result, 'text/html'),
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
if (
|
|
212
|
-
responseContentType.startsWith('text/plain') ||
|
|
213
|
-
responseContentType.startsWith('text/markdown')
|
|
214
|
-
) {
|
|
215
|
-
// console.log("********** inside res plain *********");
|
|
216
|
-
return response.text();
|
|
217
|
-
}
|
|
218
|
-
if (responseContentType.startsWith('application/json')) {
|
|
219
|
-
// console.log("********** inside res json *********");
|
|
220
|
-
return response.json();
|
|
221
|
-
}
|
|
222
|
-
if (responseContentType.startsWith('application/xml')) {
|
|
223
|
-
return response.text().then(result =>
|
|
224
|
-
// console.log('xml ********', result);
|
|
225
|
-
new DOMParser().parseFromString(result, 'application/xml'),
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
return 'done';
|
|
229
|
-
})
|
|
230
|
-
.then(data => {
|
|
231
|
-
if (data.nodeType) {
|
|
232
|
-
this.instanceData = data;
|
|
233
|
-
console.log('instanceData loaded: ', this.id, this.instanceData);
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
this.instanceData = data;
|
|
237
|
-
})
|
|
238
|
-
.catch(error => {
|
|
239
|
-
throw new Error(`failed loading data ${error}`);
|
|
221
|
+
try {
|
|
222
|
+
const response = await fetch(url, {
|
|
223
|
+
method: 'GET',
|
|
224
|
+
mode: 'cors',
|
|
225
|
+
credentials: 'include',
|
|
226
|
+
headers: {
|
|
227
|
+
'Content-Type': contentType,
|
|
228
|
+
},
|
|
240
229
|
});
|
|
230
|
+
const { status } = response;
|
|
231
|
+
const data = await handleResponse(response);
|
|
232
|
+
if (data.nodeType) {
|
|
233
|
+
this.instanceData = data;
|
|
234
|
+
console.log('instanceData loaded: ', this.id, this.instanceData);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
this.instanceData = data;
|
|
238
|
+
} catch (error) {
|
|
239
|
+
throw new Error(`failed loading data ${error}`);
|
|
240
|
+
}
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
_getContentType() {
|
package/src/fx-model.js
CHANGED
|
@@ -95,7 +95,7 @@ export class FxModel extends HTMLElement {
|
|
|
95
95
|
* @event model-construct-done is fired once all instances have be loaded or after generating instance
|
|
96
96
|
*
|
|
97
97
|
*/
|
|
98
|
-
modelConstruct() {
|
|
98
|
+
async modelConstruct() {
|
|
99
99
|
// console.log('### <<<<< dispatching model-construct >>>>>');
|
|
100
100
|
// this.dispatchEvent(new CustomEvent('model-construct', { detail: this }));
|
|
101
101
|
Fore.dispatch(this, 'model-construct', {model: this});
|
|
@@ -109,17 +109,20 @@ export class FxModel extends HTMLElement {
|
|
|
109
109
|
promises.push(instance.init());
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
// Wait until all the instances are built
|
|
113
|
+
await Promise.all(promises);
|
|
114
|
+
|
|
115
|
+
this.instances = Array.from(instances);
|
|
116
|
+
// console.log('_modelConstruct this.instances ', this.instances);
|
|
117
|
+
// Await until the model-construct-done event is handled off
|
|
118
|
+
|
|
119
|
+
await Fore.dispatch(this, 'model-construct-done', {model: this});
|
|
120
|
+
this.inited = true;
|
|
121
|
+
this.updateModel();
|
|
119
122
|
console.groupEnd();
|
|
120
123
|
} else {
|
|
121
124
|
// ### if there's no instance one will created
|
|
122
|
-
this.dispatchEvent(
|
|
125
|
+
await this.dispatchEvent(
|
|
123
126
|
new CustomEvent('model-construct-done', {
|
|
124
127
|
composed: false,
|
|
125
128
|
bubbles: true,
|
|
@@ -387,14 +390,6 @@ export class FxModel extends HTMLElement {
|
|
|
387
390
|
modelItem.constraint = compute;
|
|
388
391
|
this.formElement.addToRefresh(modelItem); // let fore know that modelItem needs refresh
|
|
389
392
|
if (!compute) valid = false;
|
|
390
|
-
// ### alerts are added only once during model-construct. Otherwise they would add up in each run of revalidate()
|
|
391
|
-
if (!this.modelConstructed) {
|
|
392
|
-
// todo: get alert from attribute or child element
|
|
393
|
-
const alert = bind.getAlert();
|
|
394
|
-
if (alert) {
|
|
395
|
-
modelItem.addAlert(alert);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
393
|
}
|
|
399
394
|
}
|
|
400
395
|
if (typeof bind.hasAttribute === 'function' && bind.hasAttribute('required')) {
|