@jinntec/fore 1.2.0 → 1.4.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 +100 -72
- package/src/ForeElementMixin.js +4 -0
- package/src/actions/abstract-action.js +102 -18
- package/src/actions/fx-action.js +9 -10
- package/src/actions/fx-append.js +1 -1
- package/src/actions/fx-confirm.js +3 -3
- package/src/actions/fx-copy.js +68 -0
- package/src/actions/fx-delete.js +53 -62
- package/src/actions/fx-dispatch.js +1 -1
- package/src/actions/fx-hide.js +4 -2
- package/src/actions/fx-insert.js +1 -1
- package/src/actions/fx-message.js +26 -2
- package/src/actions/fx-refresh.js +2 -2
- package/src/actions/fx-reload.js +30 -0
- package/src/actions/fx-replace.js +1 -1
- package/src/actions/fx-return.js +1 -1
- package/src/actions/fx-send.js +13 -3
- package/src/actions/fx-setfocus.js +33 -6
- package/src/actions/fx-setvalue.js +5 -5
- package/src/actions/fx-show.js +2 -1
- package/src/actions/fx-toggle.js +6 -1
- package/src/actions/fx-update.js +1 -1
- package/src/events.js +24 -0
- package/src/fore.js +128 -17
- package/src/fx-bind.js +6 -1
- package/src/fx-fore.js +93 -41
- package/src/fx-instance.js +95 -70
- package/src/fx-model.js +430 -441
- package/src/fx-submission.js +423 -405
- package/src/getInScopeContext.js +88 -82
- package/src/modelitem.js +5 -3
- 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 +20 -8
- package/src/ui/fx-trigger.js +26 -19
- package/src/xpath-evaluation.js +49 -26
- package/src/xpath-util.js +26 -28
package/src/fore.js
CHANGED
|
@@ -9,8 +9,19 @@ 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 [
|
|
24
|
+
'FX-ACTION',
|
|
14
25
|
'FX-DELETE',
|
|
15
26
|
'FX-DISPATCH',
|
|
16
27
|
'FX-HIDE',
|
|
@@ -21,6 +32,7 @@ export class Fore {
|
|
|
21
32
|
'FX-RECALCULATE',
|
|
22
33
|
'FX-REFRESH',
|
|
23
34
|
'FX-RENEW',
|
|
35
|
+
'FX-RELOAD',
|
|
24
36
|
'FX-REPLACE',
|
|
25
37
|
'FX-RESET',
|
|
26
38
|
'FX-RETAIN',
|
|
@@ -64,16 +76,12 @@ export class Fore {
|
|
|
64
76
|
return [
|
|
65
77
|
'FX-ALERT',
|
|
66
78
|
'FX-CONTROL',
|
|
67
|
-
'FX-BUTTON',
|
|
68
|
-
'FX-CONTROL',
|
|
69
79
|
'FX-DIALOG',
|
|
70
80
|
'FX-FILENAME',
|
|
71
81
|
'FX-MEDIATYPE',
|
|
72
82
|
'FX-GROUP',
|
|
73
83
|
'FX-HINT',
|
|
74
|
-
'FX-INPUT',
|
|
75
84
|
'FX-ITEMS',
|
|
76
|
-
'FX-LABEL',
|
|
77
85
|
'FX-OUTPUT',
|
|
78
86
|
'FX-RANGE',
|
|
79
87
|
'FX-REPEAT',
|
|
@@ -89,6 +97,16 @@ export class Fore {
|
|
|
89
97
|
];
|
|
90
98
|
}
|
|
91
99
|
|
|
100
|
+
static get MODEL_ELEMENTS(){
|
|
101
|
+
return [
|
|
102
|
+
'FX-BIND',
|
|
103
|
+
'FX-FUNCTION',
|
|
104
|
+
'FX-MODEL',
|
|
105
|
+
'FX-INSTANCE',
|
|
106
|
+
'FX-SUBMISSION',
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
|
|
92
110
|
static isUiElement(elementName) {
|
|
93
111
|
const found = Fore.UI_ELEMENTS.includes(elementName);
|
|
94
112
|
if (found) {
|
|
@@ -133,7 +151,7 @@ export class Fore {
|
|
|
133
151
|
if (Fore.isUiElement(element.nodeName) && typeof element.refresh === 'function') {
|
|
134
152
|
// console.log('refreshing', element, element?.ref);
|
|
135
153
|
// console.log('refreshing ',element);
|
|
136
|
-
element.refresh();
|
|
154
|
+
element.refresh(force);
|
|
137
155
|
} else if (element.nodeName.toUpperCase() !== 'FX-MODEL') {
|
|
138
156
|
Fore.refreshChildren(element, force);
|
|
139
157
|
}
|
|
@@ -145,6 +163,61 @@ export class Fore {
|
|
|
145
163
|
return refreshed;
|
|
146
164
|
}
|
|
147
165
|
|
|
166
|
+
static copyDom(inputElement){
|
|
167
|
+
console.time('convert');
|
|
168
|
+
const target = new DOMParser().parseFromString('<fx-fore></fx-fore>', 'text/html');
|
|
169
|
+
console.log('copyDom new doc',target);
|
|
170
|
+
console.log('copyDom new body',target.body);
|
|
171
|
+
console.log('copyDom new body',target.querySelector('fx-fore'));
|
|
172
|
+
const newFore = target.querySelector('fx-fore');
|
|
173
|
+
this.convertFromSimple(inputElement,newFore);
|
|
174
|
+
newFore.removeAttribute('convert');
|
|
175
|
+
console.log('converted', newFore);
|
|
176
|
+
return newFore;
|
|
177
|
+
console.timeEnd('convert');
|
|
178
|
+
}
|
|
179
|
+
static convertFromSimple(startElement,targetElement){
|
|
180
|
+
const children = startElement.childNodes;
|
|
181
|
+
if (children) {
|
|
182
|
+
Array.from(children).forEach(node => {
|
|
183
|
+
const lookFor = `FX-${node.nodeName.toUpperCase()}`;
|
|
184
|
+
if (Fore.MODEL_ELEMENTS.includes(lookFor)
|
|
185
|
+
|| Fore.UI_ELEMENTS.includes(lookFor)
|
|
186
|
+
|| Fore.ACTION_ELEMENTS.includes(lookFor)
|
|
187
|
+
) {
|
|
188
|
+
const conv = targetElement.ownerDocument.createElement(lookFor);
|
|
189
|
+
console.log('conv', node, conv);
|
|
190
|
+
targetElement.appendChild(conv);
|
|
191
|
+
Fore.copyAttributes(node,conv);
|
|
192
|
+
Fore.convertFromSimple(node,conv);
|
|
193
|
+
} else{
|
|
194
|
+
|
|
195
|
+
if(node.nodeType === Node.TEXT_NODE){
|
|
196
|
+
const copied = targetElement.ownerDocument.createTextNode(node.textContent);
|
|
197
|
+
targetElement.appendChild(copied);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if(node.nodeType === Node.ELEMENT_NODE){
|
|
201
|
+
const copied = targetElement.ownerDocument.createElement(node.nodeName);
|
|
202
|
+
targetElement.appendChild(copied);
|
|
203
|
+
Fore.copyAttributes(node,targetElement);
|
|
204
|
+
Fore.convertFromSimple(node,copied);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
static copyAttributes(source, target) {
|
|
212
|
+
return Array.from(source.attributes).forEach(attribute => {
|
|
213
|
+
target.setAttribute(
|
|
214
|
+
attribute.nodeName,
|
|
215
|
+
attribute.nodeValue,
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
|
|
148
221
|
/**
|
|
149
222
|
* Alternative to `closest` that respects subcontrol boundaries
|
|
150
223
|
*/
|
|
@@ -168,8 +241,8 @@ export class Fore {
|
|
|
168
241
|
* @param instance an fx-instance element
|
|
169
242
|
* @returns {string|null}
|
|
170
243
|
*/
|
|
171
|
-
static getContentType(instance,
|
|
172
|
-
if (
|
|
244
|
+
static getContentType(instance, contentType) {
|
|
245
|
+
if (contentType === 'application/x-www-form-urlencoded') {
|
|
173
246
|
return 'application/x-www-form-urlencoded; charset=UTF-8';
|
|
174
247
|
}
|
|
175
248
|
if (instance.type === 'xml') {
|
|
@@ -222,14 +295,23 @@ export class Fore {
|
|
|
222
295
|
return fadeOut();
|
|
223
296
|
}
|
|
224
297
|
|
|
225
|
-
static dispatch(target, eventName, detail) {
|
|
298
|
+
static async dispatch(target, eventName, detail) {
|
|
226
299
|
const event = new CustomEvent(eventName, {
|
|
227
300
|
composed: false,
|
|
228
301
|
bubbles: true,
|
|
229
302
|
detail,
|
|
230
303
|
});
|
|
231
|
-
|
|
232
|
-
|
|
304
|
+
event.listenerPromises = [];
|
|
305
|
+
// console.info('dispatching', event.type, target);
|
|
306
|
+
// console.log('!!! DISPATCH_START', eventName);
|
|
307
|
+
|
|
308
|
+
target.dispatchEvent(event);
|
|
309
|
+
|
|
310
|
+
// By now, all listeners for the event should have registered their completion promises to us.
|
|
311
|
+
if (event.listenerPromises.length) {
|
|
312
|
+
await Promise.all(event.listenerPromises);
|
|
313
|
+
}
|
|
314
|
+
// console.log('!!! DISPATCH_DONE', eventName);
|
|
233
315
|
}
|
|
234
316
|
|
|
235
317
|
static prettifyXml(source) {
|
|
@@ -346,13 +428,42 @@ export class Fore {
|
|
|
346
428
|
}),
|
|
347
429
|
);
|
|
348
430
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
431
|
+
const imported = document.importNode(theFore,true);
|
|
432
|
+
console.log(`########## loaded fore as component ##### ${hostElement.url}`);
|
|
433
|
+
imported.addEventListener(
|
|
434
|
+
'model-construct-done',
|
|
435
|
+
e => {
|
|
436
|
+
console.log('subcomponent ready', e.target);
|
|
437
|
+
const defaultInst = imported.querySelector('fx-instance');
|
|
438
|
+
// console.log('defaultInst', defaultInst);
|
|
439
|
+
if(hostElement.initialNode){
|
|
440
|
+
const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
441
|
+
// Note: Clone the input to prevent the inner fore from editing the outer node
|
|
442
|
+
doc.firstElementChild.appendChild(hostElement.initialNode.cloneNode(true));
|
|
443
|
+
// defaultinst.setInstanceData(this.initialNode);
|
|
444
|
+
defaultInst.setInstanceData(doc);
|
|
445
|
+
}
|
|
446
|
+
// console.log('new data', defaultInst.getInstanceData());
|
|
447
|
+
// theFore.getModel().modelConstruct();
|
|
448
|
+
imported.getModel().updateModel();
|
|
449
|
+
imported.refresh();
|
|
450
|
+
return 'done';
|
|
451
|
+
|
|
452
|
+
},
|
|
453
|
+
{ once: true },
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
const dummy = hostElement.querySelector('input');
|
|
457
|
+
if (hostElement.hasAttribute('shadow')) {
|
|
458
|
+
dummy.parentNode.removeChild(dummy);
|
|
459
|
+
hostElement.shadowRoot.appendChild(imported);
|
|
460
|
+
} else {
|
|
461
|
+
console.log(this, 'replacing widget with',theFore);
|
|
462
|
+
dummy.replaceWith(imported);
|
|
463
|
+
// this.appendChild(imported);
|
|
464
|
+
}
|
|
354
465
|
})
|
|
355
|
-
|
|
466
|
+
/*.catch(error => {
|
|
356
467
|
hostElement.dispatchEvent(
|
|
357
468
|
new CustomEvent('error', {
|
|
358
469
|
composed: false,
|
|
@@ -363,7 +474,7 @@ export class Fore {
|
|
|
363
474
|
},
|
|
364
475
|
}),
|
|
365
476
|
);
|
|
366
|
-
})
|
|
477
|
+
});*/
|
|
367
478
|
}
|
|
368
479
|
|
|
369
480
|
/**
|
package/src/fx-bind.js
CHANGED
|
@@ -61,7 +61,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
61
61
|
*/
|
|
62
62
|
init(model) {
|
|
63
63
|
this.model = model;
|
|
64
|
-
console.log('init binding ', this);
|
|
64
|
+
// console.log('init binding ', this);
|
|
65
65
|
this.instanceId = this._getInstanceId();
|
|
66
66
|
this.bindType = this.getModel().getInstance(this.instanceId).type;
|
|
67
67
|
// console.log('binding type ', this.bindType);
|
|
@@ -320,6 +320,11 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
320
320
|
this,
|
|
321
321
|
);
|
|
322
322
|
|
|
323
|
+
const alert = this.getAlert();
|
|
324
|
+
if (alert) {
|
|
325
|
+
newItem.addAlert(alert);
|
|
326
|
+
}
|
|
327
|
+
|
|
323
328
|
this.getModel().registerModelItem(newItem);
|
|
324
329
|
}
|
|
325
330
|
|
package/src/fx-fore.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {Fore} from './fore.js';
|
|
2
2
|
import './fx-instance.js';
|
|
3
|
-
import './fx-model.js';
|
|
3
|
+
import {FxModel} from './fx-model.js';
|
|
4
4
|
import '@jinntec/jinn-toast';
|
|
5
|
-
import {evaluateXPathToNodes, evaluateXPathToString} from './xpath-evaluation.js';
|
|
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
8
|
|
|
@@ -14,9 +14,9 @@ import {XPathUtil} from './xpath-util.js';
|
|
|
14
14
|
* fx-fore is the outermost container for each form. A form can have exactly one model
|
|
15
15
|
* with arbitrary number of instances.
|
|
16
16
|
*
|
|
17
|
-
* Main
|
|
17
|
+
* Main responsibilities are initialization and updating of model and instances, update of UI (refresh) and global messaging.
|
|
18
18
|
*
|
|
19
|
-
* @event compute-exception - dispatched in case the dependency graph is
|
|
19
|
+
* @event compute-exception - dispatched in case the dependency graph is circular
|
|
20
20
|
* @event refresh-done - dispatched after a refresh() run
|
|
21
21
|
* @event ready - dispatched after Fore has fully been initialized
|
|
22
22
|
* @event error - dispatches error when template expression fails to evaluate
|
|
@@ -55,7 +55,7 @@ export class FxFore extends HTMLElement {
|
|
|
55
55
|
constructor() {
|
|
56
56
|
super();
|
|
57
57
|
this.model = {};
|
|
58
|
-
this.addEventListener('model-construct-done', this._handleModelConstructDone);
|
|
58
|
+
// this.addEventListener('model-construct-done', this._handleModelConstructDone);
|
|
59
59
|
this.addEventListener('message', this._displayMessage);
|
|
60
60
|
this.addEventListener('error', this._displayError);
|
|
61
61
|
window.addEventListener('compute-exception', e => {
|
|
@@ -67,19 +67,11 @@ export class FxFore extends HTMLElement {
|
|
|
67
67
|
|
|
68
68
|
const style = `
|
|
69
69
|
:host {
|
|
70
|
-
|
|
71
|
-
height:auto;
|
|
72
|
-
padding:var(--model-element-padding);
|
|
73
|
-
font-family:Roboto, sans-serif;
|
|
74
|
-
color:var(--paper-grey-900);
|
|
70
|
+
display: block;
|
|
75
71
|
}
|
|
76
72
|
:host ::slotted(fx-model){
|
|
77
73
|
display:none;
|
|
78
74
|
}
|
|
79
|
-
// :host(.fx-ready){
|
|
80
|
-
// animation: fadein .4s forwards;
|
|
81
|
-
// display:block;
|
|
82
|
-
// }
|
|
83
75
|
|
|
84
76
|
#modalMessage .dialogActions{
|
|
85
77
|
text-align:center;
|
|
@@ -143,14 +135,6 @@ export class FxFore extends HTMLElement {
|
|
|
143
135
|
#messageContent{
|
|
144
136
|
margin-top:40px;
|
|
145
137
|
}
|
|
146
|
-
@keyframes fadein {
|
|
147
|
-
0% {
|
|
148
|
-
opacity:0;
|
|
149
|
-
}
|
|
150
|
-
100% {
|
|
151
|
-
opacity:1;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
138
|
`;
|
|
155
139
|
|
|
156
140
|
const html = `
|
|
@@ -181,6 +165,8 @@ export class FxFore extends HTMLElement {
|
|
|
181
165
|
}
|
|
182
166
|
|
|
183
167
|
connectedCallback() {
|
|
168
|
+
this.style.visibility = 'hidden';
|
|
169
|
+
console.time('init');
|
|
184
170
|
/*
|
|
185
171
|
document.addEventListener('ready', (e) =>{
|
|
186
172
|
if(e.target !== this){
|
|
@@ -217,7 +203,15 @@ export class FxFore extends HTMLElement {
|
|
|
217
203
|
}
|
|
218
204
|
|
|
219
205
|
const slot = this.shadowRoot.querySelector('slot');
|
|
220
|
-
slot.addEventListener('slotchange', event => {
|
|
206
|
+
slot.addEventListener('slotchange', async event => {
|
|
207
|
+
|
|
208
|
+
// preliminary addition for auto-conversion of non-prefixed element into prefixed elements. See fore.js
|
|
209
|
+
if(this.hasAttribute('convert')){
|
|
210
|
+
this.replaceWith(Fore.copyDom(this));
|
|
211
|
+
// Fore.copyDom(this);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
221
215
|
const children = event.target.assignedElements();
|
|
222
216
|
let modelElement = children.find(
|
|
223
217
|
modelElem => modelElem.nodeName.toUpperCase() === 'FX-MODEL',
|
|
@@ -228,18 +222,21 @@ export class FxFore extends HTMLElement {
|
|
|
228
222
|
modelElement = generatedModel;
|
|
229
223
|
}
|
|
230
224
|
if (!modelElement.inited) {
|
|
231
|
-
console.
|
|
232
|
-
|
|
225
|
+
console.info(
|
|
226
|
+
`%cFore is processing URL ${window.location.href}`,
|
|
227
|
+
"background:#64b5f6; color:white; padding:1rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;",
|
|
233
228
|
);
|
|
229
|
+
|
|
234
230
|
if (this.src) {
|
|
235
231
|
console.log('########## FORE: loaded from ... ', this.src, '##########');
|
|
236
232
|
}
|
|
237
|
-
modelElement.modelConstruct();
|
|
233
|
+
await modelElement.modelConstruct();
|
|
234
|
+
this._handleModelConstructDone();
|
|
238
235
|
}
|
|
239
236
|
this.model = modelElement;
|
|
240
237
|
});
|
|
241
|
-
this.addEventListener('path-mutated',
|
|
242
|
-
console.log('path-mutated event received', e.detail.path, e.detail.index);
|
|
238
|
+
this.addEventListener('path-mutated', () => {
|
|
239
|
+
// console.log('path-mutated event received', e.detail.path, e.detail.index);
|
|
243
240
|
this.someInstanceDataStructureChanged = true;
|
|
244
241
|
});
|
|
245
242
|
}
|
|
@@ -287,7 +284,7 @@ export class FxFore extends HTMLElement {
|
|
|
287
284
|
|
|
288
285
|
// console.log('thefore', theFore)
|
|
289
286
|
if (!theFore) {
|
|
290
|
-
Fore.
|
|
287
|
+
Fore.dispatch(this, 'error', {
|
|
291
288
|
detail: {
|
|
292
289
|
message: `Fore element not found in '${this.src}'. Maybe wrapped within 'template' element?`,
|
|
293
290
|
},
|
|
@@ -311,9 +308,13 @@ export class FxFore extends HTMLElement {
|
|
|
311
308
|
*/
|
|
312
309
|
handleIntersect(entries, observer) {
|
|
313
310
|
console.time('refreshLazy');
|
|
311
|
+
|
|
314
312
|
entries.forEach(entry => {
|
|
315
313
|
const {target} = entry;
|
|
316
314
|
|
|
315
|
+
const fore = Fore.getFore(target);
|
|
316
|
+
if(fore.initialRun) return;
|
|
317
|
+
|
|
317
318
|
if (entry.isIntersecting) {
|
|
318
319
|
console.log('in view', entry);
|
|
319
320
|
// console.log('repeat in view entry', entry.target);
|
|
@@ -375,7 +376,8 @@ export class FxFore extends HTMLElement {
|
|
|
375
376
|
|
|
376
377
|
async refresh(force) {
|
|
377
378
|
// refresh () {
|
|
378
|
-
console.
|
|
379
|
+
console.info('%crefresh','font-style: italic; background: #8bc34a; color:white; padding:0.3rem 5rem 0.3rem 0.3rem; display:block; width:100%;');
|
|
380
|
+
console.group('refresh', force);
|
|
379
381
|
|
|
380
382
|
console.time('refresh');
|
|
381
383
|
|
|
@@ -393,7 +395,7 @@ export class FxFore extends HTMLElement {
|
|
|
393
395
|
const controlsToRefresh = modelItem.boundControls;
|
|
394
396
|
if (controlsToRefresh) {
|
|
395
397
|
controlsToRefresh.forEach(ctrl => {
|
|
396
|
-
ctrl.refresh();
|
|
398
|
+
ctrl.refresh(force);
|
|
397
399
|
});
|
|
398
400
|
}
|
|
399
401
|
|
|
@@ -409,7 +411,7 @@ export class FxFore extends HTMLElement {
|
|
|
409
411
|
const modelItemOfDep = this.getModel().modelItems.find(mip => mip.path === basePath);
|
|
410
412
|
// ### refresh all boundControls
|
|
411
413
|
modelItemOfDep.boundControls.forEach(control => {
|
|
412
|
-
control.refresh();
|
|
414
|
+
control.refresh(force);
|
|
413
415
|
});
|
|
414
416
|
});
|
|
415
417
|
needsRefresh = true;
|
|
@@ -418,7 +420,7 @@ export class FxFore extends HTMLElement {
|
|
|
418
420
|
});
|
|
419
421
|
this.toRefresh = [];
|
|
420
422
|
if (!needsRefresh) {
|
|
421
|
-
console.log('
|
|
423
|
+
console.log('no dependants to refresh');
|
|
422
424
|
}
|
|
423
425
|
} else {
|
|
424
426
|
Fore.refreshChildren(this, true);
|
|
@@ -437,6 +439,8 @@ export class FxFore extends HTMLElement {
|
|
|
437
439
|
console.groupEnd();
|
|
438
440
|
// console.log('### <<<<< dispatching refresh-done - end of UI update cycle >>>>>');
|
|
439
441
|
// this.dispatchEvent(new CustomEvent('refresh-done'));
|
|
442
|
+
// this.initialRun = false;
|
|
443
|
+
this.style.visibility='visible';
|
|
440
444
|
Fore.dispatch(this, 'refresh-done', {});
|
|
441
445
|
}
|
|
442
446
|
|
|
@@ -449,9 +453,8 @@ export class FxFore extends HTMLElement {
|
|
|
449
453
|
* @private
|
|
450
454
|
*/
|
|
451
455
|
_updateTemplateExpressions() {
|
|
452
|
-
// Note the fact we're going over HTML here: therefore the `html` prefix.
|
|
453
456
|
const search =
|
|
454
|
-
"(descendant-or-self
|
|
457
|
+
"(descendant-or-self::*!(text(), @*))[contains(., '{')][substring-after(., '{') => contains('}')][not(ancestor-or-self::fx-model)]";
|
|
455
458
|
|
|
456
459
|
const tmplExpressions = evaluateXPathToNodes(search, this, this);
|
|
457
460
|
// console.log('template expressions found ', tmplExpressions);
|
|
@@ -482,7 +485,18 @@ export class FxFore extends HTMLElement {
|
|
|
482
485
|
}
|
|
483
486
|
|
|
484
487
|
_processTemplateExpressions() {
|
|
485
|
-
for (const node of this.storedTemplateExpressionByNode.keys()) {
|
|
488
|
+
for (const node of Array.from(this.storedTemplateExpressionByNode.keys())) {
|
|
489
|
+
if (node.nodeType === Node.ATTRIBUTE_NODE) {
|
|
490
|
+
// Attribute nodes are not contained by the document, but their owner elements are!
|
|
491
|
+
if (!node.ownerDocument.contains(node.ownerElement)) {
|
|
492
|
+
this.storedTemplateExpressionByNode.delete(node);
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
} else if (!node.ownerDocument.contains(node)) {
|
|
496
|
+
// For all other nodes, if the document does not contain them, they are dead
|
|
497
|
+
this.storedTemplateExpressionByNode.delete(node);
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
486
500
|
this._processTemplateExpression({
|
|
487
501
|
node,
|
|
488
502
|
expr: this.storedTemplateExpressionByNode.get(node),
|
|
@@ -497,7 +511,7 @@ export class FxFore extends HTMLElement {
|
|
|
497
511
|
const {expr} = exprObj;
|
|
498
512
|
const {node} = exprObj;
|
|
499
513
|
// console.log('expr ', expr);
|
|
500
|
-
this.evaluateTemplateExpression(expr, node
|
|
514
|
+
this.evaluateTemplateExpression(expr, node);
|
|
501
515
|
}
|
|
502
516
|
|
|
503
517
|
/**
|
|
@@ -552,11 +566,43 @@ export class FxFore extends HTMLElement {
|
|
|
552
566
|
|
|
553
567
|
/**
|
|
554
568
|
* called when `model-construct-done` event is received to
|
|
555
|
-
* start initing
|
|
569
|
+
* start initing the UI.
|
|
556
570
|
*
|
|
557
571
|
* @private
|
|
558
572
|
*/
|
|
559
573
|
_handleModelConstructDone() {
|
|
574
|
+
/*
|
|
575
|
+
listening on beforeunload after model is constructed - this is to be able to evaluate a condition on the data
|
|
576
|
+
that specifies whether or not to show confirmation.
|
|
577
|
+
*/
|
|
578
|
+
if(this.hasAttribute('show-confirmation')){
|
|
579
|
+
const condition = this.getAttribute('show-confirmation');
|
|
580
|
+
if(condition
|
|
581
|
+
&& condition !== 'show-confirmation'
|
|
582
|
+
&& condition !== 'true'
|
|
583
|
+
&& condition !== ''){
|
|
584
|
+
window.addEventListener('beforeunload', event => {
|
|
585
|
+
const mustDisplay = evaluateXPathToBoolean(condition, this.getModel().getDefaultContext(), this)
|
|
586
|
+
if(mustDisplay){
|
|
587
|
+
console.log('have to display confirmation')
|
|
588
|
+
return event.returnValue = 'are you sure';
|
|
589
|
+
}
|
|
590
|
+
event.preventDefault();
|
|
591
|
+
console.log('do not display confirmation')
|
|
592
|
+
})
|
|
593
|
+
}else{
|
|
594
|
+
window.addEventListener('beforeunload', event => {
|
|
595
|
+
// if(AbstractAction.dataChanged){
|
|
596
|
+
if(FxModel.dataChanged){
|
|
597
|
+
console.log('have to display confirmation')
|
|
598
|
+
return event.returnValue = 'are you sure';
|
|
599
|
+
}
|
|
600
|
+
event.preventDefault();
|
|
601
|
+
console.log('do not display confirmation')
|
|
602
|
+
})
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
560
606
|
this._initUI();
|
|
561
607
|
}
|
|
562
608
|
|
|
@@ -700,7 +746,8 @@ export class FxFore extends HTMLElement {
|
|
|
700
746
|
};
|
|
701
747
|
*/
|
|
702
748
|
|
|
703
|
-
|
|
749
|
+
// First refresh should be forced
|
|
750
|
+
await this.refresh(true);
|
|
704
751
|
// this.style.display='block'
|
|
705
752
|
this.classList.add('fx-ready');
|
|
706
753
|
document.body.classList.add('fx-ready');
|
|
@@ -708,9 +755,14 @@ export class FxFore extends HTMLElement {
|
|
|
708
755
|
this.ready = true;
|
|
709
756
|
this.initialRun = false;
|
|
710
757
|
// console.log('### >>>>> dispatching ready >>>>>', this);
|
|
711
|
-
console.log('### modelItems: ', this.getModel().modelItems);
|
|
712
|
-
console.log('### <<<<< FORE: form fully initialized...', this);
|
|
758
|
+
// console.log('### modelItems: ', this.getModel().modelItems);
|
|
713
759
|
Fore.dispatch(this, 'ready', {});
|
|
760
|
+
console.info(
|
|
761
|
+
`%cPage Initialization done`,
|
|
762
|
+
"background:#64b5f6; color:white; padding:1rem; display:block; white-space: nowrap; border-radius:0.3rem;width:100%;",
|
|
763
|
+
);
|
|
764
|
+
console.timeEnd('init');
|
|
765
|
+
console.log('dataChanged', FxModel.dataChanged);
|
|
714
766
|
}
|
|
715
767
|
|
|
716
768
|
registerLazyElement(element) {
|