@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/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
|
*
|
|
@@ -119,8 +168,6 @@ export class Fore {
|
|
|
119
168
|
/**
|
|
120
169
|
* recursively refreshes all UI Elements.
|
|
121
170
|
*
|
|
122
|
-
* todo: this could probably made more efficient with significant impact on rendering perf
|
|
123
|
-
*
|
|
124
171
|
* @param startElement
|
|
125
172
|
* @param force
|
|
126
173
|
* @returns {Promise<unknown>}
|
|
@@ -174,8 +221,8 @@ export class Fore {
|
|
|
174
221
|
this.convertFromSimple(inputElement,newFore);
|
|
175
222
|
newFore.removeAttribute('convert');
|
|
176
223
|
console.log('converted', newFore);
|
|
177
|
-
return newFore;
|
|
178
224
|
console.timeEnd('convert');
|
|
225
|
+
return newFore;
|
|
179
226
|
}
|
|
180
227
|
static convertFromSimple(startElement,targetElement){
|
|
181
228
|
const children = startElement.childNodes;
|
|
@@ -218,28 +265,11 @@ export class Fore {
|
|
|
218
265
|
});
|
|
219
266
|
}
|
|
220
267
|
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Alternative to `closest` that respects subcontrol boundaries
|
|
224
|
-
*/
|
|
225
|
-
static getClosest(querySelector, start) {
|
|
226
|
-
while (!start.matches(querySelector)) {
|
|
227
|
-
if (start.matches('fx-fore')) {
|
|
228
|
-
// Subform reached. Bail out
|
|
229
|
-
return null;
|
|
230
|
-
}
|
|
231
|
-
start = start.parentNode;
|
|
232
|
-
if (!start) {
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return start;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
268
|
/**
|
|
240
269
|
* returns the proper content-type for instance.
|
|
241
270
|
*
|
|
242
271
|
* @param instance an fx-instance element
|
|
272
|
+
* @param contentType - the contentType
|
|
243
273
|
* @returns {string|null}
|
|
244
274
|
*/
|
|
245
275
|
static getContentType(instance, contentType) {
|
|
@@ -256,6 +286,59 @@ export class Fore {
|
|
|
256
286
|
return null;
|
|
257
287
|
}
|
|
258
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
|
+
|
|
259
342
|
static fadeInElement(element) {
|
|
260
343
|
const duration = 600;
|
|
261
344
|
let fadeIn = () => {
|
|
@@ -297,51 +380,24 @@ export class Fore {
|
|
|
297
380
|
}
|
|
298
381
|
|
|
299
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
|
+
}
|
|
300
387
|
const event = new CustomEvent(eventName, {
|
|
301
388
|
composed: false,
|
|
302
389
|
bubbles: true,
|
|
303
390
|
detail,
|
|
304
391
|
});
|
|
305
|
-
|
|
306
|
-
// console.info('dispatching', event.type, target);
|
|
307
|
-
// console.log('!!! DISPATCH_START', eventName);
|
|
392
|
+
event.listenerPromises = [];
|
|
308
393
|
|
|
309
|
-
|
|
394
|
+
target.dispatchEvent(event);
|
|
310
395
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
static prettifyXml(source) {
|
|
319
|
-
const xmlDoc = new DOMParser().parseFromString(source, 'application/xml');
|
|
320
|
-
const xsltDoc = new DOMParser().parseFromString(
|
|
321
|
-
[
|
|
322
|
-
// describes how we want to modify the XML - indent everything
|
|
323
|
-
'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
|
|
324
|
-
' <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>',
|
|
325
|
-
' <xsl:strip-space elements="*"/>',
|
|
326
|
-
' <xsl:template match="text()">', // change to just text() to strip space in text nodes
|
|
327
|
-
' <xsl:value-of select="normalize-space(.)"/>',
|
|
328
|
-
' </xsl:template>',
|
|
329
|
-
' <xsl:template match="node()|@*">',
|
|
330
|
-
' <xsl:copy>',
|
|
331
|
-
' <xsl:apply-templates select="node()|@*"/>',
|
|
332
|
-
' </xsl:copy>',
|
|
333
|
-
' </xsl:template>',
|
|
334
|
-
'</xsl:stylesheet>',
|
|
335
|
-
].join('\n'),
|
|
336
|
-
'application/xml',
|
|
337
|
-
);
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const xsltProcessor = new XSLTProcessor();
|
|
341
|
-
xsltProcessor.importStylesheet(xsltDoc);
|
|
342
|
-
const resultDoc = xsltProcessor.transformToDocument(xmlDoc);
|
|
343
|
-
const resultXml = new XMLSerializer().serializeToString(resultDoc);
|
|
344
|
-
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);
|
|
345
401
|
}
|
|
346
402
|
|
|
347
403
|
static formatXml (xml) {
|
|
@@ -349,7 +405,6 @@ export class Fore {
|
|
|
349
405
|
var wsexp = / *(.*) +\n/g;
|
|
350
406
|
var contexp = /(<.+>)(.+\n)/g;
|
|
351
407
|
xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2');
|
|
352
|
-
var pad = 0;
|
|
353
408
|
var formatted = '';
|
|
354
409
|
var lines = xml.split('\n');
|
|
355
410
|
var indent = 0;
|
|
@@ -394,7 +449,7 @@ export class Fore {
|
|
|
394
449
|
}
|
|
395
450
|
|
|
396
451
|
static async loadForeFromUrl(hostElement, url) {
|
|
397
|
-
console.log('########## loading Fore from ', this.src, '##########');
|
|
452
|
+
// console.log('########## loading Fore from ', this.src, '##########');
|
|
398
453
|
await fetch(url, {
|
|
399
454
|
method: 'GET',
|
|
400
455
|
mode: 'cors',
|
|
@@ -434,7 +489,7 @@ export class Fore {
|
|
|
434
489
|
imported.addEventListener(
|
|
435
490
|
'model-construct-done',
|
|
436
491
|
e => {
|
|
437
|
-
console.log('subcomponent ready', e.target);
|
|
492
|
+
// console.log('subcomponent ready', e.target);
|
|
438
493
|
const defaultInst = imported.querySelector('fx-instance');
|
|
439
494
|
// console.log('defaultInst', defaultInst);
|
|
440
495
|
if(hostElement.initialNode){
|
|
@@ -459,7 +514,7 @@ export class Fore {
|
|
|
459
514
|
dummy.parentNode.removeChild(dummy);
|
|
460
515
|
hostElement.shadowRoot.appendChild(imported);
|
|
461
516
|
} else {
|
|
462
|
-
console.log(this, 'replacing widget with',theFore);
|
|
517
|
+
// console.log(this, 'replacing widget with',theFore);
|
|
463
518
|
dummy.replaceWith(imported);
|
|
464
519
|
// this.appendChild(imported);
|
|
465
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
|
|
|
@@ -44,6 +44,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
44
44
|
connectedCallback() {
|
|
45
45
|
// console.log('connectedCallback ', this);
|
|
46
46
|
// this.id = this.hasAttribute('id')?this.getAttribute('id'):;
|
|
47
|
+
this.constraint = this.getAttribute('constraint');
|
|
47
48
|
this.ref = this.getAttribute('ref');
|
|
48
49
|
this.readonly = this.getAttribute('readonly');
|
|
49
50
|
this.required = this.getAttribute('required');
|
|
@@ -133,6 +134,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
133
134
|
this._addDependencies(constraintRefs, node, path, 'constraint');
|
|
134
135
|
} else if (this.constraint) {
|
|
135
136
|
this.model.mainGraph.addNode(`${path}:constraint`, node);
|
|
137
|
+
this.model.mainGraph.addDependency(path, `${path}:constraint`);
|
|
136
138
|
}
|
|
137
139
|
});
|
|
138
140
|
}
|
|
@@ -235,7 +237,6 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
235
237
|
// console.log('#### ', thi+s.nodeset);
|
|
236
238
|
|
|
237
239
|
if (Array.isArray(this.nodeset)) {
|
|
238
|
-
// todo - iterate and create
|
|
239
240
|
// console.log('################################################ ', this.nodeset);
|
|
240
241
|
// Array.from(this.nodeset).forEach((n, index) => {
|
|
241
242
|
Array.from(this.nodeset).forEach(n => {
|
|
@@ -272,7 +273,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
272
273
|
if bind is the dot expression we use the modelitem of the parent
|
|
273
274
|
*/
|
|
274
275
|
if (XPathUtil.isSelfReference(this.ref)) {
|
|
275
|
-
const parentBoundElement =
|
|
276
|
+
const parentBoundElement = XPathUtil.getClosest('fx-bind[ref]', this.parentElement);
|
|
276
277
|
// console.log('parent bound element ', parentBoundElement);
|
|
277
278
|
|
|
278
279
|
if (parentBoundElement) {
|
|
@@ -304,9 +305,9 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
304
305
|
const path = XPathUtil.getPath(node);
|
|
305
306
|
// const shortPath = this.shortenPath(path);
|
|
306
307
|
|
|
307
|
-
// ###
|
|
308
|
-
// ###
|
|
309
|
-
// ###
|
|
308
|
+
// ### constructing default modelitem - will get evaluated during recalculate()
|
|
309
|
+
// ### constructing default modelitem - will get evaluated during recalculate()
|
|
310
|
+
// ### constructing default modelitem - will get evaluated during recalculate()
|
|
310
311
|
// const newItem = new ModelItem(shortPath,
|
|
311
312
|
const newItem = new ModelItem(
|
|
312
313
|
path,
|
|
@@ -325,6 +326,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
325
326
|
newItem.addAlert(alert);
|
|
326
327
|
}
|
|
327
328
|
|
|
329
|
+
|
|
328
330
|
this.getModel().registerModelItem(newItem);
|
|
329
331
|
}
|
|
330
332
|
|