@jinntec/fore 1.0.0-5 → 1.2.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.
Files changed (64) hide show
  1. package/README.md +7 -28
  2. package/dist/fore-dev.js +43 -0
  3. package/dist/fore-dev.js.map +1 -0
  4. package/dist/fore.js +37 -0
  5. package/dist/fore.js.map +1 -0
  6. package/index.js +3 -1
  7. package/package.json +39 -41
  8. package/resources/fore.css +27 -54
  9. package/src/DependencyNotifyingDomFacade.js +5 -13
  10. package/src/ForeElementMixin.js +15 -22
  11. package/src/actions/abstract-action.js +34 -10
  12. package/src/actions/fx-action.js +7 -5
  13. package/src/actions/fx-append.js +8 -17
  14. package/src/actions/fx-confirm.js +5 -3
  15. package/src/actions/fx-delete.js +6 -3
  16. package/src/actions/fx-dispatch.js +9 -8
  17. package/src/actions/fx-hide.js +9 -6
  18. package/src/actions/fx-insert.js +27 -14
  19. package/src/actions/fx-message.js +3 -1
  20. package/src/actions/fx-refresh.js +24 -1
  21. package/src/actions/fx-replace.js +74 -0
  22. package/src/actions/fx-return.js +42 -0
  23. package/src/actions/fx-send.js +3 -1
  24. package/src/actions/fx-setfocus.js +37 -0
  25. package/src/actions/fx-setvalue.js +58 -51
  26. package/src/actions/fx-show.js +12 -4
  27. package/src/actions/fx-toggle.js +13 -9
  28. package/src/actions/fx-update.js +3 -1
  29. package/src/dep_graph.js +1 -1
  30. package/src/drawdown.js +67 -82
  31. package/src/fore.js +143 -26
  32. package/src/functions/fx-function.js +17 -3
  33. package/src/fx-bind.js +40 -200
  34. package/src/fx-fore.js +598 -568
  35. package/src/fx-header.js +3 -1
  36. package/src/fx-instance.js +9 -1
  37. package/src/fx-model.js +60 -27
  38. package/src/fx-submission.js +108 -51
  39. package/src/fx-var.js +7 -4
  40. package/src/getInScopeContext.js +23 -16
  41. package/src/modelitem.js +4 -4
  42. package/src/relevance.js +64 -0
  43. package/src/ui/abstract-control.js +65 -37
  44. package/src/ui/fx-alert.js +7 -1
  45. package/src/ui/fx-case.js +4 -3
  46. package/src/ui/fx-container.js +4 -2
  47. package/src/ui/fx-control.js +315 -34
  48. package/src/ui/fx-dialog.js +50 -45
  49. package/src/ui/fx-group.js +3 -1
  50. package/src/ui/fx-hint.js +4 -1
  51. package/src/ui/fx-inspector.js +118 -17
  52. package/src/ui/fx-items.js +7 -5
  53. package/src/ui/fx-output.js +19 -6
  54. package/src/ui/fx-repeat.js +13 -26
  55. package/src/ui/fx-repeatitem.js +10 -4
  56. package/src/ui/fx-switch.js +5 -3
  57. package/src/ui/fx-trigger.js +3 -1
  58. package/src/xpath-evaluation.js +622 -553
  59. package/src/xpath-util.js +2 -6
  60. package/dist/fore-all.js +0 -140
  61. package/dist/fore-debug.js +0 -140
  62. package/src/.DS_Store +0 -0
  63. package/src/actions/.DS_Store +0 -0
  64. package/src/ui/.DS_Store +0 -0
package/src/fx-header.js CHANGED
@@ -17,4 +17,6 @@ export class FxHeader extends foreElementMixin(HTMLElement) {
17
17
  this.shadowRoot.innerHTML = ``;
18
18
  }
19
19
  }
20
- customElements.define('fx-header', FxHeader);
20
+ if (!customElements.get('fx-header')) {
21
+ customElements.define('fx-header', FxHeader);
22
+ }
@@ -166,6 +166,12 @@ export class FxInstance extends HTMLElement {
166
166
  },
167
167
  })
168
168
  .then(response => {
169
+ const { status } = response;
170
+ if (status >= 400) {
171
+ console.log('response status', status);
172
+ alert(`response status: ${status} - failed to load data for '${this.src}' - stopping.`);
173
+ throw new Error(`failed to load data - status: ${status}`);
174
+ }
169
175
  const responseContentType = response.headers.get('content-type').toLowerCase();
170
176
  console.log('********** responseContentType *********', responseContentType);
171
177
  if (responseContentType.startsWith('text/html')) {
@@ -257,4 +263,6 @@ export class FxInstance extends HTMLElement {
257
263
  console.log('_handleResponse ', loader.lastError);
258
264
  }
259
265
  }
260
- customElements.define('fx-instance', FxInstance);
266
+ if (!customElements.get('fx-instance')) {
267
+ customElements.define('fx-instance', FxInstance);
268
+ }
package/src/fx-model.js CHANGED
@@ -35,11 +35,11 @@ export class FxModel extends HTMLElement {
35
35
  <slot></slot>
36
36
  `;
37
37
 
38
- this.addEventListener('model-construct-done', e => {
39
- this.modelConstructed = true;
40
- // console.log('model-construct-done fired ', this.modelConstructed);
41
- console.log('model-construct-done fired ', e.detail.model.instances);
42
- });
38
+ this.addEventListener('model-construct-done', () => {
39
+ this.modelConstructed = true;
40
+ // console.log('model-construct-done fired ', this.modelConstructed);
41
+ // console.log('model-construct-done fired ', e.detail.model.instances);
42
+ },{ once: true });
43
43
 
44
44
  this.skipUpdate = false;
45
45
  }
@@ -95,8 +95,15 @@ export class FxModel extends HTMLElement {
95
95
  *
96
96
  */
97
97
  modelConstruct() {
98
- console.log('### <<<<< dispatching model-construct >>>>>');
99
- this.dispatchEvent(new CustomEvent('model-construct', { detail: this }));
98
+ // console.log('### <<<<< dispatching model-construct >>>>>');
99
+ // this.dispatchEvent(new CustomEvent('model-construct', { detail: this }));
100
+ this.dispatchEvent(
101
+ new CustomEvent('model-construct', {
102
+ composed: false,
103
+ bubbles: true,
104
+ detail: { model: this },
105
+ }),
106
+ );
100
107
 
101
108
  console.time('instance-loading');
102
109
  const instances = this.querySelectorAll('fx-instance');
@@ -109,14 +116,14 @@ export class FxModel extends HTMLElement {
109
116
 
110
117
  Promise.all(promises).then(() => {
111
118
  this.instances = Array.from(instances);
112
- console.log('_modelConstruct this.instances ', this.instances);
119
+ // console.log('_modelConstruct this.instances ', this.instances);
113
120
  this.updateModel();
114
121
  this.inited = true;
115
122
 
116
- console.log('### <<<<< dispatching model-construct-done >>>>>');
123
+ // console.log('### <<<<< dispatching model-construct-done >>>>>');
117
124
  this.dispatchEvent(
118
125
  new CustomEvent('model-construct-done', {
119
- composed: true,
126
+ composed: false,
120
127
  bubbles: true,
121
128
  detail: { model: this },
122
129
  }),
@@ -127,7 +134,7 @@ export class FxModel extends HTMLElement {
127
134
  // ### if there's no instance one will created
128
135
  this.dispatchEvent(
129
136
  new CustomEvent('model-construct-done', {
130
- composed: true,
137
+ composed: false,
131
138
  bubbles: true,
132
139
  detail: { model: this },
133
140
  }),
@@ -146,32 +153,32 @@ export class FxModel extends HTMLElement {
146
153
  * update action triggering the update cycle
147
154
  */
148
155
  updateModel() {
149
- console.time('updateModel');
156
+ // console.time('updateModel');
150
157
  this.rebuild();
151
- if(this.skipUpdate) return;
158
+ if (this.skipUpdate) return;
152
159
  this.recalculate();
153
160
  this.revalidate();
154
- console.timeEnd('updateModel');
161
+ // console.timeEnd('updateModel');
155
162
  }
156
163
 
157
164
  rebuild() {
158
165
  console.group('### rebuild');
159
166
  console.time('rebuild');
160
- this.mainGraph = new DepGraph(false); //do: should be moved down below binds.length check but causes errors in tests.
167
+ this.mainGraph = new DepGraph(false); // do: should be moved down below binds.length check but causes errors in tests.
161
168
  this.modelItems = [];
162
169
 
163
170
  // trigger recursive initialization of the fx-bind elements
164
171
  const binds = this.querySelectorAll('fx-model > fx-bind');
165
- if(binds.length === 0 ) {
166
- console.log('skipped model update');
172
+ if (binds.length === 0) {
173
+ // console.log('skipped model update');
167
174
  this.skipUpdate = true;
168
- return ;
175
+ return;
169
176
  }
170
177
 
171
178
  binds.forEach(bind => {
172
179
  bind.init(this);
173
180
  });
174
- console.timeEnd('rebuild');
181
+ // console.timeEnd('rebuild');
175
182
 
176
183
  // console.log(`dependencies of a `, this.mainGraph.dependenciesOf("/Q{}data[1]/Q{}a[1]:required"));
177
184
  // console.log(`dependencies of b `, this.mainGraph.dependenciesOf("/Q{}data[1]/Q{}b[1]:required"));
@@ -195,9 +202,14 @@ export class FxModel extends HTMLElement {
195
202
  * todo: use 'changed' flag on modelItems to determine subgraph for recalculation. Flag already exists but is not used.
196
203
  */
197
204
  recalculate() {
205
+ if(!this.mainGraph){
206
+ return;
207
+ }
208
+
198
209
  console.group('### recalculate');
199
210
  console.log('changed nodes ', this.changed);
200
211
 
212
+
201
213
  console.time('recalculate');
202
214
  this.computes = 0;
203
215
 
@@ -260,10 +272,7 @@ export class FxModel extends HTMLElement {
260
272
  console.log(`recalculated ${this.computes} modelItems`);
261
273
 
262
274
  console.timeEnd('recalculate');
263
- console.log(
264
- `recalculate finished with modelItems ${this.modelItems.length} item(s)`,
265
- this.modelItems,
266
- );
275
+ console.log('recalculate finished with modelItems ',this.modelItems);
267
276
  console.groupEnd();
268
277
  }
269
278
 
@@ -364,8 +373,9 @@ export class FxModel extends HTMLElement {
364
373
  *
365
374
  */
366
375
  revalidate() {
367
- console.group('### revalidate');
376
+ if(this.modelItems.length === 0) return true;
368
377
 
378
+ console.group('### revalidate');
369
379
  console.time('revalidate');
370
380
  let valid = true;
371
381
  this.modelItems.forEach(modelItem => {
@@ -395,6 +405,28 @@ export class FxModel extends HTMLElement {
395
405
  }
396
406
  }
397
407
  }
408
+ if (typeof bind.hasAttribute === 'function' && bind.hasAttribute('required')) {
409
+ const required = bind.getAttribute('required');
410
+ if (required) {
411
+ const compute = evaluateXPathToBoolean(required, modelItem.node, this);
412
+ console.log('modelItem required computed: ', compute);
413
+ modelItem.required = compute;
414
+ this.formElement.addToRefresh(modelItem); // let fore know that modelItem needs refresh
415
+ if(!modelItem.node.textContent){
416
+ valid = false;
417
+ }
418
+ // if (!compute) valid = false;
419
+ /*
420
+ if (!this.modelConstructed) {
421
+ // todo: get alert from attribute or child element
422
+ const alert = bind.getAlert();
423
+ if (alert) {
424
+ modelItem.addAlert(alert);
425
+ }
426
+ }
427
+ */
428
+ }
429
+ }
398
430
  }
399
431
  });
400
432
  console.timeEnd('revalidate');
@@ -421,7 +453,7 @@ export class FxModel extends HTMLElement {
421
453
  }
422
454
 
423
455
  getDefaultInstance() {
424
- return this.instances[0];
456
+ return this?.instances[0];
425
457
  }
426
458
 
427
459
  getDefaultInstanceData() {
@@ -445,5 +477,6 @@ export class FxModel extends HTMLElement {
445
477
  return result;
446
478
  }
447
479
  }
448
-
449
- customElements.define('fx-model', FxModel);
480
+ if (!customElements.get('fx-model')) {
481
+ customElements.define('fx-model', FxModel);
482
+ }
@@ -1,4 +1,5 @@
1
1
  import { Fore } from './fore.js';
2
+ import { Relevance } from './relevance.js';
2
3
  import { foreElementMixin } from './ForeElementMixin.js';
3
4
  import { evaluateXPathToString, evaluateXPath } from './xpath-evaluation.js';
4
5
  import getInScopeContext from './getInScopeContext.js';
@@ -66,23 +67,24 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
66
67
  }
67
68
 
68
69
  async submit() {
69
- await this.dispatch('submit', { submission: this });
70
+ await Fore.dispatch(this, 'submit', { submission: this });
70
71
  this._submit();
71
72
  }
72
73
 
73
74
  async _submit() {
74
- console.log('submitting....');
75
+ console.log('submitting....', this.getAttribute('id'));
75
76
  this.evalInContext();
76
77
  const model = this.getModel();
77
78
 
78
79
  model.recalculate();
79
80
 
80
- if (this.validate) {
81
+ if (this.validate==='true') {
81
82
  const valid = model.revalidate();
82
83
  if (!valid) {
83
84
  console.log('validation failed. Bubmission stopped');
84
85
  // ### allow alerts to pop up
85
- this.dispatch('submit-error', {});
86
+ // this.dispatch('submit-error', {});
87
+ Fore.dispatch(this, 'submit-error', {});
86
88
  this.getModel().parentNode.refresh();
87
89
  return;
88
90
  }
@@ -117,24 +119,20 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
117
119
  /**
118
120
  * sends the data after evaluating
119
121
  *
120
- * todo: can send only XML at the moment
121
122
  * @private
122
123
  */
123
124
  async _serializeAndSend() {
124
125
  const resolvedUrl = this._evaluateAttributeTemplateExpression(this.url, this);
125
126
 
126
127
  const instance = this.getInstance();
127
- if (instance.type !== 'xml') {
128
- console.error('JSON serialization is not supported yet');
129
- return;
130
- }
128
+ console.log('instance type', instance.type);
131
129
 
132
- // let serialized = serializer.serializeToString(this.nodeset);
133
130
  let serialized;
134
131
  if (this.serialization === 'none') {
135
132
  serialized = undefined;
136
133
  } else {
137
- const relevant = this.selectRelevant();
134
+ // const relevant = this.selectRelevant(instance.type);
135
+ const relevant = Relevance.selectRelevant(this, instance.type);
138
136
  serialized = this._serialize(instance.type, relevant);
139
137
  }
140
138
 
@@ -145,19 +143,41 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
145
143
  // console.log('data being send', serialized);
146
144
  // console.log('submitting data',serialized);
147
145
 
148
- if (resolvedUrl === '#echo') {
149
- let doc;
150
- if (serialized) {
151
- doc = new DOMParser().parseFromString(serialized, 'application/xml');
152
- } else {
153
- doc = undefined;
146
+ // if (resolvedUrl === '#echo') {
147
+ if (resolvedUrl.startsWith('#echo')) {
148
+ let data = this._parse(serialized, instance);
149
+ this._handleResponse(data);
150
+ // this.dispatch('submit-done', {});
151
+ Fore.dispatch(this, 'submit-done', {});
152
+ return;
153
+ }
154
+
155
+ if(resolvedUrl.startsWith('localStore:') && this.method === 'post'){
156
+ // let data = this._parse(serialized, instance);
157
+ const key = resolvedUrl.substring(resolvedUrl.indexOf(':')+1);
158
+ localStorage.setItem(key,serialized);
159
+ Fore.dispatch(this, 'submit-done', {});
160
+ return;
161
+ }
162
+
163
+ if(resolvedUrl.startsWith('localStore:') && (this.method === 'consume' || this.method === 'get')){
164
+ // let data = this._parse(serialized, instance);
165
+ this.replace = 'instance';
166
+ const key = resolvedUrl.substring(resolvedUrl.indexOf(':')+1);
167
+ const serialized = localStorage.getItem(key);
168
+ if(!serialized){
169
+ Fore.dispatch(this, 'submit-error', { message: `Error reading key ${key} from localstorage` });
170
+ return;
154
171
  }
155
- // const doc = new DOMParser().parseFromString(serialized, 'application/xml');
156
- // const newDoc = doc.replaceChild(relevant, doc.firstElementChild);
157
- this._handleResponse(doc);
158
- this.dispatch('submit-done', {});
172
+ let data = this._parse(serialized, instance);
173
+ this._handleResponse(data);
174
+ if(this.method === 'consume'){
175
+ localStorage.removeItem(key);
176
+ }
177
+ Fore.dispatch(this, 'submit-done', {});
159
178
  return;
160
179
  }
180
+
161
181
  // ### setting headers
162
182
  const headers = this._getHeaders();
163
183
  console.log('headers', headers);
@@ -168,7 +188,8 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
168
188
  }
169
189
 
170
190
  if (!this.methods.includes(this.method.toLowerCase())) {
171
- this.dispatch('error', { message: `Unknown method ${this.method}` });
191
+ // this.dispatch('error', { message: `Unknown method ${this.method}` });
192
+ Fore.dispatch(this, 'error', { message: `Unknown method ${this.method}` });
172
193
  return;
173
194
  }
174
195
  const response = await fetch(resolvedUrl, {
@@ -180,7 +201,8 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
180
201
  });
181
202
 
182
203
  if (!response.ok || response.status > 400) {
183
- this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
204
+ // this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
205
+ Fore.dispatch(this, 'submit-error', { message: `Error while submitting ${this.id}` });
184
206
  return;
185
207
  }
186
208
 
@@ -204,7 +226,19 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
204
226
  this._handleResponse(blob);
205
227
  }
206
228
 
207
- this.dispatch('submit-done', {});
229
+ // this.dispatch('submit-done', {});
230
+ Fore.dispatch(this, 'submit-done', {});
231
+ }
232
+
233
+ _parse(serialized, instance) {
234
+ let data = null;
235
+ if (serialized && instance.type === 'xml') {
236
+ data = new DOMParser().parseFromString(serialized, 'application/xml');
237
+ }
238
+ if (serialized && instance.type === 'json') {
239
+ data = JSON.parse(serialized);
240
+ }
241
+ return data;
208
242
  }
209
243
 
210
244
  _serialize(instanceType, relevantNodes) {
@@ -221,11 +255,10 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
221
255
  const serializer = new XMLSerializer();
222
256
  return serializer.serializeToString(relevantNodes);
223
257
  }
224
- /*
225
- if(instanceType === 'json'){
226
- console.warn('JSON serialization is not yet supported')
227
- }
228
- */
258
+ if (instanceType === 'json') {
259
+ // console.warn('JSON serialization is not yet supported')
260
+ return JSON.stringify(relevantNodes);
261
+ }
229
262
  throw new Error('unknown instance type ', instanceType);
230
263
  }
231
264
 
@@ -269,13 +302,28 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
269
302
  return targetInstance;
270
303
  }
271
304
 
305
+ /**
306
+ * handles replacement of instance data from response data.
307
+ *
308
+ * Please note that data might be
309
+ * @param data
310
+ * @private
311
+ */
272
312
  _handleResponse(data) {
273
313
  console.log('_handleResponse ', data);
314
+
315
+ /*
316
+ // ### responses need to be handled depending on their type.
317
+ if(this.type === 'json'){
318
+
319
+ }
320
+ */
321
+
274
322
  if (this.replace === 'instance') {
275
323
  const targetInstance = this._getTargetInstance();
276
324
  if (targetInstance) {
277
325
  if (this.targetref) {
278
- const theTarget = evaluateXPath(
326
+ const [theTarget] = evaluateXPath(
279
327
  this.targetref,
280
328
  targetInstance.instanceData.firstElementChild,
281
329
  this,
@@ -286,7 +334,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
286
334
  parent.replaceChild(clone, theTarget);
287
335
  console.log('finally ', parent);
288
336
  } else if (this.into) {
289
- const theTarget = evaluateXPath(
337
+ const [theTarget] = evaluateXPath(
290
338
  this.into,
291
339
  targetInstance.instanceData.firstElementChild,
292
340
  this,
@@ -296,12 +344,12 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
296
344
  } else {
297
345
  const instanceData = data;
298
346
  targetInstance.instanceData = instanceData;
347
+ console.log('### replaced instance ', this.getModel().instances);
299
348
  console.log('### replaced instance ', targetInstance.instanceData);
300
349
  }
301
350
 
302
351
  this.model.updateModel(); // force update
303
- // this.model.formElement.refresh();
304
- this.getOwnerForm().refresh();
352
+ this.getOwnerForm().refresh(true);
305
353
  } else {
306
354
  throw new Error(`target instance not found: ${targetInstance}`);
307
355
  }
@@ -318,26 +366,29 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
318
366
  if (this.replace === 'redirect') {
319
367
  window.location.href = data;
320
368
  }
321
-
322
- /*
323
- const event = new CustomEvent('submit-done', {
324
- composed: true,
325
- bubbles: true,
326
- detail: {},
327
- });
328
- console.log('firing',event);
329
- this.dispatchEvent(event);
330
- */
331
- // this.dispatch('submit-done', {});
332
369
  }
333
370
 
334
371
  /**
335
372
  * select relevant nodes
336
373
  *
337
- * todo: support for 'empty'
338
374
  * @returns {*}
339
375
  */
340
- selectRelevant() {
376
+ /*
377
+ selectRelevant(type) {
378
+ console.log('selectRelevant' ,type)
379
+ switch (type){
380
+ case 'xml':
381
+ return this._relevantXmlNodes();
382
+ default:
383
+ console.warn(`relevance selection not supported for type:${this.type}`);
384
+ return this.nodeset;
385
+ }
386
+ }
387
+ */
388
+
389
+ // todo: support for 'empty'
390
+ /*
391
+ _relevantXmlNodes() {
341
392
  // ### no relevance selection - current nodeset is used 'as-is'
342
393
  if (this.nonrelevant === 'keep') {
343
394
  return this.nodeset;
@@ -353,10 +404,11 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
353
404
  if (this.nodeset.children.length === 0 && this._isRelevant(this.nodeset)) {
354
405
  return this.nodeset;
355
406
  }
356
- const result = this._filterRelevant(this.nodeset, root);
357
- return result;
407
+ return this._filterRelevant(this.nodeset, root);
358
408
  }
409
+ */
359
410
 
411
+ /*
360
412
  _filterRelevant(node, result) {
361
413
  const { childNodes } = node;
362
414
  Array.from(childNodes).forEach(n => {
@@ -381,7 +433,9 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
381
433
  });
382
434
  return result;
383
435
  }
436
+ */
384
437
 
438
+ /*
385
439
  _isRelevant(node) {
386
440
  const mi = this.getModel().getModelItem(node);
387
441
  if (!mi || mi.relevant) {
@@ -389,9 +443,11 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
389
443
  }
390
444
  return false;
391
445
  }
446
+ */
392
447
 
393
448
  _handleError() {
394
- this.dispatch('submit-error', {});
449
+ // this.dispatch('submit-error', {});
450
+ Fore.dispatch(this, 'submit-error', {});
395
451
  /*
396
452
  console.log('ERRRORRRRR');
397
453
  this.dispatchEvent(
@@ -404,5 +460,6 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
404
460
  */
405
461
  }
406
462
  }
407
-
408
- customElements.define('fx-submission', FxSubmission);
463
+ if (!customElements.get('fx-submission')) {
464
+ customElements.define('fx-submission', FxSubmission);
465
+ }
package/src/fx-var.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { Fore } from './fore.js';
1
2
  import './fx-instance.js';
2
3
  import { evaluateXPath } from './xpath-evaluation.js';
3
4
  import { foreElementMixin } from './ForeElementMixin.js';
@@ -24,13 +25,14 @@ export class FxVariable extends foreElementMixin(HTMLElement) {
24
25
  refresh() {
25
26
  const inscope = getInScopeContext(this, this.valueQuery);
26
27
 
27
- this.value = evaluateXPath(this.valueQuery, inscope, this, this.precedingVariables);
28
+ const values = evaluateXPath(this.valueQuery, inscope, this, this.precedingVariables);
29
+ [this.value] = values;
28
30
  }
29
31
 
30
32
  setInScopeVariables(inScopeVariables) {
31
33
  if (inScopeVariables.has(this.name)) {
32
34
  console.error(`The variable ${this.name} is declared more than once`);
33
- this.dispatch('xforms-binding-error');
35
+ Fore.dispatch(this, 'xforms-binding-error', {});
34
36
  return;
35
37
  }
36
38
  inScopeVariables.set(this.name, this);
@@ -39,5 +41,6 @@ export class FxVariable extends foreElementMixin(HTMLElement) {
39
41
  this.inScopeVariables = new Map(inScopeVariables);
40
42
  }
41
43
  }
42
-
43
- customElements.define('fx-var', FxVariable);
44
+ if (!customElements.get('fx-var')) {
45
+ customElements.define('fx-var', FxVariable);
46
+ }
@@ -1,15 +1,14 @@
1
1
  import { evaluateXPathToFirstNode } from './xpath-evaluation.js';
2
+ import { Fore } from './fore.js';
2
3
 
3
4
  import { XPathUtil } from './xpath-util.js';
4
5
 
5
-
6
6
  function _getElement(node) {
7
7
  if (node && node.nodeType && node.nodeType === Node.ATTRIBUTE_NODE) {
8
8
  // The context of an attribute is the ref of the element it's defined on
9
9
  return node.ownerElement;
10
10
  }
11
11
 
12
-
13
12
  if (node.nodeType === Node.ELEMENT_NODE) {
14
13
  // The context of a query should be the element having a ref
15
14
  return node;
@@ -30,16 +29,25 @@ function _getModelInContext(node) {
30
29
  }
31
30
 
32
31
  function _getInitialContext(node, ref) {
33
- const parentBind = node.closest('[ref]');
32
+ const parentBind = Fore.getClosest('[ref]', node);
33
+ const localFore = Fore.getClosest('fx-fore', node);
34
+
35
+ const model = _getModelInContext(node);
34
36
 
35
37
  if (parentBind !== null) {
36
- return parentBind.nodeset;
38
+ /*
39
+ make sure that the closest ref belongs to the same fx-fore element
40
+ */
41
+ const parentBindFore = parentBind.closest('fx-fore');
42
+ if (localFore === parentBindFore) {
43
+ return parentBind.nodeset;
44
+ }
45
+ return model.getDefaultInstance().getDefaultContext();
37
46
  }
38
47
 
39
- const model = _getModelInContext(node);
40
48
  if (XPathUtil.isAbsolutePath(ref)) {
41
49
  const instanceId = XPathUtil.getInstanceId(ref);
42
- if(instanceId){
50
+ if (instanceId) {
43
51
  return model.getInstance(instanceId).getDefaultContext();
44
52
  }
45
53
  return model.getDefaultInstance().getDefaultContext();
@@ -52,23 +60,22 @@ function _getInitialContext(node, ref) {
52
60
 
53
61
  export default function getInScopeContext(node, ref) {
54
62
  const parentElement = _getElement(node);
55
- /*
56
- if(parentElement.nodeName.toUpperCase() === 'FX-REPEATITEM'){
57
- return parentElement.nodeset;
58
- }
59
- */
60
63
 
61
- const repeatItem = parentElement.closest('fx-repeatitem');
64
+ const repeatItem = Fore.getClosest('fx-repeatitem', parentElement);
62
65
  if (repeatItem) {
63
- if(node.nodeName === 'context'){
64
- return evaluateXPathToFirstNode(node.nodeValue, repeatItem.nodeset, _getForeContext(parentElement));
66
+ if (node.nodeName === 'context') {
67
+ return evaluateXPathToFirstNode(
68
+ node.nodeValue,
69
+ repeatItem.nodeset,
70
+ _getForeContext(parentElement),
71
+ );
65
72
  }
66
73
  return repeatItem.nodeset;
67
74
  }
68
75
 
69
76
  if (parentElement.hasAttribute('context')) {
70
- const initialContext = _getInitialContext(node.ownerElement.parentNode, ref);
71
- const contextAttr = node.ownerElement.getAttribute('context');
77
+ const initialContext = _getInitialContext(parentElement.parentNode, ref);
78
+ const contextAttr = parentElement.getAttribute('context');
72
79
  return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
73
80
  }
74
81
 
package/src/modelitem.js CHANGED
@@ -54,11 +54,11 @@ export class ModelItem {
54
54
  console.log('modelitem.setvalue newVal', newVal);
55
55
 
56
56
  if (newVal.nodeType === Node.DOCUMENT_NODE) {
57
- // this.node.replaceWith(newVal.firstElementChild);
58
- this.node.appendChild(newVal.firstElementChild);
57
+ this.node.replaceWith(newVal.firstElementChild);
58
+ // this.node.appendChild(newVal.firstElementChild);
59
59
  } else if (newVal.nodeType === Node.ELEMENT_NODE) {
60
- // this.node.replaceWith(newVal);
61
- this.node.appendChild(newVal);
60
+ this.node.replaceWith(newVal);
61
+ // this.node.appendChild(newVal);
62
62
  } else if (this.node.nodeType === Node.ATTRIBUTE_NODE) {
63
63
  this.node.nodeValue = newVal;
64
64
  } else {