@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/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;
|
|
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);
|
package/src/fx-model.js
CHANGED
|
@@ -6,7 +6,13 @@ import {evaluateXPath, evaluateXPathToBoolean} from './xpath-evaluation.js';
|
|
|
6
6
|
import {XPathUtil} from './xpath-util.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* The model of this Fore scope. It holds all the intances, binding, submissions and custom functions that
|
|
10
|
+
* as required.
|
|
11
|
+
*
|
|
12
|
+
* The model is updatin by executing rebuild (as needed), recalculate and revalidate in turn.
|
|
13
|
+
*
|
|
14
|
+
* After the cycle is run all modelItems have updated their stete to reflect latest computations.
|
|
15
|
+
*
|
|
10
16
|
*/
|
|
11
17
|
export class FxModel extends HTMLElement {
|
|
12
18
|
static dataChanged = false;
|
|
@@ -103,7 +109,6 @@ export class FxModel extends HTMLElement {
|
|
|
103
109
|
// console.time('instance-loading');
|
|
104
110
|
const instances = this.querySelectorAll('fx-instance');
|
|
105
111
|
if (instances.length > 0) {
|
|
106
|
-
console.group('init instances');
|
|
107
112
|
const promises = [];
|
|
108
113
|
instances.forEach(instance => {
|
|
109
114
|
promises.push(instance.init());
|
|
@@ -119,7 +124,6 @@ export class FxModel extends HTMLElement {
|
|
|
119
124
|
await Fore.dispatch(this, 'model-construct-done', {model: this});
|
|
120
125
|
this.inited = true;
|
|
121
126
|
this.updateModel();
|
|
122
|
-
console.groupEnd();
|
|
123
127
|
} else {
|
|
124
128
|
// ### if there's no instance one will created
|
|
125
129
|
await this.dispatchEvent(
|
|
@@ -145,17 +149,20 @@ export class FxModel extends HTMLElement {
|
|
|
145
149
|
updateModel() {
|
|
146
150
|
// console.time('updateModel');
|
|
147
151
|
this.rebuild();
|
|
152
|
+
/*
|
|
148
153
|
if (this.skipUpdate){
|
|
149
154
|
console.info('%crecalculate/revalidate skipped - no bindings', 'font-style: italic; background: #90a4ae; color:lightgrey; padding:0.3rem 5rem 0.3rem 0.3rem;display:block;width:100%;');
|
|
150
155
|
return;
|
|
151
156
|
}
|
|
157
|
+
*/
|
|
152
158
|
this.recalculate();
|
|
153
159
|
this.revalidate();
|
|
160
|
+
// console.log('updateModel finished with modelItems ', this.modelItems);
|
|
161
|
+
|
|
154
162
|
// console.timeEnd('updateModel');
|
|
155
163
|
}
|
|
156
164
|
|
|
157
165
|
rebuild() {
|
|
158
|
-
console.info('%crebuild', 'font-style: italic; background: #90a4ae; color:white; padding:0.3rem 5rem 0.3rem 0.3rem;display:block;width:100%;');
|
|
159
166
|
this.mainGraph = new DepGraph(false); // do: should be moved down below binds.length check but causes errors in tests.
|
|
160
167
|
this.modelItems = [];
|
|
161
168
|
|
|
@@ -171,15 +178,12 @@ export class FxModel extends HTMLElement {
|
|
|
171
178
|
bind.init(this);
|
|
172
179
|
});
|
|
173
180
|
|
|
174
|
-
console.log(`mainGraph`, this.mainGraph);
|
|
181
|
+
// console.log(`mainGraph`, this.mainGraph);
|
|
175
182
|
// console.log(`rebuild mainGraph calc order`, this.mainGraph.overallOrder());
|
|
176
183
|
|
|
177
184
|
// this.dispatchEvent(new CustomEvent('rebuild-done', {detail: {maingraph: this.mainGraph}}));
|
|
178
185
|
Fore.dispatch(this,'rebuild-done',{maingraph:this.mainGraph});
|
|
179
|
-
console.log(
|
|
180
|
-
`rebuild finished with modelItems ${this.modelItems.length} item(s)`,
|
|
181
|
-
this.modelItems,
|
|
182
|
-
);
|
|
186
|
+
console.log('mainGraph', this.mainGraph);
|
|
183
187
|
}
|
|
184
188
|
|
|
185
189
|
/**
|
|
@@ -188,20 +192,15 @@ export class FxModel extends HTMLElement {
|
|
|
188
192
|
* todo: use 'changed' flag on modelItems to determine subgraph for recalculation. Flag already exists but is not used.
|
|
189
193
|
*/
|
|
190
194
|
recalculate() {
|
|
191
|
-
console.info('%crecalculate', 'font-style: italic; background: #90a4ae; color:white; padding:0.3rem 5rem 0.3rem 0.3rem;display:block;width:100%;');
|
|
192
|
-
|
|
193
195
|
if (!this.mainGraph) {
|
|
194
196
|
return;
|
|
195
197
|
}
|
|
196
198
|
|
|
197
|
-
console.
|
|
198
|
-
console.log('changed nodes ', this.changed);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
console.time('recalculate');
|
|
199
|
+
// console.log('changed nodes ', this.changed);
|
|
202
200
|
this.computes = 0;
|
|
203
201
|
|
|
204
202
|
this.subgraph = new DepGraph(false);
|
|
203
|
+
// ### create the subgraph for all changed modelItems
|
|
205
204
|
if (this.changed.length !== 0) {
|
|
206
205
|
// ### build the subgraph
|
|
207
206
|
this.changed.forEach(modelItem => {
|
|
@@ -246,22 +245,16 @@ export class FxModel extends HTMLElement {
|
|
|
246
245
|
const toRefresh = [...this.changed];
|
|
247
246
|
this.formElement.toRefresh = toRefresh;
|
|
248
247
|
this.changed = [];
|
|
249
|
-
|
|
250
|
-
this.dispatchEvent(
|
|
251
|
-
new CustomEvent('recalculate-done', {detail: {subgraph: this.subgraph}}),
|
|
252
|
-
);
|
|
248
|
+
Fore.dispatch(this,'recalculate-done',{graph:this.subgraph,computes:this.computes})
|
|
253
249
|
} else {
|
|
254
250
|
const v = this.mainGraph.overallOrder(false);
|
|
255
251
|
v.forEach(path => {
|
|
256
252
|
const node = this.mainGraph.getNodeData(path);
|
|
257
253
|
this.compute(node, path);
|
|
258
254
|
});
|
|
255
|
+
Fore.dispatch(this,'recalculate-done',{graph:this.mainGraph,computes:this.computes})
|
|
259
256
|
}
|
|
260
|
-
console.log(`recalculated ${this.computes} modelItems`);
|
|
261
|
-
|
|
262
|
-
console.timeEnd('recalculate');
|
|
263
257
|
console.log('recalculate finished with modelItems ', this.modelItems);
|
|
264
|
-
console.groupEnd();
|
|
265
258
|
}
|
|
266
259
|
|
|
267
260
|
/*
|
|
@@ -323,13 +316,13 @@ export class FxModel extends HTMLElement {
|
|
|
323
316
|
}
|
|
324
317
|
}
|
|
325
318
|
*/
|
|
319
|
+
const expr = modelItem.bind[property];
|
|
326
320
|
if (property === 'calculate') {
|
|
327
|
-
const expr = modelItem.bind[property];
|
|
328
321
|
const compute = evaluateXPath(expr, modelItem.node, this);
|
|
329
322
|
modelItem.value = compute;
|
|
330
323
|
modelItem.readonly = true; // calculated nodes are always readonly
|
|
331
324
|
} else if (property !== 'constraint' && property !== 'type') {
|
|
332
|
-
|
|
325
|
+
// ### re-compute the Boolean value of all facets expect 'constraint' and 'type' which are handled in revalidate()
|
|
333
326
|
if (expr) {
|
|
334
327
|
const compute = evaluateXPathToBoolean(expr, modelItem.node, this);
|
|
335
328
|
modelItem[property] = compute;
|
|
@@ -363,11 +356,9 @@ export class FxModel extends HTMLElement {
|
|
|
363
356
|
*
|
|
364
357
|
*/
|
|
365
358
|
revalidate() {
|
|
366
|
-
console.info('%crevalidate', 'font-style: italic; background: #90a4ae; color:white; padding:0.3rem 5rem 0.3rem 0.3rem;display:block;width:100%;');
|
|
367
359
|
|
|
368
360
|
if (this.modelItems.length === 0) return true;
|
|
369
361
|
|
|
370
|
-
console.group('### revalidate');
|
|
371
362
|
console.time('revalidate');
|
|
372
363
|
|
|
373
364
|
// reset submission validation
|
|
@@ -384,7 +375,7 @@ export class FxModel extends HTMLElement {
|
|
|
384
375
|
*/
|
|
385
376
|
if (typeof bind.hasAttribute === 'function' && bind.hasAttribute('constraint')) {
|
|
386
377
|
const constraint = bind.getAttribute('constraint');
|
|
387
|
-
if (constraint) {
|
|
378
|
+
if (constraint && modelItem.node) {
|
|
388
379
|
const compute = evaluateXPathToBoolean(constraint, modelItem.node, this);
|
|
389
380
|
// console.log('modelItem validity computed: ', compute);
|
|
390
381
|
modelItem.constraint = compute;
|
|
@@ -400,7 +391,6 @@ export class FxModel extends HTMLElement {
|
|
|
400
391
|
modelItem.required = compute;
|
|
401
392
|
this.formElement.addToRefresh(modelItem); // let fore know that modelItem needs refresh
|
|
402
393
|
if (!modelItem.node.textContent) {
|
|
403
|
-
console.log('modelItem required check failed: ');
|
|
404
394
|
valid = false;
|
|
405
395
|
}
|
|
406
396
|
// if (!compute) valid = false;
|
|
@@ -417,12 +407,16 @@ export class FxModel extends HTMLElement {
|
|
|
417
407
|
}
|
|
418
408
|
}
|
|
419
409
|
});
|
|
420
|
-
console.timeEnd('revalidate');
|
|
421
410
|
console.log('modelItems after revalidate: ', this.modelItems);
|
|
422
|
-
console.groupEnd();
|
|
423
411
|
return valid;
|
|
424
412
|
}
|
|
425
413
|
|
|
414
|
+
addChanged(modelItem){
|
|
415
|
+
if(this.inited){
|
|
416
|
+
this.changed.push(modelItem);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
426
420
|
/**
|
|
427
421
|
*
|
|
428
422
|
* @param node
|
|
@@ -455,7 +449,11 @@ export class FxModel extends HTMLElement {
|
|
|
455
449
|
// console.log('instances array ',Array.from(this.instances));
|
|
456
450
|
|
|
457
451
|
const instArray = Array.from(this.instances);
|
|
458
|
-
|
|
452
|
+
const found = instArray.find(inst => inst.id === id);
|
|
453
|
+
if(!found){
|
|
454
|
+
return this.getDefaultInstance(); // if id is not found always defaults to first in doc order
|
|
455
|
+
}
|
|
456
|
+
return found;
|
|
459
457
|
}
|
|
460
458
|
|
|
461
459
|
evalBinding(bindingExpr) {
|
package/src/fx-submission.js
CHANGED
|
@@ -3,6 +3,7 @@ import {Relevance} from './relevance.js';
|
|
|
3
3
|
import {foreElementMixin} from './ForeElementMixin.js';
|
|
4
4
|
import {evaluateXPathToString, evaluateXPath} from './xpath-evaluation.js';
|
|
5
5
|
import getInScopeContext from './getInScopeContext.js';
|
|
6
|
+
import {XPathUtil} from "./xpath-util.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* todo: validate='false'
|
|
@@ -11,6 +12,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
11
12
|
constructor() {
|
|
12
13
|
super();
|
|
13
14
|
this.attachShadow({mode: 'open'});
|
|
15
|
+
this.parameters = new Map();
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
connectedCallback() {
|
|
@@ -45,9 +47,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
45
47
|
? this.getAttribute('serialization')
|
|
46
48
|
: 'xml';
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
if (!this.hasAttribute('url')) console.warn(`url is required for submission: ${this.id}`);
|
|
50
|
-
this.url = this.getAttribute('url');
|
|
50
|
+
this.url = this.hasAttribute('url') ? this.getAttribute('url'):null;
|
|
51
51
|
|
|
52
52
|
this.targetref = this.hasAttribute('targetref') ? this.getAttribute('targetref') : null;
|
|
53
53
|
|
|
@@ -90,31 +90,15 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
-
console.log('model updated....');
|
|
94
93
|
await this._serializeAndSend();
|
|
95
94
|
}
|
|
96
95
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
* @private
|
|
103
|
-
*/
|
|
104
|
-
_evaluateAttributeTemplateExpression(expr, node) {
|
|
105
|
-
const matches = expr.match(/{[^}]*}/g);
|
|
106
|
-
if (matches) {
|
|
107
|
-
matches.forEach(match => {
|
|
108
|
-
console.log('match ', match);
|
|
109
|
-
const naked = match.substring(1, match.length - 1);
|
|
110
|
-
const inscope = getInScopeContext(node, naked);
|
|
111
|
-
const result = evaluateXPathToString(naked, inscope, this.getOwnerForm());
|
|
112
|
-
const replaced = expr.replaceAll(match, result);
|
|
113
|
-
console.log('replacing ', expr, ' with ', replaced);
|
|
114
|
-
expr = replaced;
|
|
115
|
-
});
|
|
96
|
+
_getProperty(attrName){
|
|
97
|
+
if(this.parameters.has(attrName)){
|
|
98
|
+
return this.parameters.get(attrName);
|
|
99
|
+
} else {
|
|
100
|
+
return this.getAttribute(attrName);
|
|
116
101
|
}
|
|
117
|
-
return expr;
|
|
118
102
|
}
|
|
119
103
|
|
|
120
104
|
/**
|
|
@@ -123,18 +107,23 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
123
107
|
* @private
|
|
124
108
|
*/
|
|
125
109
|
async _serializeAndSend() {
|
|
126
|
-
const
|
|
127
|
-
|
|
110
|
+
const url = this._getProperty('url');
|
|
111
|
+
const resolvedUrl = this.evaluateAttributeTemplateExpression(url,this);
|
|
112
|
+
console.log('resolvedUrl',resolvedUrl);
|
|
128
113
|
const instance = this.getInstance();
|
|
129
|
-
|
|
114
|
+
if (!instance) {
|
|
115
|
+
Fore.dispatch(this, 'warn', {message: `instance not found ${instance.getAttribute('id')}`})
|
|
116
|
+
}
|
|
117
|
+
const instType = instance.getAttribute('type');
|
|
118
|
+
// console.log('instance type', instance.type);
|
|
130
119
|
|
|
131
120
|
let serialized;
|
|
132
121
|
if (this.serialization === 'none') {
|
|
133
122
|
serialized = undefined;
|
|
134
123
|
} else {
|
|
135
124
|
// const relevant = this.selectRelevant(instance.type);
|
|
136
|
-
const relevant = Relevance.selectRelevant(this,
|
|
137
|
-
serialized = this._serialize(
|
|
125
|
+
const relevant = Relevance.selectRelevant(this, instType);
|
|
126
|
+
serialized = this._serialize(instType, relevant);
|
|
138
127
|
}
|
|
139
128
|
|
|
140
129
|
// let serialized = serializer.serializeToString(relevant);
|
|
@@ -150,6 +139,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
150
139
|
this._handleResponse(data);
|
|
151
140
|
// this.dispatch('submit-done', {});
|
|
152
141
|
Fore.dispatch(this, 'submit-done', {});
|
|
142
|
+
this.parameters.clear();
|
|
153
143
|
return;
|
|
154
144
|
}
|
|
155
145
|
|
|
@@ -162,9 +152,10 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
162
152
|
const serialized = localStorage.getItem(key);
|
|
163
153
|
if (!serialized) {
|
|
164
154
|
Fore.dispatch(this, 'submit-error', {message: `Error reading key ${key} from localstorage`});
|
|
155
|
+
this.parameters.clear();
|
|
165
156
|
return;
|
|
166
157
|
}
|
|
167
|
-
|
|
158
|
+
const data = this._parse(serialized, instance);
|
|
168
159
|
this._handleResponse(data);
|
|
169
160
|
if (this.method === 'consume') {
|
|
170
161
|
localStorage.removeItem(key);
|
|
@@ -191,7 +182,6 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
191
182
|
|
|
192
183
|
// ### setting headers
|
|
193
184
|
const headers = this._getHeaders();
|
|
194
|
-
console.log('headers', headers);
|
|
195
185
|
|
|
196
186
|
if (!this.methods.includes(this.method.toLowerCase())) {
|
|
197
187
|
// this.dispatch('error', { message: `Unknown method ${this.method}` });
|
|
@@ -201,8 +191,10 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
201
191
|
try {
|
|
202
192
|
const response = await fetch(resolvedUrl, {
|
|
203
193
|
method: this.method,
|
|
204
|
-
|
|
205
|
-
|
|
194
|
+
/*
|
|
195
|
+
mode: 'cors',
|
|
196
|
+
credentials: 'include',
|
|
197
|
+
*/
|
|
206
198
|
headers,
|
|
207
199
|
body: serialized,
|
|
208
200
|
});
|
|
@@ -220,32 +212,34 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
220
212
|
contentType.startsWith('text/markdown')
|
|
221
213
|
) {
|
|
222
214
|
const text = await response.text();
|
|
223
|
-
this._handleResponse(text);
|
|
215
|
+
this._handleResponse(text, resolvedUrl,contentType);
|
|
224
216
|
} else if (contentType.startsWith('application/json')) {
|
|
225
217
|
const json = await response.json();
|
|
226
|
-
this._handleResponse(json);
|
|
218
|
+
this._handleResponse(json, resolvedUrl,contentType);
|
|
227
219
|
} else if (contentType.startsWith('application/xml')) {
|
|
228
220
|
const text = await response.text();
|
|
229
221
|
const xml = new DOMParser().parseFromString(text, 'application/xml');
|
|
230
|
-
this._handleResponse(xml);
|
|
222
|
+
this._handleResponse(xml, resolvedUrl,contentType);
|
|
231
223
|
} else {
|
|
232
224
|
const blob = await response.blob();
|
|
233
|
-
this._handleResponse(blob);
|
|
225
|
+
this._handleResponse(blob, resolvedUrl,contentType);
|
|
234
226
|
}
|
|
235
227
|
|
|
236
228
|
// this.dispatch('submit-done', {});
|
|
237
229
|
Fore.dispatch(this, 'submit-done', {});
|
|
238
230
|
} catch (error) {
|
|
239
231
|
Fore.dispatch(this, 'submit-error', {error: error.message});
|
|
232
|
+
} finally {
|
|
233
|
+
this.parameters.clear();
|
|
240
234
|
}
|
|
241
235
|
}
|
|
242
236
|
|
|
243
237
|
_parse(serialized, instance) {
|
|
244
238
|
let data = null;
|
|
245
|
-
if (serialized && instance.type === 'xml') {
|
|
239
|
+
if (serialized && instance.getAttribute('type') === 'xml') {
|
|
246
240
|
data = new DOMParser().parseFromString(serialized, 'application/xml');
|
|
247
241
|
}
|
|
248
|
-
if (serialized && instance.type === 'json') {
|
|
242
|
+
if (serialized && instance.getAttribute('type') === 'json') {
|
|
249
243
|
data = JSON.parse(serialized);
|
|
250
244
|
}
|
|
251
245
|
return data;
|
|
@@ -319,8 +313,8 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
319
313
|
* @param data
|
|
320
314
|
* @private
|
|
321
315
|
*/
|
|
322
|
-
_handleResponse(data) {
|
|
323
|
-
console.log('_handleResponse ', data);
|
|
316
|
+
_handleResponse(data, resolvedUrl, contentType) {
|
|
317
|
+
// console.log('_handleResponse ', data);
|
|
324
318
|
|
|
325
319
|
/*
|
|
326
320
|
// ### responses need to be handled depending on their type.
|
|
@@ -358,8 +352,8 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
358
352
|
} else {
|
|
359
353
|
const instanceData = data;
|
|
360
354
|
targetInstance.instanceData = instanceData;
|
|
361
|
-
console.log('### replaced instance ', this.getModel().instances);
|
|
362
|
-
console.log('### replaced instance ', targetInstance.instanceData);
|
|
355
|
+
// console.log('### replaced instance ', this.getModel().instances);
|
|
356
|
+
// console.log('### replaced instance ', targetInstance.instanceData);
|
|
363
357
|
}
|
|
364
358
|
|
|
365
359
|
// Skip any refreshes if the model is not yet inited
|
|
@@ -373,12 +367,21 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
373
367
|
}
|
|
374
368
|
|
|
375
369
|
if (this.replace === 'all') {
|
|
376
|
-
document.
|
|
370
|
+
document.open();
|
|
371
|
+
document.write(data);
|
|
372
|
+
document.close();
|
|
373
|
+
window.location.href = resolvedUrl;
|
|
374
|
+
// document.getElementsByTagName('html')[0].innerHTML = data;
|
|
377
375
|
}
|
|
378
|
-
if (this.replace === 'target') {
|
|
379
|
-
const target = this.getAttribute('target');
|
|
376
|
+
if (this.replace === 'target' && contentType.startsWith('text/html')) {
|
|
377
|
+
// const target = this.getAttribute('target');
|
|
378
|
+
const target = this._getProperty('target');
|
|
380
379
|
const targetNode = document.querySelector(target);
|
|
381
|
-
targetNode
|
|
380
|
+
if(targetNode){
|
|
381
|
+
targetNode.innerHTML = data;
|
|
382
|
+
}else{
|
|
383
|
+
Fore.dispatch(this, 'submit-error', {message:`targetNode for selector ${target} not found`});
|
|
384
|
+
}
|
|
382
385
|
}
|
|
383
386
|
if (this.replace === 'redirect') {
|
|
384
387
|
window.location.href = data;
|
package/src/getInScopeContext.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {evaluateXPathToFirstNode} from './xpath-evaluation.js';
|
|
2
|
-
import {Fore} from './fore.js';
|
|
3
|
-
|
|
1
|
+
import { evaluateXPathToFirstNode } from './xpath-evaluation.js';
|
|
4
2
|
import {XPathUtil} from './xpath-util.js';
|
|
5
3
|
|
|
6
4
|
function _getElement(node) {
|
|
@@ -29,8 +27,8 @@ function _getModelInContext(node) {
|
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
function _getInitialContext(node, ref) {
|
|
32
|
-
const parentBind =
|
|
33
|
-
const localFore =
|
|
30
|
+
const parentBind = XPathUtil.getClosest('[ref]', node);
|
|
31
|
+
const localFore = XPathUtil.getClosest('fx-fore', node);
|
|
34
32
|
|
|
35
33
|
const model = _getModelInContext(node);
|
|
36
34
|
|
|
@@ -62,12 +60,12 @@ export default function getInScopeContext(node, ref) {
|
|
|
62
60
|
if(parentElement.nodeName === 'FX-FORE'){
|
|
63
61
|
return parentElement.getModel().getDefaultInstance().getDefaultContext();
|
|
64
62
|
}
|
|
65
|
-
const parentBind =
|
|
66
|
-
if (parentBind && parentBind.nodeName === 'FX-GROUP') {
|
|
63
|
+
const parentBind = XPathUtil.getClosest('[ref]', parentElement.parentNode);
|
|
64
|
+
if (parentBind && (parentBind.nodeName === 'FX-GROUP' || parentBind.nodeName === 'FX-CONTROL')) {
|
|
67
65
|
return parentBind.nodeset;
|
|
68
66
|
}
|
|
69
67
|
|
|
70
|
-
const repeatItem =
|
|
68
|
+
const repeatItem = XPathUtil.getClosest('fx-repeatitem', parentElement);
|
|
71
69
|
if (repeatItem) {
|
|
72
70
|
if (node.nodeName === 'context') {
|
|
73
71
|
return evaluateXPathToFirstNode(
|
|
@@ -79,6 +77,22 @@ export default function getInScopeContext(node, ref) {
|
|
|
79
77
|
return repeatItem.nodeset;
|
|
80
78
|
}
|
|
81
79
|
|
|
80
|
+
// ### check for repeatitems created by fx-repeat-attributes - this could possibly be unified with standard repeats
|
|
81
|
+
// const repeatItemFromAttrs = XPathUtil.getClosest('.fx-repeatitem', parentElement);
|
|
82
|
+
// const repeatItemFromAttrs = XPathUtil.getClosest('.fx-repeatitem', parentElement);
|
|
83
|
+
const repeatItemFromAttrs = parentElement.closest('.fx-repeatitem');
|
|
84
|
+
|
|
85
|
+
if (repeatItemFromAttrs) {
|
|
86
|
+
// ### determine correct inscopecontext by determining the index of the repeatitem in its parent list and
|
|
87
|
+
// ### using that as an index on the repeat nodeset
|
|
88
|
+
const parent = repeatItemFromAttrs.parentNode;
|
|
89
|
+
const index = Array.from(parent.children).indexOf(repeatItemFromAttrs);
|
|
90
|
+
|
|
91
|
+
// ### fetching nodeset from fx-repeat-attributes element
|
|
92
|
+
const repeatFromAttributes = XPathUtil.getClosest('fx-repeat-attributes', parentElement);
|
|
93
|
+
return repeatFromAttributes.nodeset[index];
|
|
94
|
+
}
|
|
95
|
+
|
|
82
96
|
if (parentElement.hasAttribute('context')) {
|
|
83
97
|
const initialContext = _getInitialContext(parentElement.parentNode, ref);
|
|
84
98
|
const contextAttr = parentElement.getAttribute('context');
|