@jinntec/fore 1.5.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 +12 -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-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 +7 -7
- package/src/fx-fore.js +152 -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-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 +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-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
1
|
import { evaluateXPathToFirstNode } from './xpath-evaluation.js';
|
|
2
|
-
import {Fore} from './fore.js';
|
|
3
|
-
|
|
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(
|
|
@@ -80,8 +78,8 @@ export default function getInScopeContext(node, ref) {
|
|
|
80
78
|
}
|
|
81
79
|
|
|
82
80
|
// ### check for repeatitems created by fx-repeat-attributes - this could possibly be unified with standard repeats
|
|
83
|
-
// const repeatItemFromAttrs =
|
|
84
|
-
// const repeatItemFromAttrs =
|
|
81
|
+
// const repeatItemFromAttrs = XPathUtil.getClosest('.fx-repeatitem', parentElement);
|
|
82
|
+
// const repeatItemFromAttrs = XPathUtil.getClosest('.fx-repeatitem', parentElement);
|
|
85
83
|
const repeatItemFromAttrs = parentElement.closest('.fx-repeatitem');
|
|
86
84
|
|
|
87
85
|
if (repeatItemFromAttrs) {
|
|
@@ -91,7 +89,7 @@ export default function getInScopeContext(node, ref) {
|
|
|
91
89
|
const index = Array.from(parent.children).indexOf(repeatItemFromAttrs);
|
|
92
90
|
|
|
93
91
|
// ### fetching nodeset from fx-repeat-attributes element
|
|
94
|
-
const repeatFromAttributes =
|
|
92
|
+
const repeatFromAttributes = XPathUtil.getClosest('fx-repeat-attributes', parentElement);
|
|
95
93
|
return repeatFromAttributes.nodeset[index];
|
|
96
94
|
}
|
|
97
95
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* a simple component that wraps a Fore page and puts it into shadowDom.
|
|
3
|
+
*
|
|
4
|
+
* HTML link elements passed as children will be used to construct a CSSStyleSheet that is passed
|
|
5
|
+
* to the shadowDOM.
|
|
6
|
+
* @customElement
|
|
7
|
+
*/
|
|
8
|
+
export class ForeComponent extends HTMLElement {
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
this.attachShadow({mode: 'open'})
|
|
12
|
+
this.src = ''
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
connectedCallback() {
|
|
16
|
+
this.src= this.getAttribute('src');
|
|
17
|
+
const style = `
|
|
18
|
+
:host {
|
|
19
|
+
display:block;
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
const html = `
|
|
23
|
+
<fx-fore src="${this.src}">
|
|
24
|
+
</fx-fore>
|
|
25
|
+
<slot id="default"></slot>
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
this.shadowRoot.innerHTML = `
|
|
29
|
+
<style>
|
|
30
|
+
${style}
|
|
31
|
+
</style>
|
|
32
|
+
${html}
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
* wait for slotchange, then filter document.stylesheets to construct CSSStyleSheet
|
|
37
|
+
*/
|
|
38
|
+
const slot = this.shadowRoot.querySelector('#default');
|
|
39
|
+
slot.addEventListener('slotchange', async event => {
|
|
40
|
+
const children = event.target.assignedElements();
|
|
41
|
+
const hostedStylesheet = children.filter(
|
|
42
|
+
linkElem => linkElem.nodeName.toUpperCase() === 'LINK',
|
|
43
|
+
);
|
|
44
|
+
if(!hostedStylesheet) return;
|
|
45
|
+
const allCSS = [...document.styleSheets]
|
|
46
|
+
.map((styleSheet) => {
|
|
47
|
+
if(hostedStylesheet.find(sh => sh.href === styleSheet.href)){
|
|
48
|
+
try {
|
|
49
|
+
return [...styleSheet.cssRules]
|
|
50
|
+
.map((rule) => rule.cssText)
|
|
51
|
+
.join('');
|
|
52
|
+
} catch (e) {
|
|
53
|
+
console.log('Access to stylesheet %s is denied. Ignoring…', styleSheet.href);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
.join('\n');
|
|
59
|
+
|
|
60
|
+
const sheet = new CSSStyleSheet();
|
|
61
|
+
sheet.replaceSync(allCSS);
|
|
62
|
+
this.shadowRoot.adoptedStyleSheets = [sheet];
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/*
|
|
66
|
+
const eventSlot = this.shadowRoot.querySelector('slot[name="event"]');
|
|
67
|
+
eventSlot.addEventListener('slotchange', async event => {
|
|
68
|
+
const children = event.target.assignedElements();
|
|
69
|
+
console.log('events', children)
|
|
70
|
+
});
|
|
71
|
+
*/
|
|
72
|
+
const eventTmpl = this.querySelector('fx-action');
|
|
73
|
+
if(eventTmpl){
|
|
74
|
+
// const clone = eventTmpl.content.cloneNode(true);
|
|
75
|
+
const clone = eventTmpl.cloneNode(true);
|
|
76
|
+
this.removeChild(eventTmpl);
|
|
77
|
+
// const content = document.importNode(clone, true);
|
|
78
|
+
|
|
79
|
+
const fore = this.shadowRoot.querySelector('fx-fore');
|
|
80
|
+
// fore.appendChild(content.firstElementChild);
|
|
81
|
+
fore.appendChild(clone);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!customElements.get('fore-component')) {
|
|
89
|
+
customElements.define('fore-component', ForeComponent);
|
|
90
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import '../../index.js';
|
|
2
|
+
// import '@jinntec/jinn-codemirror/src/jinn-code-mirror.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* a simple component that wraps a Fore page and puts it into shadowDom.
|
|
6
|
+
*
|
|
7
|
+
* HTML link elements passed as children will be used to construct a CSSStyleSheet that is passed
|
|
8
|
+
* to the shadowDOM.
|
|
9
|
+
* @customElement
|
|
10
|
+
*/
|
|
11
|
+
export class InstanceInspector extends HTMLElement {
|
|
12
|
+
constructor() {
|
|
13
|
+
super();
|
|
14
|
+
this.attachShadow({mode: 'open'})
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
connectedCallback() {
|
|
18
|
+
this.id= this.getAttribute('id');
|
|
19
|
+
const style = `
|
|
20
|
+
:host {
|
|
21
|
+
display:block;
|
|
22
|
+
background:blue;
|
|
23
|
+
}
|
|
24
|
+
section, fx-control, jinn-codemirror{
|
|
25
|
+
display:block;
|
|
26
|
+
width:100%;
|
|
27
|
+
height:100%;
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
const html = `
|
|
31
|
+
<section>
|
|
32
|
+
<fx-control ref="instance('${this.id}')" as="node">
|
|
33
|
+
<label>${this.id}</label>
|
|
34
|
+
<jinn-codemirror mode="xml" class="widget"></jinn-codemirror>
|
|
35
|
+
</fx-control>
|
|
36
|
+
</section>
|
|
37
|
+
<slot></slot>
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
this.innerHTML = `
|
|
41
|
+
<style>
|
|
42
|
+
${style}
|
|
43
|
+
</style>
|
|
44
|
+
${html}
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
this.closest('fx-fore').refresh();
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!customElements.get('instance-inspector')) {
|
|
55
|
+
customElements.define('instance-inspector', InstanceInspector);
|
|
56
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<fx-fore>
|
|
2
|
+
<fx-message event="ready">hey from component</fx-message>
|
|
3
|
+
<fx-model>
|
|
4
|
+
<fx-instance>
|
|
5
|
+
<data>
|
|
6
|
+
<greeting>Hello Universe</greeting>
|
|
7
|
+
</data>
|
|
8
|
+
</fx-instance>
|
|
9
|
+
</fx-model>
|
|
10
|
+
|
|
11
|
+
<div class="static {greeting}">Greeting: {greeting}</div>
|
|
12
|
+
<fx-control ref="greeting" update-event="input">
|
|
13
|
+
<label>Hey!</label>
|
|
14
|
+
</fx-control>
|
|
15
|
+
<!-- <slot></slot>-->
|
|
16
|
+
</fx-fore>
|
package/src/relevance.js
CHANGED
|
@@ -38,6 +38,19 @@ export class Relevance {
|
|
|
38
38
|
const { attributes } = n;
|
|
39
39
|
if (attributes) {
|
|
40
40
|
Array.from(attributes).forEach(attr => {
|
|
41
|
+
if (element.nonrelevant === 'empty' && !Relevance._isRelevant(element, attr)) {
|
|
42
|
+
clone.setAttribute(attr.nodeName, '');
|
|
43
|
+
}else
|
|
44
|
+
if (Relevance._isRelevant(element, attr)) {
|
|
45
|
+
clone.setAttribute(attr.nodeName, attr.value);
|
|
46
|
+
} else {
|
|
47
|
+
// if (element.nonrelevant === 'empty') {
|
|
48
|
+
// clone.setAttribute(attr.nodeName, '');
|
|
49
|
+
// } else{
|
|
50
|
+
clone.removeAttribute(attr.nodeName);
|
|
51
|
+
// }
|
|
52
|
+
}
|
|
53
|
+
/*
|
|
41
54
|
if (Relevance._isRelevant(element, attr)) {
|
|
42
55
|
clone.setAttribute(attr.nodeName, attr.value);
|
|
43
56
|
} else if (element.nonrelevant === 'empty') {
|
|
@@ -45,6 +58,7 @@ export class Relevance {
|
|
|
45
58
|
} else {
|
|
46
59
|
clone.removeAttribute(attr.nodeName);
|
|
47
60
|
}
|
|
61
|
+
*/
|
|
48
62
|
});
|
|
49
63
|
}
|
|
50
64
|
return Relevance._filterRelevant(element, n, clone);
|
|
@@ -56,9 +70,21 @@ export class Relevance {
|
|
|
56
70
|
|
|
57
71
|
static _isRelevant(element, node) {
|
|
58
72
|
const mi = element.getModel().getModelItem(node);
|
|
59
|
-
|
|
73
|
+
|
|
74
|
+
// ### remove empty attributes as these usually are not expected in most XML languages.
|
|
75
|
+
if(node.nodeType === Node.ATTRIBUTE_NODE
|
|
76
|
+
&& node.nodeValue === ''){
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
// ### no modelItem means no constraints
|
|
80
|
+
if(!mi){
|
|
60
81
|
return true;
|
|
61
82
|
}
|
|
83
|
+
// ### modelItem 'relevant' is defined and 'true'
|
|
84
|
+
if ( mi.relevant) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
62
88
|
return false;
|
|
63
89
|
}
|
|
64
90
|
}
|