@jinntec/fore 2.8.0 → 3.0.1
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 +4581 -1863
- package/dist/fore.js +4598 -1871
- package/package.json +3 -1
- package/src/DependentXPathQueries.js +37 -2
- package/src/ForeElementMixin.js +64 -38
- package/src/actions/fx-delete.js +424 -73
- package/src/actions/fx-insert.js +471 -73
- package/src/actions/fx-setattribute.js +5 -5
- package/src/actions/fx-setvalue.js +11 -9
- package/src/fore.js +28 -71
- package/src/functions/fx-functionlib.js +138 -12
- package/src/functions/mylib.js +13 -0
- package/src/functions/registerFunction.js +78 -20
- package/src/fx-bind.js +128 -73
- package/src/fx-fore.js +201 -97
- package/src/fx-instance.js +138 -142
- package/src/fx-model.js +292 -102
- package/src/fx-submission.js +246 -135
- package/src/fx-var.js +28 -4
- package/src/json/JSONDomFacade.js +84 -0
- package/src/json/JSONLens.js +67 -0
- package/src/json/JSONNode.js +248 -0
- package/src/json/lensFromNode.js +5 -0
- package/src/modelitem.js +16 -2
- package/src/tools/fx-action-log.js +1 -1
- package/src/ui/UIElement.js +16 -2
- package/src/ui/fx-items.js +26 -32
- package/src/ui/fx-repeat.js +682 -246
- package/src/ui/fx-repeatitem.js +16 -1
- package/src/ui/repeat-base.js +8 -4
- package/src/withDraggability.js +0 -1
- package/src/xpath-evaluation.js +1763 -740
- package/src/xpath-path.js +274 -24
- package/src/xpath-util.js +92 -46
|
@@ -82,17 +82,20 @@ export default class FxSetvalue extends AbstractAction {
|
|
|
82
82
|
*/
|
|
83
83
|
dispatchExecute() {}
|
|
84
84
|
|
|
85
|
+
// Adjustment in setValue logic to ensure we work with JSONNode, not just raw values
|
|
85
86
|
setValue(modelItem, newVal) {
|
|
86
87
|
console.log('setValue', modelItem, newVal);
|
|
87
88
|
const item = modelItem;
|
|
88
89
|
if (!item) return;
|
|
89
90
|
|
|
90
|
-
if
|
|
91
|
-
|
|
92
|
-
const path = Fore.getDomNodeIndexString(modelItem.node);
|
|
91
|
+
// Check if current node is a JSONNode
|
|
92
|
+
const node = Array.isArray(item.node) ? item.node[0] : item.node;
|
|
93
93
|
|
|
94
|
+
if (item.value !== newVal) {
|
|
95
|
+
const path = Fore.getDomNodeIndexString(node);
|
|
94
96
|
const ev = this.event;
|
|
95
97
|
const targetElem = this;
|
|
98
|
+
|
|
96
99
|
this.dispatchEvent(
|
|
97
100
|
new CustomEvent('execute-action', {
|
|
98
101
|
composed: true,
|
|
@@ -107,20 +110,19 @@ export default class FxSetvalue extends AbstractAction {
|
|
|
107
110
|
}),
|
|
108
111
|
);
|
|
109
112
|
|
|
113
|
+
// Use ModelItem's value setter which handles both DOM nodes and JSON lenses
|
|
110
114
|
if (newVal?.nodeType) {
|
|
111
115
|
if (newVal.nodeType === Node.ELEMENT_NODE) {
|
|
112
116
|
item.value = newVal;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
if (newVal.nodeType === Node.TEXT_NODE) {
|
|
117
|
+
} else if (newVal.nodeType === Node.ATTRIBUTE_NODE) {
|
|
118
|
+
item.value = newVal.nodeValue;
|
|
119
|
+
} else if (newVal.nodeType === Node.TEXT_NODE) {
|
|
118
120
|
item.value = newVal.textContent;
|
|
119
121
|
}
|
|
120
122
|
} else {
|
|
121
123
|
item.value = newVal;
|
|
122
|
-
item.node.textContent = newVal;
|
|
123
124
|
}
|
|
125
|
+
|
|
124
126
|
this.getModel().changed.push(modelItem);
|
|
125
127
|
this.needsUpdate = true;
|
|
126
128
|
modelItem.notify();
|
package/src/fore.js
CHANGED
|
@@ -293,82 +293,39 @@ export class Fore {
|
|
|
293
293
|
* @returns {Promise<void>}
|
|
294
294
|
*/
|
|
295
295
|
static async refreshChildren(startElement, force) {
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
if (
|
|
309
|
-
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (children) {
|
|
315
|
-
for (const element of Array.from(children)) {
|
|
316
|
-
if (element.nodeName.toUpperCase() === 'FX-FORE') {
|
|
317
|
-
break;
|
|
318
|
-
}
|
|
319
|
-
if (Fore.isUiElement(element.nodeName) && typeof element.refresh === 'function') {
|
|
320
|
-
/**
|
|
321
|
-
* @type {import('./ForeElementMixin.js').default}
|
|
322
|
-
*/
|
|
323
|
-
const bound = element;
|
|
324
|
-
if (!force) {
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
/*
|
|
328
|
-
if(element.nodeName === 'FX-CASE') {
|
|
329
|
-
console.log('hey - got a case', element);
|
|
330
|
-
}
|
|
331
|
-
*/
|
|
332
|
-
if (force === true) {
|
|
333
|
-
// console.log('🔄 refreshing ', element);
|
|
334
|
-
// Unconditional force refresh
|
|
335
|
-
bound.refresh(force);
|
|
336
|
-
continue;
|
|
337
|
-
}
|
|
338
|
-
if (typeof force !== 'object') {
|
|
339
|
-
continue;
|
|
340
|
-
}
|
|
341
|
-
/*
|
|
342
|
-
if (
|
|
343
|
-
force.reason === 'index-function' &&
|
|
344
|
-
bound.dependencies.isInvalidatedByIndexFunction()
|
|
345
|
-
) {
|
|
346
|
-
console.log('🔄 refreshing ', element);
|
|
347
|
-
|
|
348
|
-
bound.refresh(force);
|
|
349
|
-
continue;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
if (
|
|
353
|
-
bound.dependencies.isInvalidatedByChildlistChanges(force.elementLocalnamesWithChanges)
|
|
354
|
-
) {
|
|
355
|
-
console.log('🔄 refreshing ', element);
|
|
356
|
-
|
|
357
|
-
bound.refresh(force);
|
|
358
|
-
continue;
|
|
359
|
-
}
|
|
360
|
-
*/
|
|
296
|
+
const children = startElement?.children ? Array.from(startElement.children) : [];
|
|
297
|
+
for (const element of children) {
|
|
298
|
+
// Do not cross into nested fore roots
|
|
299
|
+
if (element.nodeName.toUpperCase() === 'FX-FORE') {
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (Fore.isUiElement(element.nodeName) && typeof element.refresh === 'function') {
|
|
304
|
+
/** @type {import('./ForeElementMixin.js').default} */
|
|
305
|
+
const bound = element;
|
|
306
|
+
|
|
307
|
+
// Keep old behavior: only refresh UI elements during full/forced refresh
|
|
308
|
+
if (!force) {
|
|
309
|
+
// still recurse below
|
|
310
|
+
} else if (force === true) {
|
|
311
|
+
const maybePromise = bound.refresh(force);
|
|
312
|
+
if (maybePromise && typeof maybePromise.then === 'function') {
|
|
313
|
+
await maybePromise;
|
|
361
314
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
315
|
+
} else if (typeof force === 'object') {
|
|
316
|
+
// future selective refresh logic can live here if you re-enable it
|
|
317
|
+
const maybePromise = bound.refresh(force);
|
|
318
|
+
if (maybePromise && typeof maybePromise.then === 'function') {
|
|
319
|
+
await maybePromise;
|
|
365
320
|
}
|
|
366
321
|
}
|
|
367
322
|
}
|
|
368
|
-
resolve('done');
|
|
369
|
-
});
|
|
370
323
|
|
|
371
|
-
|
|
324
|
+
// Traverse DOM unless inert
|
|
325
|
+
if (!(element.inert === true)) {
|
|
326
|
+
await Fore.refreshChildren(element, force);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
372
329
|
}
|
|
373
330
|
|
|
374
331
|
static copyDom(inputElement) {
|
|
@@ -1,10 +1,45 @@
|
|
|
1
1
|
import ForeElementMixin from '../ForeElementMixin.js';
|
|
2
2
|
import registerFunction from './registerFunction.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
const LOCAL_FUNCTIONS_NS = 'http://www.w3.org/2005/xquery-local-functions';
|
|
5
|
+
|
|
6
|
+
// Global per-page cache to prevent registering the same library multiple times.
|
|
7
|
+
// Keyed by resolved URL + prefix + mode.
|
|
8
|
+
const _functionLibLoadCache = new Map();
|
|
9
|
+
|
|
10
|
+
function looksLikeModuleSrc(src) {
|
|
11
|
+
return /\.m?js($|\?)/i.test(src);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function applyPrefixToSignature(signature, prefix) {
|
|
15
|
+
if (!signature || !prefix) return signature;
|
|
16
|
+
|
|
17
|
+
const s = signature.trim();
|
|
18
|
+
const paren = s.indexOf('(');
|
|
19
|
+
if (paren < 0) return s;
|
|
20
|
+
|
|
21
|
+
const namePart = s.slice(0, paren).trim();
|
|
22
|
+
const rest = s.slice(paren);
|
|
23
|
+
|
|
24
|
+
const localName = namePart.includes(':') ? namePart.split(':').pop().trim() : namePart;
|
|
25
|
+
if (!localName) return s;
|
|
26
|
+
|
|
27
|
+
return `${prefix}:${localName}${rest}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function normalizeModuleExportToList(mod, src) {
|
|
31
|
+
const lib = mod.functions ?? mod.fxFunctions;
|
|
32
|
+
if (!lib) {
|
|
33
|
+
console.error(
|
|
34
|
+
`fx-functionlib: Module ${src} must export a named \`functions\` (or \`fxFunctions\`).`,
|
|
35
|
+
);
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
if (Array.isArray(lib)) return lib;
|
|
39
|
+
if (typeof lib === 'object') return Object.values(lib);
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
8
43
|
export class FxFunctionlib extends ForeElementMixin {
|
|
9
44
|
constructor() {
|
|
10
45
|
super();
|
|
@@ -24,20 +59,112 @@ export class FxFunctionlib extends ForeElementMixin {
|
|
|
24
59
|
this.style.display = 'none';
|
|
25
60
|
|
|
26
61
|
const src = this.getAttribute('src');
|
|
62
|
+
if (!src) {
|
|
63
|
+
console.error('fx-functionlib: Missing required @src.');
|
|
64
|
+
this._resolveLoading(undefined);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const prefix = (this.getAttribute('prefix') || '').trim();
|
|
69
|
+
|
|
70
|
+
const typeAttr = (this.getAttribute('type') || '').trim().toLowerCase();
|
|
71
|
+
const isModule = typeAttr === 'module' || (!typeAttr && looksLikeModuleSrc(src));
|
|
72
|
+
|
|
73
|
+
const resolvedUrl = new URL(src, this.baseURI).href;
|
|
74
|
+
|
|
75
|
+
if (prefix) this._ensurePrefixDeclared(prefix);
|
|
76
|
+
|
|
77
|
+
const mode = isModule ? 'module' : 'html';
|
|
78
|
+
const cacheKey = `${mode}|${resolvedUrl}|${prefix}`;
|
|
79
|
+
|
|
80
|
+
const existing = _functionLibLoadCache.get(cacheKey);
|
|
81
|
+
if (existing) {
|
|
82
|
+
try {
|
|
83
|
+
await existing;
|
|
84
|
+
} finally {
|
|
85
|
+
this._resolveLoading(undefined);
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const loadPromise = (async () => {
|
|
91
|
+
if (isModule) {
|
|
92
|
+
await this._loadModuleLibrary(resolvedUrl, src, prefix);
|
|
93
|
+
} else {
|
|
94
|
+
await this._loadHtmlLibrary(resolvedUrl, src, prefix);
|
|
95
|
+
}
|
|
96
|
+
})();
|
|
27
97
|
|
|
28
|
-
|
|
98
|
+
_functionLibLoadCache.set(cacheKey, loadPromise);
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
await loadPromise;
|
|
102
|
+
} catch (e) {
|
|
103
|
+
_functionLibLoadCache.delete(cacheKey);
|
|
104
|
+
console.error(`fx-functionlib: Loading function library at ${src} failed.`, e);
|
|
105
|
+
} finally {
|
|
106
|
+
this._resolveLoading(undefined);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
_ensurePrefixDeclared(prefix) {
|
|
111
|
+
const ownerForm =
|
|
112
|
+
(typeof this.getOwnerForm === 'function' && this.getOwnerForm()) || this.closest('fx-fore');
|
|
113
|
+
|
|
114
|
+
if (!ownerForm) return;
|
|
115
|
+
|
|
116
|
+
const attrName = `xmlns:${prefix}`;
|
|
117
|
+
if (!ownerForm.getAttribute(attrName)) {
|
|
118
|
+
ownerForm.setAttribute(attrName, LOCAL_FUNCTIONS_NS);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
_register(functionObject, prefix) {
|
|
123
|
+
if (!functionObject || typeof functionObject.signature !== 'string') return;
|
|
124
|
+
|
|
125
|
+
// If prefix is given: register ONLY the prefixed signature (no unprefixed alias).
|
|
126
|
+
const sig = prefix
|
|
127
|
+
? applyPrefixToSignature(functionObject.signature, prefix)
|
|
128
|
+
: functionObject.signature;
|
|
129
|
+
|
|
130
|
+
registerFunction({ ...functionObject, signature: sig }, this);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async _loadModuleLibrary(resolvedUrl, src, prefix) {
|
|
134
|
+
const mod = await import(/* @vite-ignore */ resolvedUrl);
|
|
135
|
+
|
|
136
|
+
const items = normalizeModuleExportToList(mod, src);
|
|
137
|
+
|
|
138
|
+
for (const item of items) {
|
|
139
|
+
if (typeof item === 'function') {
|
|
140
|
+
const { signature } = item;
|
|
141
|
+
if (typeof signature !== 'string' || !signature.trim()) continue;
|
|
142
|
+
|
|
143
|
+
this._register(
|
|
144
|
+
{
|
|
145
|
+
type: 'text/javascript',
|
|
146
|
+
signature: signature.trim(),
|
|
147
|
+
implementation: item,
|
|
148
|
+
},
|
|
149
|
+
prefix,
|
|
150
|
+
);
|
|
151
|
+
} else if (item && typeof item === 'object' && typeof item.signature === 'string') {
|
|
152
|
+
this._register(item, prefix);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async _loadHtmlLibrary(resolvedUrl, src, prefix) {
|
|
158
|
+
const result = await fetch(resolvedUrl);
|
|
29
159
|
if (!result.ok) {
|
|
30
160
|
console.error(`Loading function library at ${src} failed.`);
|
|
161
|
+
return;
|
|
31
162
|
}
|
|
32
163
|
|
|
33
164
|
const body = await result.text();
|
|
34
165
|
const document = new DOMParser().parseFromString(body, 'text/html');
|
|
35
166
|
|
|
36
|
-
/**
|
|
37
|
-
* @type {HTMLElement[]}
|
|
38
|
-
*/
|
|
39
167
|
const functions = Array.from(document.querySelectorAll('fx-function'));
|
|
40
|
-
// TODO: also recurse into new function libraries here?
|
|
41
168
|
for (const func of functions) {
|
|
42
169
|
const functionObject = {
|
|
43
170
|
type: func.getAttribute('type'),
|
|
@@ -45,12 +172,11 @@ export class FxFunctionlib extends ForeElementMixin {
|
|
|
45
172
|
functionBody: func.innerText,
|
|
46
173
|
};
|
|
47
174
|
|
|
48
|
-
|
|
175
|
+
this._register(functionObject, prefix);
|
|
49
176
|
}
|
|
50
|
-
this._resolveLoading(undefined);
|
|
51
177
|
}
|
|
52
178
|
}
|
|
53
179
|
|
|
54
180
|
if (!customElements.get('fx-functionlib')) {
|
|
55
181
|
customElements.define('fx-functionlib', FxFunctionlib);
|
|
56
|
-
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function myfunc(node) {
|
|
2
|
+
// simple: true if node is present
|
|
3
|
+
return !!node;
|
|
4
|
+
}
|
|
5
|
+
myfunc.signature = 'myfunc($node as item()?) as xs:boolean';
|
|
6
|
+
|
|
7
|
+
export function hasText(s) {
|
|
8
|
+
return s != null && String(s).trim() !== '';
|
|
9
|
+
}
|
|
10
|
+
hasText.signature = 'hasText($s as xs:string?) as xs:boolean';
|
|
11
|
+
|
|
12
|
+
// Named export is the default convention for fx-functionlib
|
|
13
|
+
export const functions = [myfunc, hasText];
|
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
import { createTypedValueFactory, registerCustomXPathFunction } from 'fontoxpath';
|
|
2
|
-
import { evaluateXPath, globallyDeclaredFunctionLocalNames } from '../xpath-evaluation';
|
|
2
|
+
import { evaluateXPath, globallyDeclaredFunctionLocalNames } from '../xpath-evaluation.js';
|
|
3
|
+
|
|
4
|
+
// FontoXPath custom functions are registered globally. If multiple <fx-functionlib> (or multiple
|
|
5
|
+
// <fx-fore> instances) register the same function name+arity, later registrations would overwrite
|
|
6
|
+
// earlier ones across the whole page. We enforce "first wins".
|
|
7
|
+
const _registeredFunctionKeys = new Set();
|
|
8
|
+
|
|
9
|
+
function _makeFunctionKey(functionIdentifier, arity) {
|
|
10
|
+
if (typeof functionIdentifier === 'string') {
|
|
11
|
+
return `str:${functionIdentifier}#${arity}`;
|
|
12
|
+
}
|
|
13
|
+
return `{${functionIdentifier.namespaceURI}}${functionIdentifier.localName}#${arity}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function _ensureGlobalUnprefixedName(localName) {
|
|
17
|
+
// Keep this list unique to avoid unbounded growth across tests
|
|
18
|
+
if (!globallyDeclaredFunctionLocalNames.includes(localName)) {
|
|
19
|
+
globallyDeclaredFunctionLocalNames.push(localName);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
3
22
|
|
|
4
23
|
/**
|
|
5
|
-
* @param functionObject {{signature: string, type: string|null, functionBody: string}}
|
|
24
|
+
* @param functionObject {{signature: string, type: string|null, functionBody: string, implementation?: Function}}
|
|
6
25
|
* @param formElement {HTMLElement} The form element connected to this function. Used to determine inscope context
|
|
7
26
|
* @returns {undefined}
|
|
8
27
|
*/
|
|
@@ -31,28 +50,64 @@ export default function registerFunction(functionObject, formElement) {
|
|
|
31
50
|
? { namespaceURI: 'http://www.w3.org/2005/xquery-local-functions', localName }
|
|
32
51
|
: `${prefix}:${localName}`;
|
|
33
52
|
|
|
34
|
-
// Make the function available globally w/o a prefix. See the functionNameResolver for for how
|
|
35
|
-
// functionObject is picked up
|
|
36
|
-
if (!prefix) {
|
|
37
|
-
globallyDeclaredFunctionLocalNames.push(localName);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
53
|
const paramParts = params
|
|
41
|
-
? params
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
? params
|
|
55
|
+
.split(',')
|
|
56
|
+
.map(param => param.trim())
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
.map(param => {
|
|
59
|
+
const match = param.match(/(?<variableName>\$[^\s]+)(?:\sas\s(?<varType>[^\s]+))/);
|
|
60
|
+
if (!match) {
|
|
61
|
+
throw new Error(`Param ${param} could not be parsed`);
|
|
62
|
+
}
|
|
63
|
+
const { variableName, varType } = match.groups;
|
|
64
|
+
return {
|
|
65
|
+
variableName,
|
|
66
|
+
variableType: varType || 'item()*',
|
|
67
|
+
};
|
|
68
|
+
})
|
|
52
69
|
: [];
|
|
53
70
|
|
|
71
|
+
const arity = paramParts.length;
|
|
72
|
+
|
|
73
|
+
// -------------------------------------------------
|
|
74
|
+
// FIRST-WINS GUARD (name + arity) WITH NAME EXPORT
|
|
75
|
+
// -------------------------------------------------
|
|
76
|
+
const key = _makeFunctionKey(functionIdentifier, arity);
|
|
77
|
+
|
|
78
|
+
if (_registeredFunctionKeys.has(key)) {
|
|
79
|
+
// If this registration is unprefixed, we must still make it callable without prefix.
|
|
80
|
+
// This fixes the unit test case where local:hello-world() was registered earlier and
|
|
81
|
+
// hello-world() should resolve to that implementation.
|
|
82
|
+
if (!prefix) {
|
|
83
|
+
_ensureGlobalUnprefixedName(localName);
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
_registeredFunctionKeys.add(key);
|
|
89
|
+
|
|
90
|
+
// Make the function available globally w/o a prefix.
|
|
91
|
+
if (!prefix) {
|
|
92
|
+
_ensureGlobalUnprefixedName(localName);
|
|
93
|
+
}
|
|
94
|
+
|
|
54
95
|
switch (type) {
|
|
55
96
|
case 'text/javascript': {
|
|
97
|
+
// If a real JS function is provided (module libs), register it directly.
|
|
98
|
+
if (typeof functionObject.implementation === 'function') {
|
|
99
|
+
const impl = functionObject.implementation;
|
|
100
|
+
registerCustomXPathFunction(
|
|
101
|
+
functionIdentifier,
|
|
102
|
+
paramParts.map(paramPart => paramPart.variableType),
|
|
103
|
+
returnType || 'item()*',
|
|
104
|
+
(domFacade, ...values) =>
|
|
105
|
+
impl.apply(formElement.getInScopeContext(), [...values, formElement.getOwnerForm()]),
|
|
106
|
+
);
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Existing behavior: compile from functionBody
|
|
56
111
|
// eslint-disable-next-line no-new-func
|
|
57
112
|
const fun = new Function(
|
|
58
113
|
'_domFacade',
|
|
@@ -60,6 +115,7 @@ export default function registerFunction(functionObject, formElement) {
|
|
|
60
115
|
'form',
|
|
61
116
|
functionObject.functionBody,
|
|
62
117
|
);
|
|
118
|
+
|
|
63
119
|
registerCustomXPathFunction(
|
|
64
120
|
functionIdentifier,
|
|
65
121
|
paramParts.map(paramPart => paramPart.variableType),
|
|
@@ -76,19 +132,20 @@ export default function registerFunction(functionObject, formElement) {
|
|
|
76
132
|
const typedValueFactories = paramParts.map(param =>
|
|
77
133
|
createTypedValueFactory(param.variableType),
|
|
78
134
|
);
|
|
135
|
+
|
|
79
136
|
const language =
|
|
80
137
|
type === 'text/xpath'
|
|
81
138
|
? 'XPath3.1'
|
|
82
139
|
: type === 'text/xquery'
|
|
83
140
|
? 'XQuery3.1'
|
|
84
141
|
: 'XQueryUpdate3.1';
|
|
142
|
+
|
|
85
143
|
const fun = (domFacade, ...args) =>
|
|
86
144
|
evaluateXPath(
|
|
87
145
|
functionObject.functionBody,
|
|
88
146
|
formElement.getInScopeContext(),
|
|
89
147
|
formElement.getOwnerForm(),
|
|
90
148
|
paramParts.reduce((variablesByName, paramPart, i) => {
|
|
91
|
-
// Because we know the XPath type here (from the function declaration) we do not have to depend on the implicit typings
|
|
92
149
|
variablesByName[paramPart.variableName.replace('$', '')] = typedValueFactories[i](
|
|
93
150
|
args[i],
|
|
94
151
|
domFacade,
|
|
@@ -97,6 +154,7 @@ export default function registerFunction(functionObject, formElement) {
|
|
|
97
154
|
}, {}),
|
|
98
155
|
{ language },
|
|
99
156
|
);
|
|
157
|
+
|
|
100
158
|
registerCustomXPathFunction(
|
|
101
159
|
functionIdentifier,
|
|
102
160
|
paramParts.map(paramPart => paramPart.variableType),
|