@jinntec/fore 1.5.0 → 1.7.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 +2 -36
- package/dist/fore-dev.js.map +1 -1
- package/dist/fore.js +2 -30
- package/dist/fore.js.map +1 -1
- package/index.js +13 -0
- package/package.json +9 -5
- package/resources/fore.css +178 -92
- package/src/DependencyNotifyingDomFacade.js +1 -2
- package/src/ForeElementMixin.js +31 -5
- package/src/actions/abstract-action.js +379 -297
- package/src/actions/fx-action.js +0 -1
- package/src/actions/fx-append.js +1 -2
- package/src/actions/fx-confirm.js +12 -0
- package/src/actions/fx-copy.js +0 -1
- package/src/actions/fx-delete.js +31 -9
- package/src/actions/fx-dispatch.js +19 -5
- package/src/actions/fx-hide.js +19 -0
- package/src/actions/fx-insert.js +72 -8
- package/src/actions/fx-load.js +253 -0
- package/src/actions/fx-message.js +22 -7
- package/src/actions/fx-refresh.js +11 -1
- package/src/actions/fx-reload.js +12 -2
- package/src/actions/fx-replace.js +5 -4
- package/src/actions/fx-reset.js +48 -0
- package/src/actions/fx-return.js +0 -1
- package/src/actions/fx-send.js +40 -2
- package/src/actions/fx-setfocus.js +25 -7
- package/src/actions/fx-setvalue.js +32 -4
- package/src/actions/fx-show.js +14 -2
- package/src/actions/fx-toggle.js +0 -1
- package/src/actions/fx-toggleboolean.js +58 -0
- package/src/actions/fx-update.js +9 -0
- package/src/events.js +0 -1
- package/src/fore.js +118 -63
- package/src/functions/common-function.js +28 -0
- package/src/fx-bind.js +9 -7
- package/src/fx-fore.js +153 -55
- package/src/fx-instance.js +55 -17
- package/src/fx-model.js +31 -33
- package/src/fx-submission.js +50 -47
- package/src/getInScopeContext.js +8 -10
- package/src/lab/fore-component.js +90 -0
- package/src/lab/instance-inspector.js +56 -0
- package/src/lab/template.html +16 -0
- package/src/relevance.js +27 -1
- package/src/tools/adi.js +1056 -0
- package/src/tools/fx-action-log.js +662 -0
- package/src/tools/fx-devtools.js +444 -0
- package/src/tools/fx-dom-inspector.js +609 -0
- package/src/tools/fx-json-instance.js +435 -0
- package/src/tools/fx-log-item.js +133 -0
- package/src/tools/fx-log-settings.js +474 -0
- package/src/tools/fx-minimap.js +194 -0
- package/src/tools/helpers.js +132 -0
- package/src/ui/abstract-control.js +41 -3
- package/src/ui/fx-alert.js +0 -1
- package/src/ui/fx-container.js +14 -3
- package/src/ui/fx-control.js +553 -474
- package/src/ui/fx-dialog.js +2 -0
- package/src/ui/fx-dom-inspector.js +1255 -0
- package/src/ui/fx-group.js +3 -4
- package/src/ui/fx-hint.js +2 -4
- package/src/ui/fx-inspector.js +5 -6
- package/src/ui/fx-items.js +55 -14
- package/src/ui/fx-output.js +36 -17
- package/src/ui/fx-repeat-attributes.js +10 -43
- package/src/ui/fx-repeat.js +5 -7
- package/src/ui/fx-switch.js +14 -3
- package/src/ui/fx-trigger.js +13 -1
- package/src/xpath-evaluation.js +109 -26
- package/src/xpath-util.js +55 -1
package/src/fx-fore.js
CHANGED
|
@@ -2,10 +2,9 @@ import {Fore} from './fore.js';
|
|
|
2
2
|
import './fx-instance.js';
|
|
3
3
|
import {FxModel} from './fx-model.js';
|
|
4
4
|
import '@jinntec/jinn-toast';
|
|
5
|
-
import {evaluateXPathToBoolean, evaluateXPathToNodes, evaluateXPathToString} from './xpath-evaluation.js';
|
|
5
|
+
import {evaluateXPathToBoolean, evaluateXPathToNodes, evaluateXPathToFirstNode, evaluateXPathToString} from './xpath-evaluation.js';
|
|
6
6
|
import getInScopeContext from './getInScopeContext.js';
|
|
7
7
|
import {XPathUtil} from './xpath-util.js';
|
|
8
|
-
// import {FxRepeat} from "./ui/fx-repeat";
|
|
9
8
|
import {FxRepeatAttributes} from './ui/fx-repeat-attributes.js';
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -26,6 +25,8 @@ import {FxRepeatAttributes} from './ui/fx-repeat-attributes.js';
|
|
|
26
25
|
* @ts-check
|
|
27
26
|
*/
|
|
28
27
|
export class FxFore extends HTMLElement {
|
|
28
|
+
static outermostHandler = null;
|
|
29
|
+
|
|
29
30
|
static get properties() {
|
|
30
31
|
return {
|
|
31
32
|
/**
|
|
@@ -43,6 +44,12 @@ export class FxFore extends HTMLElement {
|
|
|
43
44
|
ready: {
|
|
44
45
|
type: Boolean,
|
|
45
46
|
},
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
validateOn: {
|
|
51
|
+
type: String
|
|
52
|
+
}
|
|
46
53
|
};
|
|
47
54
|
}
|
|
48
55
|
|
|
@@ -57,9 +64,13 @@ export class FxFore extends HTMLElement {
|
|
|
57
64
|
constructor() {
|
|
58
65
|
super();
|
|
59
66
|
this.model = {};
|
|
67
|
+
this.inited=false;
|
|
60
68
|
// this.addEventListener('model-construct-done', this._handleModelConstructDone);
|
|
69
|
+
// todo: refactoring - these should rather go into connectedcallback
|
|
61
70
|
this.addEventListener('message', this._displayMessage);
|
|
62
71
|
this.addEventListener('error', this._displayError);
|
|
72
|
+
this.addEventListener('warn', this._displayWarning);
|
|
73
|
+
this.addEventListener('log', this._logError);
|
|
63
74
|
window.addEventListener('compute-exception', e => {
|
|
64
75
|
console.error('circular dependency: ', e);
|
|
65
76
|
});
|
|
@@ -67,6 +78,10 @@ export class FxFore extends HTMLElement {
|
|
|
67
78
|
this.ready = false;
|
|
68
79
|
this.storedTemplateExpressionByNode = new Map();
|
|
69
80
|
|
|
81
|
+
// Stores the outer most action handler. If an action handler is already running, all
|
|
82
|
+
// updates are included in that one
|
|
83
|
+
this.outermostHandler = null;
|
|
84
|
+
|
|
70
85
|
const style = `
|
|
71
86
|
:host {
|
|
72
87
|
display: block;
|
|
@@ -137,13 +152,20 @@ export class FxFore extends HTMLElement {
|
|
|
137
152
|
#messageContent{
|
|
138
153
|
margin-top:40px;
|
|
139
154
|
}
|
|
155
|
+
.warning{
|
|
156
|
+
background:orange;
|
|
157
|
+
}
|
|
140
158
|
`;
|
|
141
159
|
|
|
142
160
|
const html = `
|
|
161
|
+
<noscript>This page uses Web Components and needs JavaScript to be enabled..</noscript>
|
|
162
|
+
|
|
143
163
|
<jinn-toast id="message" gravity="bottom" position="left"></jinn-toast>
|
|
144
164
|
<jinn-toast id="sticky" gravity="bottom" position="left" duration="-1" close="true" data-class="sticky-message"></jinn-toast>
|
|
145
|
-
<jinn-toast id="error" text="error" duration="-1" data-class="error" close="true" position="left" gravity="bottom"></jinn-toast>
|
|
146
|
-
<
|
|
165
|
+
<jinn-toast id="error" text="error" duration="-1" data-class="error" close="true" position="left" gravity="bottom" escape-markup="false"></jinn-toast>
|
|
166
|
+
<jinn-toast id="warn" text="warning" duration="-1" data-class="warning" close="true" position="right" gravity="bottom"></jinn-toast>
|
|
167
|
+
<slot id="default"></slot>
|
|
168
|
+
<slot name="messages"></slot>
|
|
147
169
|
<div id="modalMessage" class="overlay">
|
|
148
170
|
<div class="popup">
|
|
149
171
|
<h2></h2>
|
|
@@ -151,6 +173,7 @@ export class FxFore extends HTMLElement {
|
|
|
151
173
|
<div id="messageContent"></div>
|
|
152
174
|
</div>
|
|
153
175
|
</div>
|
|
176
|
+
<slot name="event"></slot>
|
|
154
177
|
`;
|
|
155
178
|
|
|
156
179
|
this.attachShadow({mode: 'open'});
|
|
@@ -165,6 +188,7 @@ export class FxFore extends HTMLElement {
|
|
|
165
188
|
this.initialRun = true;
|
|
166
189
|
this.someInstanceDataStructureChanged = false;
|
|
167
190
|
this.repeatsFromAttributesCreated = false;
|
|
191
|
+
this.validateOn = this.hasAttribute('validate-on') ? this.getAttribute('validate-on'):'update';
|
|
168
192
|
}
|
|
169
193
|
|
|
170
194
|
connectedCallback() {
|
|
@@ -205,10 +229,12 @@ export class FxFore extends HTMLElement {
|
|
|
205
229
|
return;
|
|
206
230
|
}
|
|
207
231
|
|
|
208
|
-
|
|
209
|
-
slot.addEventListener('slotchange', async event => {
|
|
232
|
+
this._injectDevtools();
|
|
210
233
|
|
|
234
|
+
const slot = this.shadowRoot.querySelector('slot#default');
|
|
235
|
+
slot.addEventListener('slotchange', async event => {
|
|
211
236
|
// preliminary addition for auto-conversion of non-prefixed element into prefixed elements. See fore.js
|
|
237
|
+
if(this.inited) return;
|
|
212
238
|
if(this.hasAttribute('convert')){
|
|
213
239
|
this.replaceWith(Fore.copyDom(this));
|
|
214
240
|
// Fore.copyDom(this);
|
|
@@ -223,6 +249,9 @@ export class FxFore extends HTMLElement {
|
|
|
223
249
|
const generatedModel = document.createElement('fx-model');
|
|
224
250
|
this.appendChild(generatedModel);
|
|
225
251
|
modelElement = generatedModel;
|
|
252
|
+
// We are going to get a new slotchange event immediately, because we changed a slot.
|
|
253
|
+
// so cancel this one.
|
|
254
|
+
return;
|
|
226
255
|
}
|
|
227
256
|
if (!modelElement.inited) {
|
|
228
257
|
console.info(
|
|
@@ -230,23 +259,33 @@ export class FxFore extends HTMLElement {
|
|
|
230
259
|
"background:#64b5f6; color:white; padding:1rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;",
|
|
231
260
|
);
|
|
232
261
|
|
|
233
|
-
if (this.src) {
|
|
234
|
-
console.log('########## FORE: loaded from ... ', this.src, '##########');
|
|
235
|
-
}
|
|
236
262
|
await modelElement.modelConstruct();
|
|
237
263
|
this._handleModelConstructDone();
|
|
238
264
|
}
|
|
239
265
|
this.model = modelElement;
|
|
240
266
|
|
|
241
267
|
this._createRepeatsFromAttributes();
|
|
268
|
+
this.inited = true;
|
|
242
269
|
|
|
243
270
|
});
|
|
244
271
|
this.addEventListener('path-mutated', () => {
|
|
245
|
-
// console.log('path-mutated event received', e.detail.path, e.detail.index);
|
|
246
272
|
this.someInstanceDataStructureChanged = true;
|
|
247
273
|
});
|
|
248
274
|
}
|
|
249
275
|
|
|
276
|
+
_injectDevtools(){
|
|
277
|
+
if (this.ownerDocument.querySelector('fx-devtools')) {
|
|
278
|
+
// There's already a devtools, so we can ignore this one.
|
|
279
|
+
// One devtools can focus multiple fore elements
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const search = window.location.search;
|
|
283
|
+
const urlParams = new URLSearchParams(search);
|
|
284
|
+
if(urlParams.has('inspect')){
|
|
285
|
+
const devtools = document.createElement('fx-devtools');
|
|
286
|
+
document.body.appendChild(devtools);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
250
289
|
addToRefresh(modelItem) {
|
|
251
290
|
const found = this.toRefresh.find(mi => mi.path === modelItem.path);
|
|
252
291
|
if (!found) {
|
|
@@ -261,7 +300,7 @@ export class FxFore extends HTMLElement {
|
|
|
261
300
|
* @private
|
|
262
301
|
*/
|
|
263
302
|
_loadFromSrc() {
|
|
264
|
-
console.log('########## loading Fore from ', this.src, '##########');
|
|
303
|
+
// console.log('########## loading Fore from ', this.src, '##########');
|
|
265
304
|
fetch(this.src, {
|
|
266
305
|
method: 'GET',
|
|
267
306
|
mode: 'cors',
|
|
@@ -297,6 +336,12 @@ export class FxFore extends HTMLElement {
|
|
|
297
336
|
});
|
|
298
337
|
}
|
|
299
338
|
theFore.setAttribute('from-src', this.src);
|
|
339
|
+
const thisAttrs = this.attributes;
|
|
340
|
+
Array.from(thisAttrs).forEach(attr =>{
|
|
341
|
+
if(attr.name !== 'src'){
|
|
342
|
+
theFore.setAttribute(attr.name,attr.value);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
300
345
|
this.replaceWith(theFore);
|
|
301
346
|
})
|
|
302
347
|
.catch(() => {
|
|
@@ -313,7 +358,7 @@ export class FxFore extends HTMLElement {
|
|
|
313
358
|
* @param observer
|
|
314
359
|
*/
|
|
315
360
|
handleIntersect(entries, observer) {
|
|
316
|
-
console.time('refreshLazy');
|
|
361
|
+
// console.time('refreshLazy');
|
|
317
362
|
|
|
318
363
|
entries.forEach(entry => {
|
|
319
364
|
const {target} = entry;
|
|
@@ -322,7 +367,7 @@ export class FxFore extends HTMLElement {
|
|
|
322
367
|
if(fore.initialRun) return;
|
|
323
368
|
|
|
324
369
|
if (entry.isIntersecting) {
|
|
325
|
-
console.log('in view', entry);
|
|
370
|
+
// console.log('in view', entry);
|
|
326
371
|
// console.log('repeat in view entry', entry.target);
|
|
327
372
|
// const target = entry.target;
|
|
328
373
|
// if(target.hasAttribute('refresh-on-view')){
|
|
@@ -331,17 +376,17 @@ export class FxFore extends HTMLElement {
|
|
|
331
376
|
|
|
332
377
|
// todo: too restrictive here? what if target is a usual html element? shouldn't it refresh downwards?
|
|
333
378
|
if (typeof target.refresh === 'function') {
|
|
334
|
-
console.log('refreshing target', target);
|
|
379
|
+
// console.log('refreshing target', target);
|
|
335
380
|
target.refresh(target, true);
|
|
336
381
|
} else {
|
|
337
|
-
console.log('refreshing children', target);
|
|
382
|
+
// console.log('refreshing children', target);
|
|
338
383
|
Fore.refreshChildren(target, true);
|
|
339
384
|
}
|
|
340
385
|
}
|
|
341
386
|
});
|
|
342
387
|
entries[0].target.getOwnerForm().dispatchEvent(new CustomEvent('refresh-done'));
|
|
343
388
|
|
|
344
|
-
console.timeEnd('refreshLazy');
|
|
389
|
+
// console.timeEnd('refreshLazy');
|
|
345
390
|
}
|
|
346
391
|
|
|
347
392
|
evaluateToNodes(xpath, context) {
|
|
@@ -367,8 +412,8 @@ export class FxFore extends HTMLElement {
|
|
|
367
412
|
*
|
|
368
413
|
*/
|
|
369
414
|
async forceRefresh() {
|
|
370
|
-
console.time('refresh');
|
|
371
|
-
console.group('### forced refresh', this);
|
|
415
|
+
// console.time('refresh');
|
|
416
|
+
// console.group('### forced refresh', this);
|
|
372
417
|
|
|
373
418
|
Fore.refreshChildren(this, true);
|
|
374
419
|
this._updateTemplateExpressions();
|
|
@@ -376,23 +421,16 @@ export class FxFore extends HTMLElement {
|
|
|
376
421
|
this._processTemplateExpressions();
|
|
377
422
|
Fore.dispatch(this, 'refresh-done', {});
|
|
378
423
|
|
|
379
|
-
console.groupEnd();
|
|
380
|
-
console.timeEnd('refresh');
|
|
424
|
+
// console.groupEnd();
|
|
425
|
+
// console.timeEnd('refresh');
|
|
381
426
|
}
|
|
382
427
|
|
|
383
428
|
async refresh(force) {
|
|
384
429
|
// refresh () {
|
|
385
|
-
console.info('%crefresh','font-style: italic; background: #8bc34a; color:white; padding:0.3rem 5rem 0.3rem 0.3rem; display:block; width:100%;');
|
|
386
|
-
console.group('refresh', force);
|
|
387
|
-
|
|
388
|
-
console.time('refresh');
|
|
389
|
-
|
|
390
430
|
// ### refresh Fore UI elements
|
|
391
|
-
// console.time('refreshChildren');
|
|
392
|
-
console.log('toRefresh', this.toRefresh);
|
|
393
|
-
|
|
394
431
|
// if (!this.initialRun && this.toRefresh.length !== 0) {
|
|
395
432
|
if (!force && !this.initialRun && this.toRefresh.length !== 0) {
|
|
433
|
+
// console.log('toRefresh', this.toRefresh);
|
|
396
434
|
let needsRefresh = false;
|
|
397
435
|
|
|
398
436
|
// ### after recalculation the changed modelItems are copied to 'toRefresh' array for processing
|
|
@@ -425,10 +463,20 @@ export class FxFore extends HTMLElement {
|
|
|
425
463
|
}
|
|
426
464
|
});
|
|
427
465
|
this.toRefresh = [];
|
|
466
|
+
/*
|
|
428
467
|
if (!needsRefresh) {
|
|
429
468
|
console.log('no dependants to refresh');
|
|
430
469
|
}
|
|
470
|
+
*/
|
|
431
471
|
} else {
|
|
472
|
+
// ### resetting visited state for controls to refresh
|
|
473
|
+
/*
|
|
474
|
+
const visited = this.parentNode.querySelectorAll('.visited');
|
|
475
|
+
Array.from(visited).forEach(v =>{
|
|
476
|
+
v.classList.remove('visited');
|
|
477
|
+
});
|
|
478
|
+
*/
|
|
479
|
+
|
|
432
480
|
Fore.refreshChildren(this, true);
|
|
433
481
|
// console.timeEnd('refreshChildren');
|
|
434
482
|
}
|
|
@@ -440,9 +488,6 @@ export class FxFore extends HTMLElement {
|
|
|
440
488
|
}
|
|
441
489
|
this._processTemplateExpressions();
|
|
442
490
|
|
|
443
|
-
console.timeEnd('refresh');
|
|
444
|
-
|
|
445
|
-
console.groupEnd();
|
|
446
491
|
// console.log('### <<<<< dispatching refresh-done - end of UI update cycle >>>>>');
|
|
447
492
|
// this.dispatchEvent(new CustomEvent('refresh-done'));
|
|
448
493
|
// this.initialRun = false;
|
|
@@ -494,12 +539,12 @@ export class FxFore extends HTMLElement {
|
|
|
494
539
|
for (const node of Array.from(this.storedTemplateExpressionByNode.keys())) {
|
|
495
540
|
if (node.nodeType === Node.ATTRIBUTE_NODE) {
|
|
496
541
|
// Attribute nodes are not contained by the document, but their owner elements are!
|
|
497
|
-
if (!
|
|
542
|
+
if (!XPathUtil.contains(this, node.ownerElement)) {
|
|
498
543
|
this.storedTemplateExpressionByNode.delete(node);
|
|
499
544
|
continue;
|
|
500
545
|
}
|
|
501
|
-
} else if (!
|
|
502
|
-
// For all other nodes, if
|
|
546
|
+
} else if (!XPathUtil.contains(this, node)) {
|
|
547
|
+
// For all other nodes, if this `fore` element does not contain them, they are dead
|
|
503
548
|
this.storedTemplateExpressionByNode.delete(node);
|
|
504
549
|
continue;
|
|
505
550
|
}
|
|
@@ -521,10 +566,9 @@ export class FxFore extends HTMLElement {
|
|
|
521
566
|
}
|
|
522
567
|
|
|
523
568
|
/**
|
|
524
|
-
* evaluate a template expression
|
|
525
|
-
* @param
|
|
569
|
+
* evaluate a template expression on a node either text- or attribute node.
|
|
570
|
+
* @param expr The string to parse for expressions
|
|
526
571
|
* @param node the node which will get updated with evaluation result
|
|
527
|
-
* @param form the form element
|
|
528
572
|
*/
|
|
529
573
|
evaluateTemplateExpression(expr, node) {
|
|
530
574
|
const replaced = expr.replace(/{[^}]*}/g, match => {
|
|
@@ -542,11 +586,15 @@ export class FxFore extends HTMLElement {
|
|
|
542
586
|
// Templates are special: they use the namespace configuration from the place where they are
|
|
543
587
|
// being defined
|
|
544
588
|
const instanceId = XPathUtil.getInstanceId(naked);
|
|
545
|
-
|
|
546
|
-
|
|
589
|
+
|
|
590
|
+
// If there is an instance referred
|
|
591
|
+
const inst = instanceId ? this.getModel().getInstance(instanceId) : this.getModel().getDefaultInstance();
|
|
592
|
+
|
|
593
|
+
try {
|
|
547
594
|
return evaluateXPathToString(naked, inscope, node, null, inst);
|
|
548
595
|
} catch (error) {
|
|
549
|
-
console.
|
|
596
|
+
console.warn('ignoring unparseable expr', error);
|
|
597
|
+
|
|
550
598
|
return match;
|
|
551
599
|
}
|
|
552
600
|
});
|
|
@@ -590,21 +638,17 @@ export class FxFore extends HTMLElement {
|
|
|
590
638
|
window.addEventListener('beforeunload', event => {
|
|
591
639
|
const mustDisplay = evaluateXPathToBoolean(condition, this.getModel().getDefaultContext(), this)
|
|
592
640
|
if(mustDisplay){
|
|
593
|
-
console.log('have to display confirmation')
|
|
594
641
|
return event.returnValue = 'are you sure';
|
|
595
642
|
}
|
|
596
643
|
event.preventDefault();
|
|
597
|
-
console.log('do not display confirmation')
|
|
598
644
|
})
|
|
599
645
|
}else{
|
|
600
646
|
window.addEventListener('beforeunload', event => {
|
|
601
647
|
// if(AbstractAction.dataChanged){
|
|
602
648
|
if(FxModel.dataChanged){
|
|
603
|
-
console.log('have to display confirmation')
|
|
604
649
|
return event.returnValue = 'are you sure';
|
|
605
650
|
}
|
|
606
651
|
event.preventDefault();
|
|
607
|
-
console.log('do not display confirmation')
|
|
608
652
|
})
|
|
609
653
|
}
|
|
610
654
|
}
|
|
@@ -622,7 +666,7 @@ export class FxFore extends HTMLElement {
|
|
|
622
666
|
async _lazyCreateInstance() {
|
|
623
667
|
const model = this.querySelector('fx-model');
|
|
624
668
|
if (model.instances.length === 0) {
|
|
625
|
-
console.log('### lazy creation of instance');
|
|
669
|
+
// console.log('### lazy creation of instance');
|
|
626
670
|
const generatedInstance = document.createElement('fx-instance');
|
|
627
671
|
model.appendChild(generatedInstance);
|
|
628
672
|
|
|
@@ -631,7 +675,8 @@ export class FxFore extends HTMLElement {
|
|
|
631
675
|
this._generateInstance(this, generated.firstElementChild);
|
|
632
676
|
generatedInstance.instanceData = generated;
|
|
633
677
|
model.instances.push(generatedInstance);
|
|
634
|
-
console.log('generatedInstance ', this.getModel().getDefaultInstanceData());
|
|
678
|
+
// console.log('generatedInstance ', this.getModel().getDefaultInstanceData());
|
|
679
|
+
Fore.dispatch(this,'instance-loaded',{instance:this})
|
|
635
680
|
}
|
|
636
681
|
}
|
|
637
682
|
|
|
@@ -644,11 +689,9 @@ export class FxFore extends HTMLElement {
|
|
|
644
689
|
const ref = start.getAttribute('ref');
|
|
645
690
|
|
|
646
691
|
if (ref.includes('/')) {
|
|
647
|
-
console.log('complex path to create ', ref);
|
|
692
|
+
// console.log('complex path to create ', ref);
|
|
648
693
|
const steps = ref.split('/');
|
|
649
694
|
steps.forEach(step => {
|
|
650
|
-
console.log('step ', step);
|
|
651
|
-
|
|
652
695
|
// const generated = document.createElement(ref);
|
|
653
696
|
parent = this._generateNode(parent, step, start);
|
|
654
697
|
});
|
|
@@ -728,8 +771,9 @@ export class FxFore extends HTMLElement {
|
|
|
728
771
|
* @private
|
|
729
772
|
*/
|
|
730
773
|
async _initUI() {
|
|
731
|
-
console.log('### _initUI()');
|
|
774
|
+
// console.log('### _initUI()');
|
|
732
775
|
if (!this.initialRun) return;
|
|
776
|
+
this.classList.add('initialRun');
|
|
733
777
|
await this._lazyCreateInstance();
|
|
734
778
|
|
|
735
779
|
// console.log('registering variables!');
|
|
@@ -763,12 +807,8 @@ export class FxFore extends HTMLElement {
|
|
|
763
807
|
// console.log('### >>>>> dispatching ready >>>>>', this);
|
|
764
808
|
// console.log('### modelItems: ', this.getModel().modelItems);
|
|
765
809
|
Fore.dispatch(this, 'ready', {});
|
|
766
|
-
console.
|
|
767
|
-
`%cPage Initialization done`,
|
|
768
|
-
"background:#64b5f6; color:white; padding:1rem; display:block; white-space: nowrap; border-radius:0.3rem;width:100%;",
|
|
769
|
-
);
|
|
810
|
+
// console.log('dataChanged', FxModel.dataChanged);
|
|
770
811
|
console.timeEnd('init');
|
|
771
|
-
console.log('dataChanged', FxModel.dataChanged);
|
|
772
812
|
}
|
|
773
813
|
|
|
774
814
|
registerLazyElement(element) {
|
|
@@ -808,6 +848,50 @@ export class FxFore extends HTMLElement {
|
|
|
808
848
|
toast.showToast(msg);
|
|
809
849
|
}
|
|
810
850
|
|
|
851
|
+
_displayWarning(e){
|
|
852
|
+
const msg = e.detail.message;
|
|
853
|
+
// this._showMessage('modal', msg);
|
|
854
|
+
const path = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
|
|
855
|
+
const toast = this.shadowRoot.querySelector('#warn');
|
|
856
|
+
toast.showToast(`WARN: ${path}:${msg}`);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
_logError(e) {
|
|
860
|
+
e.stopPropagation();
|
|
861
|
+
e.preventDefault();
|
|
862
|
+
|
|
863
|
+
const div = document.createElement('div');
|
|
864
|
+
div.setAttribute('slot','messages');
|
|
865
|
+
div.setAttribute('data-level',e.detail.level);
|
|
866
|
+
|
|
867
|
+
const id = document.createElement('div');
|
|
868
|
+
id.textContent = `"${e.detail.id}"`;
|
|
869
|
+
div.appendChild(id);
|
|
870
|
+
|
|
871
|
+
const path = document.createElement('div');
|
|
872
|
+
const pathExpr = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
|
|
873
|
+
// console.log('pathExpr',pathExpr)
|
|
874
|
+
path.textContent = pathExpr;
|
|
875
|
+
div.appendChild(path);
|
|
876
|
+
|
|
877
|
+
const message = document.createElement('div');
|
|
878
|
+
message.textContent = e.detail.message;
|
|
879
|
+
div.appendChild(message);
|
|
880
|
+
|
|
881
|
+
/*
|
|
882
|
+
const path = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
|
|
883
|
+
div.innerText = `${path} :: ${e.detail.message}`;
|
|
884
|
+
*/
|
|
885
|
+
this.appendChild(div);
|
|
886
|
+
div.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"});
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
const errorElement = evaluateXPathToFirstNode(`/${pathExpr}`,document,null);
|
|
890
|
+
errorElement.classList.add('fore-error');
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
}
|
|
894
|
+
|
|
811
895
|
_showMessage(level, msg) {
|
|
812
896
|
if (level === 'modal') {
|
|
813
897
|
// this.$.messageContent.innerText = msg;
|
|
@@ -834,6 +918,20 @@ export class FxFore extends HTMLElement {
|
|
|
834
918
|
const repeats = this.querySelectorAll('[data-ref]');
|
|
835
919
|
if(repeats){
|
|
836
920
|
Array.from(repeats).forEach(item =>{
|
|
921
|
+
if(item.closest('fx-control')) return;
|
|
922
|
+
/*
|
|
923
|
+
const parentRepeat = item.closest('fx-repeat');
|
|
924
|
+
if(parentRepeat){
|
|
925
|
+
this.dispatchEvent(
|
|
926
|
+
new CustomEvent('log', {
|
|
927
|
+
composed: false,
|
|
928
|
+
bubbles: true,
|
|
929
|
+
cancelable:true,
|
|
930
|
+
detail: { id:this.id, message: `nesting elements with data-ref attributes within fx-repeat is not supported by now`, level:'Error'},
|
|
931
|
+
}),
|
|
932
|
+
);
|
|
933
|
+
}
|
|
934
|
+
*/
|
|
837
935
|
|
|
838
936
|
const table = item.parentNode.closest('table');
|
|
839
937
|
let host;
|
package/src/fx-instance.js
CHANGED
|
@@ -30,12 +30,14 @@ async function handleResponse(response) {
|
|
|
30
30
|
// console.log("********** inside res json *********");
|
|
31
31
|
return response.json();
|
|
32
32
|
}
|
|
33
|
-
if (responseContentType.startsWith('application/xml')
|
|
33
|
+
if (responseContentType.startsWith('application/xml') ||
|
|
34
|
+
responseContentType.startsWith('text/xml')) {
|
|
35
|
+
// See https://www.rfc-editor.org/rfc/rfc7303
|
|
34
36
|
const text = await response.text();
|
|
35
37
|
// console.log('xml ********', result);
|
|
36
38
|
return new DOMParser().parseFromString(text, 'application/xml');
|
|
37
39
|
}
|
|
38
|
-
|
|
40
|
+
throw new Error(`unable to handle response content type: ${responseContentType}`);
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
/**
|
|
@@ -49,6 +51,7 @@ export class FxInstance extends HTMLElement {
|
|
|
49
51
|
super();
|
|
50
52
|
this.model = this.parentNode;
|
|
51
53
|
this.attachShadow({ mode: 'open' });
|
|
54
|
+
this.originalInstance = null;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
connectedCallback() {
|
|
@@ -67,6 +70,7 @@ export class FxInstance extends HTMLElement {
|
|
|
67
70
|
this.type = this.getAttribute('type');
|
|
68
71
|
} else {
|
|
69
72
|
this.type = 'xml';
|
|
73
|
+
this.setAttribute('type',this.type);
|
|
70
74
|
}
|
|
71
75
|
const style = `
|
|
72
76
|
:host {
|
|
@@ -107,6 +111,11 @@ export class FxInstance extends HTMLElement {
|
|
|
107
111
|
return this;
|
|
108
112
|
}
|
|
109
113
|
|
|
114
|
+
reset(){
|
|
115
|
+
// this._useInlineData();
|
|
116
|
+
this.instanceData = this.originalInstance.cloneNode(true);
|
|
117
|
+
}
|
|
118
|
+
|
|
110
119
|
evalXPath(xpath) {
|
|
111
120
|
const formElement = this.parentElement.parentElement;
|
|
112
121
|
const result = evaluateXPathToFirstNode(xpath, this.getDefaultContext(), formElement);
|
|
@@ -130,7 +139,8 @@ export class FxInstance extends HTMLElement {
|
|
|
130
139
|
this.createInstanceData();
|
|
131
140
|
return;
|
|
132
141
|
}
|
|
133
|
-
this.
|
|
142
|
+
this._setInitialData(data);
|
|
143
|
+
// this.instanceData = data;
|
|
134
144
|
}
|
|
135
145
|
|
|
136
146
|
/**
|
|
@@ -168,7 +178,11 @@ export class FxInstance extends HTMLElement {
|
|
|
168
178
|
newNode.appendChild(doc.createTextNode(p[1]));
|
|
169
179
|
root.appendChild(newNode);
|
|
170
180
|
}
|
|
181
|
+
this._setInitialData(doc);
|
|
182
|
+
/*
|
|
171
183
|
this.instanceData = doc;
|
|
184
|
+
this.originalInstance = this.instanceData.cloneNode(true);
|
|
185
|
+
*/
|
|
172
186
|
// this.instanceData.firstElementChild.setAttribute('id', this.id);
|
|
173
187
|
// resolve('done');
|
|
174
188
|
} else if (this.src) {
|
|
@@ -183,9 +197,11 @@ export class FxInstance extends HTMLElement {
|
|
|
183
197
|
// const doc = new DOMParser().parseFromString('<data data-id="default"></data>', 'application/xml');
|
|
184
198
|
const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
185
199
|
this.instanceData = doc;
|
|
200
|
+
this.originalInstance = this.instanceData.cloneNode(true);
|
|
186
201
|
}
|
|
187
202
|
if (this.type === 'json') {
|
|
188
203
|
this.instanceData = {};
|
|
204
|
+
this.originalInstance = [...this.instanceData];
|
|
189
205
|
}
|
|
190
206
|
}
|
|
191
207
|
|
|
@@ -196,8 +212,8 @@ export class FxInstance extends HTMLElement {
|
|
|
196
212
|
const key = url.substring(url.indexOf(':') + 1);
|
|
197
213
|
|
|
198
214
|
const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
199
|
-
const root = doc.firstElementChild;
|
|
200
215
|
this.instanceData = doc;
|
|
216
|
+
// ### does it make sense to store originalData here?
|
|
201
217
|
|
|
202
218
|
if (!key) {
|
|
203
219
|
console.warn('no key specified for localStore');
|
|
@@ -212,7 +228,6 @@ export class FxInstance extends HTMLElement {
|
|
|
212
228
|
}
|
|
213
229
|
const data = new DOMParser().parseFromString(serialized, 'application/xml');
|
|
214
230
|
// let data = this._parse(serialized, instance);
|
|
215
|
-
// root.appendChild(data);
|
|
216
231
|
doc.firstElementChild.replaceWith(data.firstElementChild);
|
|
217
232
|
return;
|
|
218
233
|
}
|
|
@@ -221,25 +236,41 @@ export class FxInstance extends HTMLElement {
|
|
|
221
236
|
try {
|
|
222
237
|
const response = await fetch(url, {
|
|
223
238
|
method: 'GET',
|
|
239
|
+
/*
|
|
224
240
|
mode: 'cors',
|
|
225
241
|
credentials: 'include',
|
|
242
|
+
*/
|
|
226
243
|
headers: {
|
|
227
244
|
'Content-Type': contentType,
|
|
228
245
|
},
|
|
229
246
|
});
|
|
230
|
-
const { status } = response;
|
|
231
247
|
const data = await handleResponse(response);
|
|
248
|
+
this._setInitialData(data);
|
|
249
|
+
/*
|
|
232
250
|
if (data.nodeType) {
|
|
251
|
+
this._setInitialData(data);
|
|
233
252
|
this.instanceData = data;
|
|
253
|
+
this.originalInstance = this.instanceData.cloneNode(true);
|
|
234
254
|
console.log('instanceData loaded: ', this.id, this.instanceData);
|
|
235
255
|
return;
|
|
236
256
|
}
|
|
237
257
|
this.instanceData = data;
|
|
258
|
+
this.originalInstance = [...data];
|
|
259
|
+
*/
|
|
238
260
|
} catch (error) {
|
|
239
261
|
throw new Error(`failed loading data ${error}`);
|
|
240
262
|
}
|
|
241
263
|
}
|
|
242
264
|
|
|
265
|
+
_setInitialData(data){
|
|
266
|
+
this.instanceData = data;
|
|
267
|
+
if(data.nodeType){
|
|
268
|
+
this.originalInstance = this.instanceData.cloneNode(true);
|
|
269
|
+
} else {
|
|
270
|
+
this.originalInstance = {...this.instanceData};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
243
274
|
_getContentType() {
|
|
244
275
|
if (this.type === 'xml') {
|
|
245
276
|
return 'application/xml';
|
|
@@ -257,7 +288,8 @@ export class FxInstance extends HTMLElement {
|
|
|
257
288
|
const instanceData = new DOMParser().parseFromString(this.innerHTML, 'application/xml');
|
|
258
289
|
|
|
259
290
|
// console.log('fx-instance init id:', this.id);
|
|
260
|
-
this.instanceData = instanceData;
|
|
291
|
+
// this.instanceData = instanceData;
|
|
292
|
+
this._setInitialData(instanceData);
|
|
261
293
|
// console.log('instanceData ', this.instanceData);
|
|
262
294
|
// console.log('instanceData ', this.instanceData.firstElementChild);
|
|
263
295
|
|
|
@@ -265,28 +297,34 @@ export class FxInstance extends HTMLElement {
|
|
|
265
297
|
// this.instanceData.firstElementChild.setAttribute('id', this.id);
|
|
266
298
|
// todo: move innerHTML out to shadowDOM (for later reset)
|
|
267
299
|
} else if (this.type === 'json') {
|
|
268
|
-
this.instanceData = JSON.parse(this.textContent);
|
|
300
|
+
// this.instanceData = JSON.parse(this.textContent);
|
|
301
|
+
this._setInitialData(JSON.parse(this.textContent));
|
|
269
302
|
} else if (this.type === 'html') {
|
|
270
|
-
this.instanceData = this.firstElementChild.children;
|
|
303
|
+
// this.instanceData = this.firstElementChild.children;
|
|
304
|
+
this._setInitialData(this.firstElementChild.children)
|
|
305
|
+
|
|
271
306
|
} else if (this.type === 'text') {
|
|
272
|
-
this.instanceData = this.textContent;
|
|
307
|
+
// this.instanceData = this.textContent;
|
|
308
|
+
this._setInitialData(this.textContent)
|
|
273
309
|
} else {
|
|
274
310
|
console.warn('unknow type for data ', this.type);
|
|
275
311
|
}
|
|
276
312
|
}
|
|
277
313
|
|
|
278
|
-
_handleResponse() {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
314
|
+
// _handleResponse() {
|
|
315
|
+
// console.log('_handleResponse ');
|
|
316
|
+
// const ajax = this.shadowRoot.getElementById('loader');
|
|
317
|
+
// const instanceData = new DOMParser().parseFromString(ajax.lastResponse, 'application/xml');
|
|
318
|
+
// this.instanceData = instanceData;
|
|
319
|
+
// console.log('data: ', this.instanceData);
|
|
320
|
+
// }
|
|
285
321
|
|
|
322
|
+
/*
|
|
286
323
|
_handleError() {
|
|
287
324
|
const loader = this.shadowRoot.getElementById('loader');
|
|
288
325
|
console.log('_handleResponse ', loader.lastError);
|
|
289
326
|
}
|
|
327
|
+
*/
|
|
290
328
|
}
|
|
291
329
|
if (!customElements.get('fx-instance')) {
|
|
292
330
|
customElements.define('fx-instance', FxInstance);
|