@jinntec/fore 1.4.0 → 1.6.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 -270
- 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-update.js +9 -0
- package/src/events.js +0 -1
- package/src/fore.js +119 -63
- package/src/functions/common-function.js +28 -0
- package/src/fx-bind.js +7 -7
- package/src/fx-fore.js +207 -54
- 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 +22 -8
- 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-action-log.js +358 -0
- 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 +409 -0
- package/src/ui/fx-repeat.js +12 -6
- 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/fore.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import getInScopeContext from "./getInScopeContext.js";
|
|
2
|
+
import {evaluateXPathToString} from "./xpath-evaluation.js";
|
|
3
|
+
import { XPathUtil } from "./xpath-util.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Class hosting common utility functions used throughout all fore elements
|
|
7
|
+
*
|
|
8
|
+
* @example ../doc/demo.html
|
|
9
|
+
*/
|
|
1
10
|
export class Fore {
|
|
2
11
|
static READONLY_DEFAULT = false;
|
|
3
12
|
|
|
@@ -9,6 +18,46 @@ export class Fore {
|
|
|
9
18
|
|
|
10
19
|
static TYPE_DEFAULT = 'xs:string';
|
|
11
20
|
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* returns true if target element is the widget itself or some element within the widget.
|
|
24
|
+
* @param target an event target
|
|
25
|
+
* @returns {boolean}
|
|
26
|
+
*/
|
|
27
|
+
static isWidget(target) {
|
|
28
|
+
if(target?.classList.contains("widget")) return true;
|
|
29
|
+
let parent = target.parentNode;
|
|
30
|
+
while(parent && parent.nodeName !== 'FX-CONTROL'){
|
|
31
|
+
if(parent.classList.contains('widget')) return true;
|
|
32
|
+
parent = parent.parentNode;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
static getDomNodeIndexString(node) {
|
|
39
|
+
const indexes = [];
|
|
40
|
+
let currentNode = node;
|
|
41
|
+
|
|
42
|
+
while (currentNode && currentNode.parentNode) {
|
|
43
|
+
const parent = currentNode.parentNode;
|
|
44
|
+
if (parent.childNodes && parent.childNodes.length > 0) {
|
|
45
|
+
const index = [...parent.childNodes].indexOf(currentNode);
|
|
46
|
+
indexes.unshift(index);
|
|
47
|
+
}
|
|
48
|
+
currentNode = parent;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return indexes.join('.');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static getExpression(input){
|
|
55
|
+
if(input.startsWith('{') && input.endsWith('}')){
|
|
56
|
+
return input.substring(1, input.length - 1);
|
|
57
|
+
}
|
|
58
|
+
return input;
|
|
59
|
+
}
|
|
60
|
+
|
|
12
61
|
/**
|
|
13
62
|
* returns the next `fx-fore` element upwards in tree
|
|
14
63
|
*
|
|
@@ -86,6 +135,7 @@ export class Fore {
|
|
|
86
135
|
'FX-RANGE',
|
|
87
136
|
'FX-REPEAT',
|
|
88
137
|
'FX-REPEATITEM',
|
|
138
|
+
'FX-REPEAT-ATTRIBUTES',
|
|
89
139
|
'FX-SWITCH',
|
|
90
140
|
'FX-SECRET',
|
|
91
141
|
'FX-SELECT',
|
|
@@ -118,8 +168,6 @@ export class Fore {
|
|
|
118
168
|
/**
|
|
119
169
|
* recursively refreshes all UI Elements.
|
|
120
170
|
*
|
|
121
|
-
* todo: this could probably made more efficient with significant impact on rendering perf
|
|
122
|
-
*
|
|
123
171
|
* @param startElement
|
|
124
172
|
* @param force
|
|
125
173
|
* @returns {Promise<unknown>}
|
|
@@ -173,8 +221,8 @@ export class Fore {
|
|
|
173
221
|
this.convertFromSimple(inputElement,newFore);
|
|
174
222
|
newFore.removeAttribute('convert');
|
|
175
223
|
console.log('converted', newFore);
|
|
176
|
-
return newFore;
|
|
177
224
|
console.timeEnd('convert');
|
|
225
|
+
return newFore;
|
|
178
226
|
}
|
|
179
227
|
static convertFromSimple(startElement,targetElement){
|
|
180
228
|
const children = startElement.childNodes;
|
|
@@ -217,28 +265,11 @@ export class Fore {
|
|
|
217
265
|
});
|
|
218
266
|
}
|
|
219
267
|
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Alternative to `closest` that respects subcontrol boundaries
|
|
223
|
-
*/
|
|
224
|
-
static getClosest(querySelector, start) {
|
|
225
|
-
while (!start.matches(querySelector)) {
|
|
226
|
-
if (start.matches('fx-fore')) {
|
|
227
|
-
// Subform reached. Bail out
|
|
228
|
-
return null;
|
|
229
|
-
}
|
|
230
|
-
start = start.parentNode;
|
|
231
|
-
if (!start) {
|
|
232
|
-
return null;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
return start;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
268
|
/**
|
|
239
269
|
* returns the proper content-type for instance.
|
|
240
270
|
*
|
|
241
271
|
* @param instance an fx-instance element
|
|
272
|
+
* @param contentType - the contentType
|
|
242
273
|
* @returns {string|null}
|
|
243
274
|
*/
|
|
244
275
|
static getContentType(instance, contentType) {
|
|
@@ -255,6 +286,59 @@ export class Fore {
|
|
|
255
286
|
return null;
|
|
256
287
|
}
|
|
257
288
|
|
|
289
|
+
static async handleResponse(response) {
|
|
290
|
+
const { status } = response;
|
|
291
|
+
if (status >= 400) {
|
|
292
|
+
// console.log('response status', status);
|
|
293
|
+
alert(`response status: ${status} - failed to load data for '${this.src}' - stopping.`);
|
|
294
|
+
throw new Error(`failed to load data - status: ${status}`);
|
|
295
|
+
}
|
|
296
|
+
const responseContentType = response.headers.get('content-type').toLowerCase();
|
|
297
|
+
// console.log('********** responseContentType *********', responseContentType);
|
|
298
|
+
if (responseContentType.startsWith('text/html')) {
|
|
299
|
+
// const htmlResponse = response.text();
|
|
300
|
+
// return new DOMParser().parseFromString(htmlResponse, 'text/html');
|
|
301
|
+
// return response.text();
|
|
302
|
+
return response.text().then(result =>
|
|
303
|
+
// console.log('xml ********', result);
|
|
304
|
+
new DOMParser().parseFromString(result, 'text/html'),
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
if (
|
|
308
|
+
responseContentType.startsWith('text/plain') ||
|
|
309
|
+
responseContentType.startsWith('text/markdown')
|
|
310
|
+
) {
|
|
311
|
+
// console.log("********** inside res plain *********");
|
|
312
|
+
return response.text();
|
|
313
|
+
}
|
|
314
|
+
if (responseContentType.startsWith('application/json')) {
|
|
315
|
+
// console.log("********** inside res json *********");
|
|
316
|
+
return response.json();
|
|
317
|
+
}
|
|
318
|
+
if (responseContentType.startsWith('application/xml')) {
|
|
319
|
+
const text = await response.text();
|
|
320
|
+
// console.log('xml ********', result);
|
|
321
|
+
return new DOMParser().parseFromString(text, 'application/xml');
|
|
322
|
+
}
|
|
323
|
+
return 'done';
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
static evaluateAttributeTemplateExpression(expr, node) {
|
|
327
|
+
const matches = expr.match(/{[^}]*}/g);
|
|
328
|
+
if (matches) {
|
|
329
|
+
matches.forEach(match => {
|
|
330
|
+
console.log('match ', match);
|
|
331
|
+
const naked = match.substring(1, match.length - 1);
|
|
332
|
+
const inscope = getInScopeContext(node, naked);
|
|
333
|
+
const result = evaluateXPathToString(naked, inscope, node.getOwnerForm());
|
|
334
|
+
const replaced = expr.replaceAll(match, result);
|
|
335
|
+
console.log('replacing ', expr, ' with ', replaced);
|
|
336
|
+
expr = replaced;
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
return expr;
|
|
340
|
+
}
|
|
341
|
+
|
|
258
342
|
static fadeInElement(element) {
|
|
259
343
|
const duration = 600;
|
|
260
344
|
let fadeIn = () => {
|
|
@@ -296,51 +380,24 @@ export class Fore {
|
|
|
296
380
|
}
|
|
297
381
|
|
|
298
382
|
static async dispatch(target, eventName, detail) {
|
|
383
|
+
if (!XPathUtil.contains(target?.ownerDocument, target)) {
|
|
384
|
+
// The target is gone from the document. This happens when we are done with a refresh that removed the component
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
299
387
|
const event = new CustomEvent(eventName, {
|
|
300
388
|
composed: false,
|
|
301
389
|
bubbles: true,
|
|
302
390
|
detail,
|
|
303
391
|
});
|
|
304
|
-
|
|
305
|
-
// console.info('dispatching', event.type, target);
|
|
306
|
-
// console.log('!!! DISPATCH_START', eventName);
|
|
392
|
+
event.listenerPromises = [];
|
|
307
393
|
|
|
308
|
-
|
|
394
|
+
target.dispatchEvent(event);
|
|
309
395
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
static prettifyXml(source) {
|
|
318
|
-
const xmlDoc = new DOMParser().parseFromString(source, 'application/xml');
|
|
319
|
-
const xsltDoc = new DOMParser().parseFromString(
|
|
320
|
-
[
|
|
321
|
-
// describes how we want to modify the XML - indent everything
|
|
322
|
-
'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
|
|
323
|
-
' <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>',
|
|
324
|
-
' <xsl:strip-space elements="*"/>',
|
|
325
|
-
' <xsl:template match="text()">', // change to just text() to strip space in text nodes
|
|
326
|
-
' <xsl:value-of select="normalize-space(.)"/>',
|
|
327
|
-
' </xsl:template>',
|
|
328
|
-
' <xsl:template match="node()|@*">',
|
|
329
|
-
' <xsl:copy>',
|
|
330
|
-
' <xsl:apply-templates select="node()|@*"/>',
|
|
331
|
-
' </xsl:copy>',
|
|
332
|
-
' </xsl:template>',
|
|
333
|
-
'</xsl:stylesheet>',
|
|
334
|
-
].join('\n'),
|
|
335
|
-
'application/xml',
|
|
336
|
-
);
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const xsltProcessor = new XSLTProcessor();
|
|
340
|
-
xsltProcessor.importStylesheet(xsltDoc);
|
|
341
|
-
const resultDoc = xsltProcessor.transformToDocument(xmlDoc);
|
|
342
|
-
const resultXml = new XMLSerializer().serializeToString(resultDoc);
|
|
343
|
-
return resultXml;
|
|
396
|
+
// By now, all listeners for the event should have registered their completion promises to us.
|
|
397
|
+
if (event.listenerPromises.length) {
|
|
398
|
+
await Promise.all(event.listenerPromises);
|
|
399
|
+
}
|
|
400
|
+
// console.log('!!! DISPATCH_DONE', eventName);
|
|
344
401
|
}
|
|
345
402
|
|
|
346
403
|
static formatXml (xml) {
|
|
@@ -348,7 +405,6 @@ export class Fore {
|
|
|
348
405
|
var wsexp = / *(.*) +\n/g;
|
|
349
406
|
var contexp = /(<.+>)(.+\n)/g;
|
|
350
407
|
xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2');
|
|
351
|
-
var pad = 0;
|
|
352
408
|
var formatted = '';
|
|
353
409
|
var lines = xml.split('\n');
|
|
354
410
|
var indent = 0;
|
|
@@ -393,7 +449,7 @@ export class Fore {
|
|
|
393
449
|
}
|
|
394
450
|
|
|
395
451
|
static async loadForeFromUrl(hostElement, url) {
|
|
396
|
-
console.log('########## loading Fore from ', this.src, '##########');
|
|
452
|
+
// console.log('########## loading Fore from ', this.src, '##########');
|
|
397
453
|
await fetch(url, {
|
|
398
454
|
method: 'GET',
|
|
399
455
|
mode: 'cors',
|
|
@@ -433,7 +489,7 @@ export class Fore {
|
|
|
433
489
|
imported.addEventListener(
|
|
434
490
|
'model-construct-done',
|
|
435
491
|
e => {
|
|
436
|
-
console.log('subcomponent ready', e.target);
|
|
492
|
+
// console.log('subcomponent ready', e.target);
|
|
437
493
|
const defaultInst = imported.querySelector('fx-instance');
|
|
438
494
|
// console.log('defaultInst', defaultInst);
|
|
439
495
|
if(hostElement.initialNode){
|
|
@@ -458,7 +514,7 @@ export class Fore {
|
|
|
458
514
|
dummy.parentNode.removeChild(dummy);
|
|
459
515
|
hostElement.shadowRoot.appendChild(imported);
|
|
460
516
|
} else {
|
|
461
|
-
console.log(this, 'replacing widget with',theFore);
|
|
517
|
+
// console.log(this, 'replacing widget with',theFore);
|
|
462
518
|
dummy.replaceWith(imported);
|
|
463
519
|
// this.appendChild(imported);
|
|
464
520
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function prettifyXml(source) {
|
|
2
|
+
const xmlDoc = new DOMParser().parseFromString(source, 'application/xml');
|
|
3
|
+
const xsltDoc = new DOMParser().parseFromString(
|
|
4
|
+
[
|
|
5
|
+
// describes how we want to modify the XML - indent everything
|
|
6
|
+
'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
|
|
7
|
+
' <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>',
|
|
8
|
+
' <xsl:strip-space elements="*"/>',
|
|
9
|
+
' <xsl:template match="text()">', // change to just text() to strip space in text nodes
|
|
10
|
+
' <xsl:value-of select="normalize-space(.)"/>',
|
|
11
|
+
' </xsl:template>',
|
|
12
|
+
' <xsl:template match="node()|@*">',
|
|
13
|
+
' <xsl:copy>',
|
|
14
|
+
' <xsl:apply-templates select="node()|@*"/>',
|
|
15
|
+
' </xsl:copy>',
|
|
16
|
+
' </xsl:template>',
|
|
17
|
+
'</xsl:stylesheet>',
|
|
18
|
+
].join('\n'),
|
|
19
|
+
'application/xml',
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
const xsltProcessor = new XSLTProcessor();
|
|
24
|
+
xsltProcessor.importStylesheet(xsltDoc);
|
|
25
|
+
const resultDoc = xsltProcessor.transformToDocument(xmlDoc);
|
|
26
|
+
const resultXml = new XMLSerializer().serializeToString(resultDoc);
|
|
27
|
+
return resultXml;
|
|
28
|
+
}
|
package/src/fx-bind.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { DependencyNotifyingDomFacade } from './DependencyNotifyingDomFacade.js';
|
|
2
2
|
import { foreElementMixin } from './ForeElementMixin.js';
|
|
3
|
-
import { Fore } from './fore.js';
|
|
4
3
|
import { ModelItem } from './modelitem.js';
|
|
5
4
|
import {
|
|
6
5
|
evaluateXPathToBoolean,
|
|
@@ -20,8 +19,9 @@ import getInScopeContext from './getInScopeContext.js';
|
|
|
20
19
|
* Note: why is fx-bind not extending BoundElement? Though fx-bind has a 'ref' attr it is not bound in the sense of
|
|
21
20
|
* getting updates about changes of the bound nodes. Instead it acts as a factory for modelItems that are used by
|
|
22
21
|
* BoundElements to track their state.
|
|
22
|
+
*
|
|
23
|
+
* @customElements
|
|
23
24
|
*/
|
|
24
|
-
// export class FxBind extends HTMLElement {
|
|
25
25
|
export class FxBind extends foreElementMixin(HTMLElement) {
|
|
26
26
|
static READONLY_DEFAULT = false;
|
|
27
27
|
|
|
@@ -235,7 +235,6 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
235
235
|
// console.log('#### ', thi+s.nodeset);
|
|
236
236
|
|
|
237
237
|
if (Array.isArray(this.nodeset)) {
|
|
238
|
-
// todo - iterate and create
|
|
239
238
|
// console.log('################################################ ', this.nodeset);
|
|
240
239
|
// Array.from(this.nodeset).forEach((n, index) => {
|
|
241
240
|
Array.from(this.nodeset).forEach(n => {
|
|
@@ -272,7 +271,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
272
271
|
if bind is the dot expression we use the modelitem of the parent
|
|
273
272
|
*/
|
|
274
273
|
if (XPathUtil.isSelfReference(this.ref)) {
|
|
275
|
-
const parentBoundElement =
|
|
274
|
+
const parentBoundElement = XPathUtil.getClosest('fx-bind[ref]', this.parentElement);
|
|
276
275
|
// console.log('parent bound element ', parentBoundElement);
|
|
277
276
|
|
|
278
277
|
if (parentBoundElement) {
|
|
@@ -304,9 +303,9 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
304
303
|
const path = XPathUtil.getPath(node);
|
|
305
304
|
// const shortPath = this.shortenPath(path);
|
|
306
305
|
|
|
307
|
-
// ###
|
|
308
|
-
// ###
|
|
309
|
-
// ###
|
|
306
|
+
// ### constructing default modelitem - will get evaluated during recalculate()
|
|
307
|
+
// ### constructing default modelitem - will get evaluated during recalculate()
|
|
308
|
+
// ### constructing default modelitem - will get evaluated during recalculate()
|
|
310
309
|
// const newItem = new ModelItem(shortPath,
|
|
311
310
|
const newItem = new ModelItem(
|
|
312
311
|
path,
|
|
@@ -325,6 +324,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
325
324
|
newItem.addAlert(alert);
|
|
326
325
|
}
|
|
327
326
|
|
|
327
|
+
|
|
328
328
|
this.getModel().registerModelItem(newItem);
|
|
329
329
|
}
|
|
330
330
|
|