@jinntec/fore 1.0.0-2 → 1.0.0-5

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/src/fx-fore.js CHANGED
@@ -64,7 +64,7 @@ export class FxFore extends HTMLElement {
64
64
 
65
65
  const style = `
66
66
  :host {
67
- display: none;
67
+ // display: none;
68
68
  height:auto;
69
69
  padding:var(--model-element-padding);
70
70
  font-family:Roboto, sans-serif;
@@ -97,7 +97,7 @@ export class FxFore extends HTMLElement {
97
97
  visibility: visible;
98
98
  opacity: 1;
99
99
  }
100
-
100
+
101
101
  .popup {
102
102
  margin: 70px auto;
103
103
  background: #fff;
@@ -133,7 +133,7 @@ export class FxFore extends HTMLElement {
133
133
  .popup .close:focus{
134
134
  outline:none;
135
135
  }
136
-
136
+
137
137
  .popup .close:hover {
138
138
  color: #06D85F;
139
139
  }
@@ -152,6 +152,7 @@ export class FxFore extends HTMLElement {
152
152
 
153
153
  const html = `
154
154
  <jinn-toast id="message" gravity="bottom" position="left"></jinn-toast>
155
+ <jinn-toast id="sticky" gravity="bottom" position="left" duration="-1" close="true" data-class="sticky-message"></jinn-toast>
155
156
  <jinn-toast id="error" text="error" duration="-1" data-class="error" close="true" position="left" gravity="bottom"></jinn-toast>
156
157
  <slot></slot>
157
158
  <div id="modalMessage" class="overlay">
@@ -170,6 +171,10 @@ export class FxFore extends HTMLElement {
170
171
  </style>
171
172
  ${html}
172
173
  `;
174
+
175
+ this.toRefresh = [];
176
+ this.initialRun = true;
177
+ this.someInstanceDataStructureChanged = false;
173
178
  }
174
179
 
175
180
  connectedCallback() {
@@ -183,6 +188,12 @@ export class FxFore extends HTMLElement {
183
188
  this.intersectionObserver = new IntersectionObserver(this.handleIntersect, options);
184
189
  }
185
190
 
191
+ this.src = this.hasAttribute('src')? this.getAttribute('src'):null;
192
+ if(this.src){
193
+ this._loadFromSrc();
194
+ return ;
195
+ }
196
+
186
197
  const slot = this.shadowRoot.querySelector('slot');
187
198
  slot.addEventListener('slotchange', event => {
188
199
  const children = event.target.assignedElements();
@@ -198,10 +209,71 @@ export class FxFore extends HTMLElement {
198
209
  console.log(
199
210
  `########## FORE: kick off processing for ... ${window.location.href} ##########`,
200
211
  );
212
+ if(this.src){
213
+ console.log('########## FORE: loaded from ... ', this.src, '##########');
214
+ }
201
215
  modelElement.modelConstruct();
202
216
  }
203
217
  this.model = modelElement;
204
218
  });
219
+ this.addEventListener('path-mutated', (e) =>{
220
+ console.log('path-mutated event received', e.detail.path, e.detail.index);
221
+ this.someInstanceDataStructureChanged = true;
222
+ });
223
+ }
224
+
225
+
226
+ addToRefresh(modelItem){
227
+ const found = this.toRefresh.find(mi => mi.path === modelItem.path );
228
+ if(!found){
229
+ this.toRefresh.push(modelItem);
230
+ }
231
+ }
232
+
233
+ /**
234
+ * loads a Fore from an URL given by `src`.
235
+ *
236
+ * Will extract the `fx-fore` element from that target file and use and replace current `fx-fore` element with the loaded one.
237
+ * @private
238
+ */
239
+ _loadFromSrc() {
240
+ console.log('########## loading Fore from ',this.src ,'##########');
241
+ fetch(this.src, {
242
+ method: 'GET',
243
+ mode: 'cors',
244
+ credentials: 'include',
245
+ headers: {
246
+ 'Content-Type': 'text/html',
247
+ },
248
+ })
249
+ .then(response => {
250
+ const responseContentType = response.headers.get('content-type').toLowerCase();
251
+ console.log('********** responseContentType *********', responseContentType);
252
+ if (responseContentType.startsWith('text/html')) {
253
+ // const htmlResponse = response.text();
254
+ // return new DOMParser().parseFromString(htmlResponse, 'text/html');
255
+ // return response.text();
256
+ return response.text().then(result =>
257
+ // console.log('xml ********', result);
258
+ new DOMParser().parseFromString(result, 'text/html'),
259
+ );
260
+ }
261
+ return 'done';
262
+ })
263
+ .then(data => {
264
+ // const theFore = fxEvaluateXPathToFirstNode('//fx-fore', data.firstElementChild);
265
+ const theFore = data.querySelector('fx-fore');
266
+
267
+ // console.log('thefore', theFore)
268
+ if(!theFore){
269
+ this.dispatchEvent(new CustomEvent('error',{detail:{message: `Fore element not found in '${this.src}'. Maybe wrapped within 'template' element?`}}));
270
+ }
271
+ theFore.setAttribute('from-src', this.src);
272
+ this.replaceWith(theFore);
273
+ })
274
+ .catch(error => {
275
+ this.dispatchEvent(new CustomEvent('error',{detail:{message: `'${this.src}' not found or does not contain Fore element.`}}));
276
+ });
205
277
  }
206
278
 
207
279
  /**
@@ -266,32 +338,56 @@ export class FxFore extends HTMLElement {
266
338
 
267
339
  console.time('refresh');
268
340
 
269
- /*
270
- const changedModelItems = this.getModel().changed;
271
- const graph = this.getModel().mainGraph;
272
- let doRefresh = true;
273
- changedModelItems.forEach(item => {
274
- if(graph.hasNode(item.path)) {
275
- const deps = graph.dependentsOf(item.path, false);
276
- if (deps.length === 0) {
277
- doRefresh=false;
341
+ // ### refresh Fore UI elements
342
+ console.time('refreshChildren');
343
+ console.log('toRefresh',this.toRefresh);
344
+
345
+ if(!this.initialRun && this.toRefresh.length !== 0){
346
+ let needsRefresh = false;
347
+
348
+ // ### after recalculation the changed modelItems are copied to 'toRefresh' array for processing
349
+ this.toRefresh.forEach(modelItem => {
350
+ // check if modelItem has boundControls - if so, call refresh() for each of them
351
+ const controlsToRefresh = modelItem.boundControls;
352
+ if(controlsToRefresh){
353
+ controlsToRefresh.forEach(ctrl => {
354
+ ctrl.refresh();
355
+ });
278
356
  }
279
- }
280
- });
281
- this.getModel().changed = [];
282
357
 
283
- if (!doRefresh) {
284
- this.dispatchEvent(new CustomEvent('refresh-done'));
285
- return ;
358
+ // ### check if other controls depend on current modelItem
359
+ const mainGraph = this.getModel().mainGraph;
360
+ if(mainGraph && mainGraph.hasNode(modelItem.path)){
361
+ const deps = this.getModel().mainGraph.dependentsOf(modelItem.path, false);
362
+ // ### iterate dependant modelItems and refresh all their boundControls
363
+ if(deps.length !== 0){
364
+ deps.forEach(dep => {
365
+ // ### if changed modelItem has a 'facet' path we use the basePath that is the locationPath without facet name
366
+ const basePath = XPathUtil.getBasePath(dep);
367
+ const modelItemOfDep = this.getModel().modelItems.find(mip => mip.path === basePath);
368
+ // ### refresh all boundControls
369
+ modelItemOfDep.boundControls.forEach(control =>{control.refresh()});
370
+ });
371
+ needsRefresh = true;
372
+ }
373
+ }
374
+ });
375
+ this.toRefresh = [];
376
+ if(!needsRefresh){
377
+ console.log('skipping refresh - no dependants');
378
+ }
379
+ }else{
380
+ Fore.refreshChildren(this, true);
381
+ console.timeEnd('refreshChildren');
286
382
  }
287
- */
288
- // ### refresh Fore UI elements
289
- console.time('refreshChildren');
290
- Fore.refreshChildren(this, true);
291
- console.timeEnd('refreshChildren');
292
383
 
293
384
  // ### refresh template expressions
294
- this._updateTemplateExpressions();
385
+ if(this.initialRun || this.someInstanceDataStructureChanged){
386
+ this._updateTemplateExpressions();
387
+ this.someInstanceDataStructureChanged = false; //reset
388
+ }
389
+ this._processTemplateExpressions();
390
+
295
391
  console.timeEnd('refresh');
296
392
 
297
393
  console.groupEnd();
@@ -319,6 +415,8 @@ export class FxFore extends HTMLElement {
319
415
  this.storedTemplateExpressions = [];
320
416
  }
321
417
 
418
+ console.log('######### storedTemplateExpressions', this.storedTemplateExpressions.length);
419
+
322
420
  /*
323
421
  storing expressions and their nodes for re-evaluation
324
422
  */
@@ -329,21 +427,26 @@ export class FxFore extends HTMLElement {
329
427
  }
330
428
  const expr = this._getTemplateExpression(node);
331
429
 
430
+ // console.log('storedTemplateExpressionByNode', this.storedTemplateExpressionByNode);
332
431
  this.storedTemplateExpressionByNode.set(node, expr);
333
432
  });
433
+ console.log('stored template expressions ', this.storedTemplateExpressionByNode);
334
434
 
335
435
  // TODO: Should we clean up nodes that existed but are now gone?
436
+ this._processTemplateExpressions();
437
+
438
+ }
439
+
440
+ _processTemplateExpressions() {
336
441
  for (const node of this.storedTemplateExpressionByNode.keys()) {
337
442
  this._processTemplateExpression({
338
443
  node,
339
444
  expr: this.storedTemplateExpressionByNode.get(node),
340
445
  });
341
446
  }
342
-
343
- console.log('stored template expressions ', this.storedTemplateExpressionByNode);
344
447
  }
345
448
 
346
- // eslint-disable-next-line class-methods-use-this
449
+ // eslint-disable-next-line class-methods-use-this
347
450
  _processTemplateExpression(exprObj) {
348
451
  // console.log('processing template expression ', exprObj);
349
452
 
@@ -553,6 +656,18 @@ export class FxFore extends HTMLElement {
553
656
 
554
657
  await this._lazyCreateInstance();
555
658
 
659
+ console.log('registering variables!');
660
+ const variables = new Map();
661
+ (function registerVariables(node) {
662
+ for (const child of node.children) {
663
+ if ('setInScopeVariables' in child) {
664
+ child.setInScopeVariables(variables);
665
+ }
666
+ registerVariables(child);
667
+ }
668
+ })(this);
669
+ console.log('Found variables:', variables);
670
+
556
671
  const options = {
557
672
  root: null,
558
673
  rootMargin: '0px',
@@ -562,8 +677,10 @@ export class FxFore extends HTMLElement {
562
677
  await this.refresh();
563
678
  // this.style.display='block'
564
679
  this.classList.add('fx-ready');
680
+ document.body.classList.add('fx-ready');
565
681
 
566
682
  this.ready = true;
683
+ this.initialRun = false;
567
684
  console.log('### <<<<< dispatching ready >>>>>');
568
685
  console.log('########## modelItems: ', this.getModel().modelItems);
569
686
  console.log('########## FORE: form fully initialized... ##########');
@@ -613,9 +730,9 @@ export class FxFore extends HTMLElement {
613
730
  this.shadowRoot.getElementById('messageContent').innerText = msg;
614
731
  // this.shadowRoot.getElementById('modalMessage').open();
615
732
  this.shadowRoot.getElementById('modalMessage').classList.add('show');
616
- } else if (level === 'modeless') {
733
+ } else if (level === 'sticky') {
617
734
  // const notification = this.$.modeless;
618
- this.shadowRoot.querySelector('#message').showToast(msg);
735
+ this.shadowRoot.querySelector('#sticky').showToast(msg);
619
736
  } else {
620
737
  const toast = this.shadowRoot.querySelector('#message');
621
738
  toast.showToast(msg);
package/src/fx-model.js CHANGED
@@ -157,7 +157,7 @@ export class FxModel extends HTMLElement {
157
157
  rebuild() {
158
158
  console.group('### rebuild');
159
159
  console.time('rebuild');
160
- this.mainGraph = new DepGraph(false);
160
+ this.mainGraph = new DepGraph(false); //do: should be moved down below binds.length check but causes errors in tests.
161
161
  this.modelItems = [];
162
162
 
163
163
  // trigger recursive initialization of the fx-bind elements
@@ -167,6 +167,7 @@ export class FxModel extends HTMLElement {
167
167
  this.skipUpdate = true;
168
168
  return ;
169
169
  }
170
+
170
171
  binds.forEach(bind => {
171
172
  bind.init(this);
172
173
  });
@@ -195,7 +196,7 @@ export class FxModel extends HTMLElement {
195
196
  */
196
197
  recalculate() {
197
198
  console.group('### recalculate');
198
- console.log('recalculate instances ', this.instances);
199
+ console.log('changed nodes ', this.changed);
199
200
 
200
201
  console.time('recalculate');
201
202
  this.computes = 0;
@@ -242,6 +243,8 @@ export class FxModel extends HTMLElement {
242
243
  this.compute(node, path);
243
244
  }
244
245
  });
246
+ const toRefresh = [...this.changed];
247
+ this.formElement.toRefresh = toRefresh;
245
248
  this.changed = [];
246
249
  console.log('subgraph', this.subgraph);
247
250
  this.dispatchEvent(
@@ -380,6 +383,7 @@ export class FxModel extends HTMLElement {
380
383
  const compute = evaluateXPathToBoolean(constraint, modelItem.node, this);
381
384
  console.log('modelItem validity computed: ', compute);
382
385
  modelItem.constraint = compute;
386
+ this.formElement.addToRefresh(modelItem); // let fore know that modelItem needs refresh
383
387
  if (!compute) valid = false;
384
388
  // ### alerts are added only once during model-construct. Otherwise they would add up in each run of revalidate()
385
389
  if (!this.modelConstructed) {
@@ -81,6 +81,9 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
81
81
  const valid = model.revalidate();
82
82
  if (!valid) {
83
83
  console.log('validation failed. Bubmission stopped');
84
+ // ### allow alerts to pop up
85
+ this.dispatch('submit-error', {});
86
+ this.getModel().parentNode.refresh();
84
87
  return;
85
88
  }
86
89
  }
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);
@@ -2,10 +2,20 @@ import { evaluateXPathToFirstNode } from './xpath-evaluation.js';
2
2
 
3
3
  import { XPathUtil } from './xpath-util.js';
4
4
 
5
- function _getParentElement(node) {
6
- if (node.nodeType === Node.ATTRIBUTE_NODE) {
5
+
6
+ function _getElement(node) {
7
+ if (node && node.nodeType && node.nodeType === Node.ATTRIBUTE_NODE) {
8
+ // The context of an attribute is the ref of the element it's defined on
7
9
  return node.ownerElement;
8
10
  }
11
+
12
+
13
+ if (node.nodeType === Node.ELEMENT_NODE) {
14
+ // The context of a query should be the element having a ref
15
+ return node;
16
+ }
17
+
18
+ // For text nodes, just start looking from the parent element
9
19
  return node.parentNode;
10
20
  }
11
21
 
@@ -29,7 +39,10 @@ function _getInitialContext(node, ref) {
29
39
  const model = _getModelInContext(node);
30
40
  if (XPathUtil.isAbsolutePath(ref)) {
31
41
  const instanceId = XPathUtil.getInstanceId(ref);
32
- return model.getInstance(instanceId).getDefaultContext();
42
+ if(instanceId){
43
+ return model.getInstance(instanceId).getDefaultContext();
44
+ }
45
+ return model.getDefaultInstance().getDefaultContext();
33
46
  }
34
47
  if (model.getDefaultInstance() !== null && model.inited) {
35
48
  return model.getDefaultInstance().getDefaultContext();
@@ -38,7 +51,7 @@ function _getInitialContext(node, ref) {
38
51
  }
39
52
 
40
53
  export default function getInScopeContext(node, ref) {
41
- const parentElement = _getParentElement(node);
54
+ const parentElement = _getElement(node);
42
55
  /*
43
56
  if(parentElement.nodeName.toUpperCase() === 'FX-REPEATITEM'){
44
57
  return parentElement.nodeset;
@@ -47,13 +60,40 @@ export default function getInScopeContext(node, ref) {
47
60
 
48
61
  const repeatItem = parentElement.closest('fx-repeatitem');
49
62
  if (repeatItem) {
63
+ if(node.nodeName === 'context'){
64
+ return evaluateXPathToFirstNode(node.nodeValue, repeatItem.nodeset, _getForeContext(parentElement));
65
+ }
50
66
  return repeatItem.nodeset;
51
67
  }
52
68
 
53
- if (node.nodeType === Node.ELEMENT_NODE && node.hasAttribute('context')) {
54
- const initialContext = _getInitialContext(node.parentNode, ref);
55
- const contextAttr = node.getAttribute('context');
69
+ if (parentElement.hasAttribute('context')) {
70
+ const initialContext = _getInitialContext(node.ownerElement.parentNode, ref);
71
+ const contextAttr = node.ownerElement.getAttribute('context');
56
72
  return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
57
73
  }
74
+
75
+ if (node.nodeType === Node.ATTRIBUTE_NODE && node.nodeName === 'context') {
76
+ const initialContext = _getInitialContext(node.ownerElement.parentNode, ref);
77
+ const contextAttr = node.ownerElement.getAttribute('context');
78
+ return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
79
+ }
80
+ if (node.nodeType === Node.ATTRIBUTE_NODE && node.nodeName === 'ref') {
81
+ // Note: do not consider the ref of the owner element since it should not be used to define the
82
+ // context
83
+ if (node.ownerElement.hasAttribute('context')) {
84
+ const initialContext = _getInitialContext(node.ownerElement.parentNode, ref);
85
+ const contextAttr = node.ownerElement.getAttribute('context');
86
+ return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
87
+ }
88
+
89
+ // Never resolve the context from a ref itself!
90
+ return _getInitialContext(parentElement.parentNode, ref);
91
+ }
92
+
93
+ // if (node.nodeType === Node.ELEMENT_NODE && node.hasAttribute('context')) {
94
+ // const initialContext = _getInitialContext(node.parentNode, ref);
95
+ // const contextAttr = node.getAttribute('context');
96
+ // return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
97
+ // }
58
98
  return _getInitialContext(parentElement, ref);
59
99
  }
package/src/modelitem.js CHANGED
@@ -30,6 +30,7 @@ export class ModelItem {
30
30
  this.bind = bind;
31
31
  this.changed = false;
32
32
  this.alerts = [];
33
+ this.boundControls = [];
33
34
  // this.value = this._getValue();
34
35
  }
35
36
 
@@ -31,7 +31,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
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();
@@ -44,6 +44,10 @@ export class FxContainer extends foreElementMixin(HTMLElement) {
44
44
  if (this.isBound()) {
45
45
  this.evalInContext();
46
46
  this.modelItem = this.getModelItem();
47
+ if(!this.modelItem.boundControls.includes(this)){
48
+ this.modelItem.boundControls.push(this);
49
+ }
50
+
47
51
  // this.value = this.modelItem.value;
48
52
  }
49
53
 
@@ -0,0 +1,77 @@
1
+ import {Fore} from '../fore.js';
2
+ export class FxDialog extends HTMLElement {
3
+
4
+ static get properties() {
5
+ return {
6
+ id: String
7
+ };
8
+ }
9
+
10
+ constructor() {
11
+ super();
12
+ this.attachShadow({mode: 'open'});
13
+ }
14
+
15
+ connectedCallback() {
16
+ const style = `
17
+ :host {
18
+ display:none;
19
+ height: 100vh;
20
+ width:100vw;
21
+ position:fixed;
22
+ left:0;
23
+ top:0;
24
+ right:0;
25
+ bottom:0;
26
+ transition:opacity 0.4s linear;
27
+ }
28
+
29
+ `;
30
+
31
+ this.shadowRoot.innerHTML = this.render(style);
32
+ this.id = this.getAttribute('id');
33
+
34
+ // const dialog = document.getElementById(this.id);
35
+
36
+ const closeBtn = this.querySelector('.close-dialog');
37
+ if (closeBtn) {
38
+ closeBtn.addEventListener('click', (e) => {
39
+ document.getElementById(this.id).classList.remove('show');
40
+ });
41
+ }
42
+
43
+ this.addEventListener('transitionend',()=>{
44
+ console.log('transitionend');
45
+ // this.style.display = 'none';
46
+ });
47
+
48
+ this.focus();
49
+ }
50
+
51
+ render(styles) {
52
+ return `
53
+ <style>
54
+ ${styles}
55
+ </style>
56
+ <slot></slot>
57
+ `;
58
+ }
59
+
60
+ open(){
61
+ window.addEventListener('keyup', (e) => {
62
+ if (e.key === "Escape") {
63
+ this.hide();
64
+ }
65
+ },{once:true});
66
+
67
+ this.classList.add('show');
68
+ }
69
+
70
+ async hide(){
71
+ await Fore.fadeOutElement(this,400);
72
+ this.classList.remove('show');
73
+ }
74
+
75
+ }
76
+
77
+ customElements.define('fx-dialog', FxDialog);
@@ -1,6 +1,4 @@
1
- import XfAbstractControl from './abstract-control.js';
2
1
  import { evaluateXPath, evaluateXPathToString, evaluateXPathToNodes } from '../xpath-evaluation.js';
3
- import getInScopeContext from '../getInScopeContext.js';
4
2
  import FxControl from './fx-control.js';
5
3
  import { Fore } from '../fore.js';
6
4
 
@@ -103,12 +101,15 @@ export class FxItems extends FxControl {
103
101
  // getting expr
104
102
  const expr = input.value;
105
103
  const cutted = expr.substring(1, expr.length - 1);
106
- const evaluated = evaluateXPath(cutted, node, newEntry);
104
+ const evaluated = evaluateXPathToString(cutted, node, newEntry);
107
105
 
108
- const valAttr = this.getAttribute('value');
106
+ // adding space around value to allow matching of 'words'
107
+ const spaced = ` ${evaluated} `;
108
+
109
+ const valAttr = ` ${this.getAttribute('value')} `;
109
110
  input.value = evaluated;
110
111
  input.setAttribute('id', id);
111
- if (valAttr.indexOf(input.value) !== -1) {
112
+ if (valAttr.indexOf(spaced) !== -1) {
112
113
  input.checked = true;
113
114
  }
114
115
  }
@@ -1,5 +1,5 @@
1
1
  import XfAbstractControl from './abstract-control.js';
2
- import { evaluateXPath, evaluateXPathToString } from '../xpath-evaluation.js';
2
+ import { evaluateXPath, evaluateXPathToStrings } from '../xpath-evaluation.js';
3
3
  import getInScopeContext from '../getInScopeContext.js';
4
4
  // import {markdown} from '../drawdown.js';
5
5
 
@@ -68,19 +68,16 @@ export class FxOutput extends XfAbstractControl {
68
68
  }
69
69
 
70
70
  async refresh() {
71
- // ### 1. eval 'value' attr
72
- // await super.refresh();
71
+ // Resolve the ref first. The ref will set the `nodeset` which is important for the 'context'
72
+ if (this.ref) {
73
+ await super.refresh();
74
+ }
73
75
 
76
+ // ### 2. Eval the value
74
77
  if (this.valueAttr) {
75
78
  this.value = this.getValue();
76
79
  await this.updateWidgetValue();
77
- return;
78
80
  }
79
- // ### 2. eval 'ref' attr
80
- if (this.ref) {
81
- super.refresh();
82
- }
83
- // ### 3. use inline content which is there anyway
84
81
  }
85
82
 
86
83
  getValue() {
@@ -90,7 +87,8 @@ export class FxOutput extends XfAbstractControl {
90
87
  if (this.hasAttribute('html')) {
91
88
  return evaluateXPath(this.valueAttr, inscopeContext, this);
92
89
  }
93
- return evaluateXPathToString(this.valueAttr, inscopeContext, this);
90
+
91
+ return evaluateXPathToStrings(this.valueAttr, inscopeContext, this)[0];
94
92
  } catch (error) {
95
93
  console.error(error);
96
94
  this.dispatch('error', { message: error });
@@ -119,7 +117,7 @@ export class FxOutput extends XfAbstractControl {
119
117
  return;
120
118
  */
121
119
 
122
- const node = this.modelItem.node;
120
+ const { node } = this.modelItem;
123
121
 
124
122
  if (node.nodeType) {
125
123
  // const mainSlot = this.shadowRoot.querySelector('#main');