@jinntec/fore 1.0.0-0 → 1.0.0-3
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/README.md +17 -1
- package/dist/fore-all.js +10 -10
- package/dist/fore.js +1 -1
- package/index.js +8 -0
- package/package.json +4 -1
- package/resources/fore.css +111 -1
- package/src/DependencyNotifyingDomFacade.js +9 -1
- package/src/ForeElementMixin.js +25 -17
- package/src/actions/abstract-action.js +8 -7
- package/src/actions/fx-action.js +6 -1
- package/src/actions/fx-dispatch.js +10 -2
- package/src/actions/fx-hide.js +23 -0
- package/src/actions/fx-insert.js +14 -10
- package/src/actions/fx-send.js +1 -1
- package/src/actions/fx-setvalue.js +2 -4
- package/src/actions/fx-show.js +23 -0
- package/src/dep_graph.js +9 -0
- package/src/drawdown.js +172 -0
- package/src/fore.js +94 -3
- package/src/functions/fx-function.js +2 -2
- package/src/fx-bind.js +20 -17
- package/src/fx-fore.js +306 -33
- package/src/fx-instance.js +27 -6
- package/src/fx-model.js +182 -41
- package/src/fx-submission.js +29 -7
- package/src/fx-var.js +43 -0
- package/src/getInScopeContext.js +28 -7
- package/src/modelitem.js +1 -0
- package/src/ui/abstract-control.js +21 -6
- package/src/ui/fx-alert.js +16 -20
- package/src/ui/fx-container.js +9 -4
- package/src/ui/fx-control.js +76 -39
- package/src/ui/fx-dialog.js +68 -0
- package/src/ui/fx-inspector.js +44 -0
- package/src/ui/fx-items.js +120 -0
- package/src/ui/fx-output.js +77 -9
- package/src/ui/fx-repeat.js +86 -16
- package/src/ui/fx-repeatitem.js +16 -3
- package/src/ui/fx-trigger.js +3 -0
- package/src/xpath-evaluation.js +609 -267
- package/src/xpath-util.js +52 -12
package/src/fx-model.js
CHANGED
|
@@ -16,11 +16,13 @@ export class FxModel extends HTMLElement {
|
|
|
16
16
|
this.instances = [];
|
|
17
17
|
this.modelItems = [];
|
|
18
18
|
this.defaultContext = {};
|
|
19
|
+
this.changed = [];
|
|
19
20
|
|
|
20
21
|
// this.mainGraph = new DepGraph(false);
|
|
21
22
|
this.inited = false;
|
|
22
23
|
this.modelConstructed = false;
|
|
23
24
|
this.attachShadow({ mode: 'open' });
|
|
25
|
+
this.computes = 0;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
get formElement() {
|
|
@@ -39,7 +41,7 @@ export class FxModel extends HTMLElement {
|
|
|
39
41
|
console.log('model-construct-done fired ', e.detail.model.instances);
|
|
40
42
|
});
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
this.skipUpdate = false;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
static lazyCreateModelItem(model, ref, node) {
|
|
@@ -83,10 +85,20 @@ export class FxModel extends HTMLElement {
|
|
|
83
85
|
return mi;
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
/**
|
|
89
|
+
* modelConstruct starts actual processing of the model by
|
|
90
|
+
*
|
|
91
|
+
* 1. loading instances if present or constructing one
|
|
92
|
+
* 2. calling updateModel to run the model update cycle of rebuild, recalculate and revalidate
|
|
93
|
+
*
|
|
94
|
+
* @event model-construct-done is fired once all instances have be loaded or after generating instance
|
|
95
|
+
*
|
|
96
|
+
*/
|
|
86
97
|
modelConstruct() {
|
|
87
98
|
console.log('### <<<<< dispatching model-construct >>>>>');
|
|
88
99
|
this.dispatchEvent(new CustomEvent('model-construct', { detail: this }));
|
|
89
100
|
|
|
101
|
+
console.time('instance-loading');
|
|
90
102
|
const instances = this.querySelectorAll('fx-instance');
|
|
91
103
|
if (instances.length > 0) {
|
|
92
104
|
console.group('init instances');
|
|
@@ -121,6 +133,7 @@ export class FxModel extends HTMLElement {
|
|
|
121
133
|
}),
|
|
122
134
|
);
|
|
123
135
|
}
|
|
136
|
+
console.timeEnd('instance-loading');
|
|
124
137
|
this.inited = true;
|
|
125
138
|
}
|
|
126
139
|
|
|
@@ -133,33 +146,46 @@ export class FxModel extends HTMLElement {
|
|
|
133
146
|
* update action triggering the update cycle
|
|
134
147
|
*/
|
|
135
148
|
updateModel() {
|
|
149
|
+
console.time('updateModel');
|
|
136
150
|
this.rebuild();
|
|
151
|
+
if(this.skipUpdate) return;
|
|
137
152
|
this.recalculate();
|
|
138
153
|
this.revalidate();
|
|
154
|
+
console.timeEnd('updateModel');
|
|
139
155
|
}
|
|
140
156
|
|
|
141
157
|
rebuild() {
|
|
142
158
|
console.group('### rebuild');
|
|
143
|
-
|
|
144
|
-
this.mainGraph = new DepGraph(false);
|
|
159
|
+
console.time('rebuild');
|
|
160
|
+
this.mainGraph = new DepGraph(false); //do: should be moved down below binds.length check but causes errors in tests.
|
|
145
161
|
this.modelItems = [];
|
|
146
162
|
|
|
147
163
|
// trigger recursive initialization of the fx-bind elements
|
|
148
164
|
const binds = this.querySelectorAll('fx-model > fx-bind');
|
|
165
|
+
if(binds.length === 0 ) {
|
|
166
|
+
console.log('skipped model update');
|
|
167
|
+
this.skipUpdate = true;
|
|
168
|
+
return ;
|
|
169
|
+
}
|
|
170
|
+
|
|
149
171
|
binds.forEach(bind => {
|
|
150
172
|
bind.init(this);
|
|
151
173
|
});
|
|
174
|
+
console.timeEnd('rebuild');
|
|
152
175
|
|
|
153
176
|
// console.log(`dependencies of a `, this.mainGraph.dependenciesOf("/Q{}data[1]/Q{}a[1]:required"));
|
|
154
177
|
// console.log(`dependencies of b `, this.mainGraph.dependenciesOf("/Q{}data[1]/Q{}b[1]:required"));
|
|
155
178
|
console.log(`rebuild mainGraph`, this.mainGraph);
|
|
156
179
|
console.log(`rebuild mainGraph calc order`, this.mainGraph.overallOrder());
|
|
180
|
+
|
|
181
|
+
this.dispatchEvent(new CustomEvent('rebuild-done', { detail: { maingraph: this.mainGraph } }));
|
|
182
|
+
|
|
157
183
|
/*
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
*/
|
|
184
|
+
console.log(
|
|
185
|
+
`rebuild finished with modelItems ${this.modelItems.length} item(s)`,
|
|
186
|
+
this.modelItems,
|
|
187
|
+
);
|
|
188
|
+
*/
|
|
163
189
|
console.groupEnd();
|
|
164
190
|
}
|
|
165
191
|
|
|
@@ -170,38 +196,70 @@ export class FxModel extends HTMLElement {
|
|
|
170
196
|
*/
|
|
171
197
|
recalculate() {
|
|
172
198
|
console.group('### recalculate');
|
|
173
|
-
console.log('
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
console.log('changed nodes ', this.changed);
|
|
200
|
+
|
|
201
|
+
console.time('recalculate');
|
|
202
|
+
this.computes = 0;
|
|
203
|
+
|
|
204
|
+
this.subgraph = new DepGraph(false);
|
|
205
|
+
if (this.changed.length !== 0) {
|
|
206
|
+
// ### build the subgraph
|
|
207
|
+
this.changed.forEach(modelItem => {
|
|
208
|
+
this.subgraph.addNode(modelItem.path, modelItem.node);
|
|
209
|
+
// const dependents = this.mainGraph.dependantsOf(modelItem.path, false);
|
|
210
|
+
// this._addSubgraphDependencies(modelItem.path);
|
|
211
|
+
if (this.mainGraph.hasNode(modelItem.path)) {
|
|
212
|
+
// const dependents = this.mainGraph.directDependantsOf(modelItem.path)
|
|
213
|
+
|
|
214
|
+
const all = this.mainGraph.dependantsOf(modelItem.path, false);
|
|
215
|
+
const dependents = all.reverse();
|
|
216
|
+
if (dependents.length !== 0) {
|
|
217
|
+
dependents.forEach(dep => {
|
|
218
|
+
// const subdep = this.mainGraph.dependentsOf(dep,false);
|
|
219
|
+
// subgraph.addDependency(dep, modelItem.path);
|
|
220
|
+
const val = this.mainGraph.getNodeData(dep);
|
|
221
|
+
this.subgraph.addNode(dep, val);
|
|
222
|
+
if (dep.includes(':')) {
|
|
223
|
+
const path = dep.substring(0, dep.indexOf(':'));
|
|
224
|
+
this.subgraph.addNode(path, val);
|
|
225
|
+
|
|
226
|
+
const deps = this.mainGraph.dependentsOf(modelItem.path, false);
|
|
227
|
+
// if we find the dep to be first in list of dependents we are dependent on ourselves not adding edge to modelItem.path
|
|
228
|
+
if (deps.indexOf(dep) !== 0) {
|
|
229
|
+
this.subgraph.addDependency(dep, modelItem.path);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// subgraph.addDependency(dep,modelItem.path);
|
|
233
|
+
});
|
|
201
234
|
}
|
|
202
235
|
}
|
|
203
|
-
}
|
|
204
|
-
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// ### compute the subgraph
|
|
239
|
+
const ordered = this.subgraph.overallOrder(false);
|
|
240
|
+
ordered.forEach(path => {
|
|
241
|
+
if (this.mainGraph.hasNode(path)) {
|
|
242
|
+
const node = this.mainGraph.getNodeData(path);
|
|
243
|
+
this.compute(node, path);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
const toRefresh = [...this.changed];
|
|
247
|
+
this.formElement.toRefresh = toRefresh;
|
|
248
|
+
this.changed = [];
|
|
249
|
+
console.log('subgraph', this.subgraph);
|
|
250
|
+
this.dispatchEvent(
|
|
251
|
+
new CustomEvent('recalculate-done', { detail: { subgraph: this.subgraph } }),
|
|
252
|
+
);
|
|
253
|
+
} else {
|
|
254
|
+
const v = this.mainGraph.overallOrder(false);
|
|
255
|
+
v.forEach(path => {
|
|
256
|
+
const node = this.mainGraph.getNodeData(path);
|
|
257
|
+
this.compute(node, path);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
console.log(`recalculated ${this.computes} modelItems`);
|
|
261
|
+
|
|
262
|
+
console.timeEnd('recalculate');
|
|
205
263
|
console.log(
|
|
206
264
|
`recalculate finished with modelItems ${this.modelItems.length} item(s)`,
|
|
207
265
|
this.modelItems,
|
|
@@ -209,6 +267,86 @@ export class FxModel extends HTMLElement {
|
|
|
209
267
|
console.groupEnd();
|
|
210
268
|
}
|
|
211
269
|
|
|
270
|
+
/*
|
|
271
|
+
_addSubgraphDependencies(path){
|
|
272
|
+
const dependents = this.mainGraph.directDependantsOf(path)
|
|
273
|
+
|
|
274
|
+
const alreadyInGraph = this.subgraph.incomingEdges[path];
|
|
275
|
+
// const alreadyInGraph = path in this.subgraph;
|
|
276
|
+
if(dependents.length !== 0 && alreadyInGraph.length === 0){
|
|
277
|
+
|
|
278
|
+
dependents.forEach(dep => {
|
|
279
|
+
// const val= this.mainGraph.getNodeData(dep);
|
|
280
|
+
// this.subgraph.addNode(dep,val);
|
|
281
|
+
if(dep.includes(':')){
|
|
282
|
+
const subpath = dep.substring(0, dep.indexOf(':'));
|
|
283
|
+
// this.subgraph.addNode(subpath,val);
|
|
284
|
+
this.subgraph.addDependency(subpath,dep);
|
|
285
|
+
this.subgraph.addDependency(dep,path);
|
|
286
|
+
/!*
|
|
287
|
+
const subdeps = this.mainGraph.directDependantsOf(path);
|
|
288
|
+
console.log('subdeps',path, subdeps);
|
|
289
|
+
subdeps.forEach(sdep => {
|
|
290
|
+
const sval= this.mainGraph.getNodeData(sdep);
|
|
291
|
+
this.subgraph.addNode(sdep,sval);
|
|
292
|
+
console.log('subdep',sdep);
|
|
293
|
+
});
|
|
294
|
+
*!/
|
|
295
|
+
if(this.subgraph.incomingEdges[dep] === 0){
|
|
296
|
+
this._addSubgraphDependencies(subpath)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
}
|
|
305
|
+
*/
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* (re-) computes a modelItem.
|
|
309
|
+
* @param node - the node the modelItem is attached to
|
|
310
|
+
* @param path - the canonical XPath of the node
|
|
311
|
+
*/
|
|
312
|
+
compute(node, path) {
|
|
313
|
+
const modelItem = this.getModelItem(node);
|
|
314
|
+
if (modelItem && path.includes(':')) {
|
|
315
|
+
const property = path.split(':')[1];
|
|
316
|
+
if (property) {
|
|
317
|
+
/*
|
|
318
|
+
if (property === 'readonly') {
|
|
319
|
+
// make sure that calculated items are always readonly
|
|
320
|
+
if(modelItem.bind['calculate']){
|
|
321
|
+
modelItem.readonly = true;
|
|
322
|
+
}else {
|
|
323
|
+
const expr = modelItem.bind[property];
|
|
324
|
+
const compute = evaluateXPathToBoolean(expr, modelItem.node, this);
|
|
325
|
+
modelItem.readonly = compute;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
*/
|
|
329
|
+
if (property === 'calculate') {
|
|
330
|
+
const expr = modelItem.bind[property];
|
|
331
|
+
const compute = evaluateXPath(expr, modelItem.node, this);
|
|
332
|
+
modelItem.value = compute;
|
|
333
|
+
modelItem.readonly = true; // calculated nodes are always readonly
|
|
334
|
+
} else if (property !== 'constraint' && property !== 'type') {
|
|
335
|
+
const expr = modelItem.bind[property];
|
|
336
|
+
if (expr) {
|
|
337
|
+
const compute = evaluateXPathToBoolean(expr, modelItem.node, this);
|
|
338
|
+
modelItem[property] = compute;
|
|
339
|
+
console.log(
|
|
340
|
+
`recalculating path ${path} - Expr:'${expr}' computed`,
|
|
341
|
+
modelItem[property],
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
this.computes += 1;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
212
350
|
/**
|
|
213
351
|
* Iterates all modelItems to calculate the validation status.
|
|
214
352
|
*
|
|
@@ -228,6 +366,7 @@ export class FxModel extends HTMLElement {
|
|
|
228
366
|
revalidate() {
|
|
229
367
|
console.group('### revalidate');
|
|
230
368
|
|
|
369
|
+
console.time('revalidate');
|
|
231
370
|
let valid = true;
|
|
232
371
|
this.modelItems.forEach(modelItem => {
|
|
233
372
|
// console.log('validating node ', modelItem.node);
|
|
@@ -235,15 +374,16 @@ export class FxModel extends HTMLElement {
|
|
|
235
374
|
const { bind } = modelItem;
|
|
236
375
|
if (bind) {
|
|
237
376
|
/*
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
377
|
+
todo: investigate why bind is an element when created in fx-bind.init() and an fx-bind object when
|
|
378
|
+
created lazily.
|
|
379
|
+
*/
|
|
241
380
|
if (typeof bind.hasAttribute === 'function' && bind.hasAttribute('constraint')) {
|
|
242
381
|
const constraint = bind.getAttribute('constraint');
|
|
243
382
|
if (constraint) {
|
|
244
383
|
const compute = evaluateXPathToBoolean(constraint, modelItem.node, this);
|
|
245
384
|
console.log('modelItem validity computed: ', compute);
|
|
246
385
|
modelItem.constraint = compute;
|
|
386
|
+
this.formElement.addToRefresh(modelItem); // let fore know that modelItem needs refresh
|
|
247
387
|
if (!compute) valid = false;
|
|
248
388
|
// ### alerts are added only once during model-construct. Otherwise they would add up in each run of revalidate()
|
|
249
389
|
if (!this.modelConstructed) {
|
|
@@ -257,6 +397,7 @@ export class FxModel extends HTMLElement {
|
|
|
257
397
|
}
|
|
258
398
|
}
|
|
259
399
|
});
|
|
400
|
+
console.timeEnd('revalidate');
|
|
260
401
|
console.log('modelItems after revalidate: ', this.modelItems);
|
|
261
402
|
console.groupEnd();
|
|
262
403
|
return valid;
|
package/src/fx-submission.js
CHANGED
|
@@ -26,6 +26,9 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
26
26
|
/** if present should be a existing instance id */
|
|
27
27
|
this.instance = this.hasAttribute('instance') ? this.getAttribute('instance') : null;
|
|
28
28
|
|
|
29
|
+
/** if present will determine XPath where to insert a response into when mode is 'replace' */
|
|
30
|
+
this.into = this.hasAttribute('into') ? this.getAttribute('into') : null;
|
|
31
|
+
|
|
29
32
|
/** http method */
|
|
30
33
|
this.method = this.hasAttribute('method') ? this.getAttribute('method') : 'get';
|
|
31
34
|
|
|
@@ -78,6 +81,9 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
78
81
|
const valid = model.revalidate();
|
|
79
82
|
if (!valid) {
|
|
80
83
|
console.log('validation failed. Bubmission stopped');
|
|
84
|
+
// ### allow alerts to pop up
|
|
85
|
+
this.dispatch('submit-error', {});
|
|
86
|
+
this.getModel().parentNode.refresh();
|
|
81
87
|
return;
|
|
82
88
|
}
|
|
83
89
|
}
|
|
@@ -173,9 +179,17 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
173
179
|
body: serialized,
|
|
174
180
|
});
|
|
175
181
|
|
|
176
|
-
|
|
182
|
+
if (!response.ok || response.status > 400) {
|
|
183
|
+
this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
177
186
|
|
|
178
|
-
|
|
187
|
+
const contentType = response.headers.get('content-type').toLowerCase();
|
|
188
|
+
if (
|
|
189
|
+
contentType.startsWith('text/plain') ||
|
|
190
|
+
contentType.startsWith('text/html') ||
|
|
191
|
+
contentType.startsWith('text/markdown')
|
|
192
|
+
) {
|
|
179
193
|
const text = await response.text();
|
|
180
194
|
this._handleResponse(text);
|
|
181
195
|
} else if (contentType.startsWith('application/json')) {
|
|
@@ -190,10 +204,6 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
190
204
|
this._handleResponse(blob);
|
|
191
205
|
}
|
|
192
206
|
|
|
193
|
-
if (!response.ok || response.status > 400) {
|
|
194
|
-
this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
207
|
this.dispatch('submit-done', {});
|
|
198
208
|
}
|
|
199
209
|
|
|
@@ -265,12 +275,24 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
|
265
275
|
const targetInstance = this._getTargetInstance();
|
|
266
276
|
if (targetInstance) {
|
|
267
277
|
if (this.targetref) {
|
|
268
|
-
const theTarget = evaluateXPath(
|
|
278
|
+
const theTarget = evaluateXPath(
|
|
279
|
+
this.targetref,
|
|
280
|
+
targetInstance.instanceData.firstElementChild,
|
|
281
|
+
this,
|
|
282
|
+
);
|
|
269
283
|
console.log('theTarget', theTarget);
|
|
270
284
|
const clone = data.firstElementChild;
|
|
271
285
|
const parent = theTarget.parentNode;
|
|
272
286
|
parent.replaceChild(clone, theTarget);
|
|
273
287
|
console.log('finally ', parent);
|
|
288
|
+
} else if (this.into) {
|
|
289
|
+
const theTarget = evaluateXPath(
|
|
290
|
+
this.into,
|
|
291
|
+
targetInstance.instanceData.firstElementChild,
|
|
292
|
+
this,
|
|
293
|
+
);
|
|
294
|
+
console.log('theTarget', theTarget);
|
|
295
|
+
theTarget.innerHTML = data;
|
|
274
296
|
} else {
|
|
275
297
|
const instanceData = data;
|
|
276
298
|
targetInstance.instanceData = instanceData;
|
package/src/fx-var.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import './fx-instance.js';
|
|
2
|
+
import { evaluateXPath } from './xpath-evaluation.js';
|
|
3
|
+
import { foreElementMixin } from './ForeElementMixin.js';
|
|
4
|
+
import getInScopeContext from './getInScopeContext.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @ts-check
|
|
8
|
+
*/
|
|
9
|
+
export class FxVariable extends foreElementMixin(HTMLElement) {
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
|
|
13
|
+
this.attachShadow({ mode: 'open' });
|
|
14
|
+
this.name = '';
|
|
15
|
+
this.valueQuery = '';
|
|
16
|
+
this.value = null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
connectedCallback() {
|
|
20
|
+
this.name = this.getAttribute('name');
|
|
21
|
+
this.valueQuery = this.getAttribute('value');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
refresh() {
|
|
25
|
+
const inscope = getInScopeContext(this, this.valueQuery);
|
|
26
|
+
|
|
27
|
+
this.value = evaluateXPath(this.valueQuery, inscope, this, this.precedingVariables);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
setInScopeVariables(inScopeVariables) {
|
|
31
|
+
if (inScopeVariables.has(this.name)) {
|
|
32
|
+
console.error(`The variable ${this.name} is declared more than once`);
|
|
33
|
+
this.dispatch('xforms-binding-error');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
inScopeVariables.set(this.name, this);
|
|
37
|
+
// Clone the preceding variables to make sure we are not going to get access to variables we
|
|
38
|
+
// should not get access to
|
|
39
|
+
this.inScopeVariables = new Map(inScopeVariables);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
customElements.define('fx-var', FxVariable);
|
package/src/getInScopeContext.js
CHANGED
|
@@ -2,10 +2,18 @@ import { evaluateXPathToFirstNode } from './xpath-evaluation.js';
|
|
|
2
2
|
|
|
3
3
|
import { XPathUtil } from './xpath-util.js';
|
|
4
4
|
|
|
5
|
-
function
|
|
5
|
+
function _getElement(node) {
|
|
6
6
|
if (node.nodeType === Node.ATTRIBUTE_NODE) {
|
|
7
|
+
// The context of an attribute is the ref of the element it's defined on
|
|
7
8
|
return node.ownerElement;
|
|
8
9
|
}
|
|
10
|
+
|
|
11
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
12
|
+
// The context of a query should be the element having a ref
|
|
13
|
+
return node;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// For text nodes, just start looking from the parent element
|
|
9
17
|
return node.parentNode;
|
|
10
18
|
}
|
|
11
19
|
|
|
@@ -31,14 +39,14 @@ function _getInitialContext(node, ref) {
|
|
|
31
39
|
const instanceId = XPathUtil.getInstanceId(ref);
|
|
32
40
|
return model.getInstance(instanceId).getDefaultContext();
|
|
33
41
|
}
|
|
34
|
-
if (model.getDefaultInstance() !== null) {
|
|
42
|
+
if (model.getDefaultInstance() !== null && model.inited) {
|
|
35
43
|
return model.getDefaultInstance().getDefaultContext();
|
|
36
44
|
}
|
|
37
45
|
return [];
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
export default function getInScopeContext(node, ref) {
|
|
41
|
-
const parentElement =
|
|
49
|
+
const parentElement = _getElement(node);
|
|
42
50
|
/*
|
|
43
51
|
if(parentElement.nodeName.toUpperCase() === 'FX-REPEATITEM'){
|
|
44
52
|
return parentElement.nodeset;
|
|
@@ -50,10 +58,23 @@ export default function getInScopeContext(node, ref) {
|
|
|
50
58
|
return repeatItem.nodeset;
|
|
51
59
|
}
|
|
52
60
|
|
|
53
|
-
if (node.nodeType === Node.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
if (node.nodeType === Node.ATTRIBUTE_NODE && node.nodeName === 'ref') {
|
|
62
|
+
// Note: do not consider the ref of the owner element since it should not be used to define the
|
|
63
|
+
// context
|
|
64
|
+
if (node.ownerElement.hasAttribute('context')) {
|
|
65
|
+
const initialContext = _getInitialContext(node.ownerElement.parentNode, ref);
|
|
66
|
+
const contextAttr = node.ownerElement.getAttribute('context');
|
|
67
|
+
return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Never resolve the context from a ref itself!
|
|
71
|
+
return _getInitialContext(parentElement.parentNode, ref);
|
|
57
72
|
}
|
|
73
|
+
|
|
74
|
+
// if (node.nodeType === Node.ELEMENT_NODE && node.hasAttribute('context')) {
|
|
75
|
+
// const initialContext = _getInitialContext(node.parentNode, ref);
|
|
76
|
+
// const contextAttr = node.getAttribute('context');
|
|
77
|
+
// return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
|
|
78
|
+
// }
|
|
58
79
|
return _getInitialContext(parentElement, ref);
|
|
59
80
|
}
|
package/src/modelitem.js
CHANGED
|
@@ -26,12 +26,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
26
26
|
/**
|
|
27
27
|
* (re)apply all modelItem state properties to this control. model -> UI
|
|
28
28
|
*/
|
|
29
|
-
async refresh() {
|
|
30
|
-
console.log('### AbstractControl.refresh on : ', this);
|
|
29
|
+
async refresh(force) {
|
|
30
|
+
// console.log('### AbstractControl.refresh on : ', this);
|
|
31
31
|
|
|
32
32
|
const currentVal = this.value;
|
|
33
33
|
|
|
34
|
-
// if(this.repeated) return
|
|
34
|
+
// if(this.repeated) return
|
|
35
35
|
if (this.isNotBound()) return;
|
|
36
36
|
|
|
37
37
|
// await this.updateComplete;
|
|
@@ -52,6 +52,14 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
52
52
|
// console.log('### XfAbstractControl.refresh modelItem : ', this.modelItem);
|
|
53
53
|
|
|
54
54
|
this.value = this.modelItem.value;
|
|
55
|
+
|
|
56
|
+
/*
|
|
57
|
+
this is another case that highlights the fact that an init() function might make sense in general.
|
|
58
|
+
*/
|
|
59
|
+
if(!this.modelItem.boundControls.includes(this)){
|
|
60
|
+
this.modelItem.boundControls.push(this);
|
|
61
|
+
}
|
|
62
|
+
|
|
55
63
|
// console.log('>>>>>>>> abstract refresh ', this.control);
|
|
56
64
|
// this.control[this.valueProp] = this.value;
|
|
57
65
|
await this.updateWidgetValue();
|
|
@@ -67,16 +75,21 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
67
75
|
// this.requestUpdate();
|
|
68
76
|
}
|
|
69
77
|
}
|
|
78
|
+
// Fore.refreshChildren(this,force);
|
|
70
79
|
// await this.updateComplete;
|
|
71
80
|
}
|
|
72
81
|
|
|
82
|
+
/**
|
|
83
|
+
*
|
|
84
|
+
* @returns {Promise<void>}
|
|
85
|
+
*/
|
|
73
86
|
// eslint-disable-next-line class-methods-use-this
|
|
74
87
|
async updateWidgetValue() {
|
|
75
88
|
throw new Error('You have to implement the method updateWidgetValue!');
|
|
76
89
|
}
|
|
77
90
|
|
|
78
91
|
handleModelItemProperties() {
|
|
79
|
-
console.log('form ready', this.getOwnerForm().ready);
|
|
92
|
+
// console.log('form ready', this.getOwnerForm().ready);
|
|
80
93
|
this.handleRequired();
|
|
81
94
|
this.handleReadonly();
|
|
82
95
|
if (this.getOwnerForm().ready) {
|
|
@@ -175,10 +188,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
175
188
|
if (this.isEnabled() !== this.modelItem.relevant) {
|
|
176
189
|
if (this.modelItem.relevant) {
|
|
177
190
|
this._dispatchEvent('relevant');
|
|
178
|
-
this._fadeIn(this, this.display);
|
|
191
|
+
// this._fadeIn(this, this.display);
|
|
192
|
+
this.style.display = this.display;
|
|
179
193
|
} else {
|
|
180
194
|
this._dispatchEvent('nonrelevant');
|
|
181
|
-
this._fadeOut(this);
|
|
195
|
+
// this._fadeOut(this);
|
|
196
|
+
this.style.display = 'none';
|
|
182
197
|
}
|
|
183
198
|
}
|
|
184
199
|
}
|
package/src/ui/fx-alert.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import AbstractControl from './abstract-control.js';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export class FxAlert extends AbstractControl {
|
|
4
|
+
constructor() {
|
|
5
|
+
super();
|
|
6
|
+
this.attachShadow({ mode: 'open' });
|
|
7
|
+
}
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
return css`
|
|
9
|
+
connectedCallback() {
|
|
10
|
+
const style = `
|
|
8
11
|
:host {
|
|
9
|
-
display: block;
|
|
10
12
|
height: auto;
|
|
11
13
|
font-size: 0.8em;
|
|
12
14
|
font-weight: 400;
|
|
@@ -14,23 +16,17 @@ export class FxAlert extends XfAbstractControl {
|
|
|
14
16
|
display: none;
|
|
15
17
|
}
|
|
16
18
|
`;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
constructor() {
|
|
20
|
-
super();
|
|
21
|
-
this.style.display = 'none';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static get properties() {
|
|
25
|
-
return {
|
|
26
|
-
...super.properties,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
19
|
|
|
30
|
-
|
|
31
|
-
return html`
|
|
20
|
+
const html = `
|
|
32
21
|
<slot></slot>
|
|
33
22
|
`;
|
|
23
|
+
|
|
24
|
+
this.shadowRoot.innerHTML = `
|
|
25
|
+
<style>
|
|
26
|
+
${style}
|
|
27
|
+
</style>
|
|
28
|
+
${html}
|
|
29
|
+
`;
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
async updateWidgetValue() {
|