@jinntec/fore 1.10.0 → 1.10.2

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-bind.js CHANGED
@@ -80,7 +80,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
80
80
  _buildBindGraph() {
81
81
  if (this.bindType === 'xml') {
82
82
  this.nodeset.forEach(node => {
83
- const instance = XPathUtil.resolveInstance(this);
83
+ const instance = XPathUtil.resolveInstance(this,this.ref);
84
84
 
85
85
  const path = XPathUtil.getPath(node, instance);
86
86
  this.model.mainGraph.addNode(path, node);
package/src/fx-fore.js CHANGED
@@ -85,9 +85,10 @@ export class FxFore extends HTMLElement {
85
85
  // this.addEventListener('model-construct-done', this._handleModelConstructDone);
86
86
  // todo: refactoring - these should rather go into connectedcallback
87
87
  this.addEventListener('message', this._displayMessage);
88
- this.addEventListener('error', this._displayError);
88
+ // this.addEventListener('error', this._displayError);
89
+ this.addEventListener('error', this._logError);
89
90
  this.addEventListener('warn', this._displayWarning);
90
- this.addEventListener('log', this._logError);
91
+ // this.addEventListener('log', this._logError);
91
92
  window.addEventListener('compute-exception', e => {
92
93
  console.error('circular dependency: ', e);
93
94
  });
@@ -176,7 +177,7 @@ export class FxFore extends HTMLElement {
176
177
 
177
178
  const html = `
178
179
  <noscript>This page uses Web Components and needs JavaScript to be enabled..</noscript>
179
-
180
+ <!-- <slot name="errors"></slot> -->
180
181
  <jinn-toast id="message" gravity="bottom" position="left"></jinn-toast>
181
182
  <jinn-toast id="sticky" gravity="bottom" position="left" duration="-1" close="true" data-class="sticky-message"></jinn-toast>
182
183
  <jinn-toast id="error" text="error" duration="-1" data-class="error" close="true" position="right" gravity="top" escape-markup="false"></jinn-toast>
@@ -324,9 +325,9 @@ export class FxFore extends HTMLElement {
324
325
  * Will extract the `fx-fore` element from that target file and use and replace current `fx-fore` element with the loaded one.
325
326
  * @private
326
327
  */
327
- _loadFromSrc() {
328
+ async _loadFromSrc() {
328
329
  // console.log('########## loading Fore from ', this.src, '##########');
329
- fetch(this.src, {
330
+ await fetch(this.src, {
330
331
  method: 'GET',
331
332
  mode: 'cors',
332
333
  credentials: 'include',
@@ -450,42 +451,50 @@ export class FxFore extends HTMLElement {
450
451
  // console.timeEnd('refresh');
451
452
  }
452
453
 
453
- async refresh(force, changedPaths) {
454
- if (!changedPaths) {
455
- changedPaths = this.toRefresh.map(item => item.path);
456
- } else {
457
- this.toRefresh.push(
458
- ...changedPaths
459
- .map(
460
- path =>
461
- this.getModel()
462
- .modelItems
463
- .find(item => item.path === path)
464
- )
465
- .filter(Boolean)
466
- );
467
-
468
- for(const changedPath of changedPaths) {
469
- for (const repeat of this.querySelectorAll('fx-repeat')) {
470
- if (repeat.closest('fx-fore') !== this) {
471
- continue;
472
- }
473
-
474
- if (repeat.touchedPaths.has(changedPath)) {
475
- // Make a temporary model-item-like structure for this
476
- this.toRefresh.push({
477
- path: changedPath,
478
- boundControls: [repeat]
479
- });
480
-
481
- console.log('Found a repeat to update!!!', repeat)
482
- }
483
- }
484
- }
454
+ // async refresh(force, changedPaths) {
455
+ async refresh(force) {
456
+
457
+ /*
458
+
459
+ if (!changedPaths) {
460
+ changedPaths = this.toRefresh.map(item => item.path);
461
+ } else {
462
+ this.toRefresh.push(
463
+ ...changedPaths
464
+ .map(
465
+ path =>
466
+ this.getModel()
467
+ .modelItems
468
+ .find(item => item.path === path)
469
+ )
470
+ .filter(Boolean)
471
+ );
472
+
473
+ for(const changedPath of changedPaths) {
474
+ for (const repeat of this.querySelectorAll('fx-repeat')) {
475
+ if (repeat.closest('fx-fore') !== this) {
476
+ continue;
477
+ }
478
+
479
+ if (repeat.touchedPaths && repeat.touchedPaths.has(changedPath)) {
480
+ // Make a temporary model-item-like structure for this
481
+ this.toRefresh.push({
482
+ path: changedPath,
483
+ boundControls: [repeat]
484
+ });
485
+
486
+ console.log('Found a repeat to update!!!', repeat)
487
+ }
488
+ }
489
+ }
485
490
  }
491
+ */
486
492
  if (this.isRefreshing) {
487
493
  return;
488
494
  }
495
+ this.isRefreshing = true;
496
+ console.log('### <<<<< refresh() >>>>>');
497
+
489
498
  // refresh () {
490
499
  // ### refresh Fore UI elements
491
500
  // if (!this.initialRun && this.toRefresh.length !== 0) {
@@ -556,10 +565,12 @@ export class FxFore extends HTMLElement {
556
565
  this.style.visibility='visible';
557
566
  Fore.dispatch(this, 'refresh-done', {});
558
567
 
559
- this.isRefreshing = true;
560
- this.parentNode.closest('fx-fore')?.refresh(false, changedPaths);
568
+ // this.isRefreshing = true;
569
+ // this.parentNode.closest('fx-fore')?.refresh(false, changedPaths);
570
+ this.parentNode.closest('fx-fore')?.refresh(false);
561
571
  for (const subFore of this.querySelectorAll('fx-fore')) {
562
- subFore.refresh(false, changedPaths);
572
+ // subFore.refresh(false, changedPaths);
573
+ subFore.refresh(false);
563
574
  }
564
575
  this.isRefreshing = false;
565
576
  }
@@ -649,6 +660,13 @@ export class FxFore extends HTMLElement {
649
660
  * @param node the node which will get updated with evaluation result
650
661
  */
651
662
  evaluateTemplateExpression(expr, node) {
663
+
664
+ // ### do not evaluate template expressions with nonrelevant sections
665
+ if(node.nodeType === Node.ATTRIBUTE_NODE && node.ownerElement.closest('[nonrelevant]')) return;
666
+ if(node.nodeType === Node.TEXT_NODE && node.parentNode.closest('[nonrelevant]')) return;
667
+ if(node.nodeType === Node.ELEMENT_NODE && node.closest('[nonrelevant]')) return;
668
+
669
+ // if(node.closest('[nonrelevant]')) return;
652
670
  const replaced = expr.replace(/{[^}]*}/g, match => {
653
671
  if (match === '{}') return match;
654
672
  const naked = match.substring(1, match.length - 1);
@@ -750,30 +768,31 @@ export class FxFore extends HTMLElement {
750
768
  */
751
769
  async _lazyCreateInstance() {
752
770
  const model = this.querySelector('fx-model');
753
- // Inherit shared models from the parent component
754
771
 
772
+ // ##### lazy creation should NOT take place if there's a parent Fore using shared instances
755
773
  const parentFore = this.parentNode.closest('fx-fore');
756
- if (parentFore) {
757
- const sharedInstances = Array.from(parentFore.getModel().querySelectorAll('fx-instance')).filter(instance => instance.hasAttribute('shared'));
758
- for(const instance of sharedInstances) {
759
- this.getModel().instances.push(instance);
760
- }
761
- this.getModel().updateModel();
762
- }
763
-
764
-
765
- if (model.instances.length === 0) {
766
- // console.log('### lazy creation of instance');
767
- const generatedInstance = document.createElement('fx-instance');
768
- model.appendChild(generatedInstance);
774
+ if(parentFore){
775
+ const shared = parentFore.getModel().instances.filter(shared => shared.hasAttribute('shared'));
776
+ if(shared.length !==0) return;
777
+ }
769
778
 
770
- const generated = document.implementation.createDocument(null, 'data', null);
771
- // const newData = this._generateInstance(this, generated.firstElementChild);
772
- this._generateInstance(this, generated.firstElementChild);
773
- generatedInstance.instanceData = generated;
774
- model.instances.push(generatedInstance);
775
- // console.log('generatedInstance ', this.getModel().getDefaultInstanceData());
776
- Fore.dispatch(this,'instance-loaded',{instance:this});
779
+ // still need to catch just in case...
780
+ try{
781
+ if (model.instances.length === 0) {
782
+ // console.log('### lazy creation of instance');
783
+ const generatedInstance = document.createElement('fx-instance');
784
+ model.appendChild(generatedInstance);
785
+
786
+ const generated = document.implementation.createDocument(null, 'data', null);
787
+ // const newData = this._generateInstance(this, generated.firstElementChild);
788
+ this._generateInstance(this, generated.firstElementChild);
789
+ generatedInstance.instanceData = generated;
790
+ model.instances.push(generatedInstance);
791
+ // console.log('generatedInstance ', this.getModel().getDefaultInstanceData());
792
+ Fore.dispatch(this,'instance-loaded',{instance:this});
793
+ }
794
+ }catch (e) {
795
+ console.warn('lazyCreateInstance created an error attempting to create a document', e.message);
777
796
  }
778
797
  }
779
798
 
@@ -869,6 +888,8 @@ export class FxFore extends HTMLElement {
869
888
  */
870
889
  async _initUI() {
871
890
  // console.log('### _initUI()');
891
+ console.log('### <<<<< _initUI >>>>>');
892
+
872
893
  if (!this.initialRun) return;
873
894
  this.classList.add('initialRun');
874
895
  await this._lazyCreateInstance();
@@ -902,6 +923,8 @@ export class FxFore extends HTMLElement {
902
923
  this.ready = true;
903
924
  this.initialRun = false;
904
925
  // console.log('### >>>>> dispatching ready >>>>>', this);
926
+ console.log(`### <<<<< ${this.id} ready >>>>>`);
927
+
905
928
  // console.log('### modelItems: ', this.getModel().modelItems);
906
929
  Fore.dispatch(this, 'ready', {});
907
930
  // console.log('dataChanged', FxModel.dataChanged);
@@ -953,39 +976,23 @@ export class FxFore extends HTMLElement {
953
976
  toast.showToast(`WARN: ${path}:${msg}`);
954
977
  }
955
978
 
979
+
956
980
  _logError(e) {
957
981
  e.stopPropagation();
958
982
  e.preventDefault();
959
983
 
960
- const div = document.createElement('div');
961
- div.setAttribute('slot','messages');
962
- div.setAttribute('data-level',e.detail.level);
963
-
964
- const id = document.createElement('div');
965
- id.textContent = `"${e.detail.id}"`;
966
- div.appendChild(id);
967
-
968
- const path = document.createElement('div');
969
- const pathExpr = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
970
- // console.log('pathExpr',pathExpr)
971
- path.textContent = pathExpr;
972
- div.appendChild(path);
973
-
974
- const message = document.createElement('div');
975
- message.textContent = e.detail.message;
976
- div.appendChild(message);
977
-
978
- /*
979
- const path = XPathUtil.shortenPath(evaluateXPathToString('path()',e.target,this));
980
- div.innerText = `${path} :: ${e.detail.message}`;
981
- */
982
- this.appendChild(div);
983
- div.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"});
984
-
985
-
986
- const errorElement = evaluateXPathToFirstNode(`/${pathExpr}`,document,null);
987
- errorElement.classList.add('fore-error');
984
+ console.error('ERROR',e.detail.message);
985
+ console.error(e.detail.origin);
986
+ if(e.detail.expr){
987
+ console.error('Failing expression',e.detail.expr);
988
+ }
989
+ console.error('---');
990
+ this._displayError(e);
991
+ }
988
992
 
993
+ _copyToClipboard(target){
994
+ console.log('copyToClipboard' , target.value)
995
+ navigator.clipboard.writeText(target.value);
989
996
 
990
997
  }
991
998
 
package/src/fx-model.js CHANGED
@@ -30,6 +30,7 @@ export class FxModel extends HTMLElement {
30
30
  this.modelConstructed = false;
31
31
  this.attachShadow({mode: 'open'});
32
32
  this.computes = 0;
33
+ this.fore = {};
33
34
  }
34
35
 
35
36
  get formElement() {
@@ -49,6 +50,7 @@ export class FxModel extends HTMLElement {
49
50
  }, {once: true});
50
51
 
51
52
  this.skipUpdate = false;
53
+ this.fore = this.parentNode;
52
54
  }
53
55
 
54
56
  static lazyCreateModelItem(model, ref, node) {
@@ -104,7 +106,7 @@ export class FxModel extends HTMLElement {
104
106
  *
105
107
  */
106
108
  async modelConstruct() {
107
- // console.log('### <<<<< dispatching model-construct >>>>>');
109
+ console.log('### <<<<< dispatching model-construct >>>>>');
108
110
  // this.dispatchEvent(new CustomEvent('model-construct', { detail: this }));
109
111
  Fore.dispatch(this, 'model-construct', {model: this});
110
112
 
@@ -122,12 +124,12 @@ export class FxModel extends HTMLElement {
122
124
  this.instances = Array.from(instances);
123
125
  // console.log('_modelConstruct this.instances ', this.instances);
124
126
  // Await until the model-construct-done event is handled off
125
-
126
127
  await Fore.dispatch(this, 'model-construct-done', {model: this});
127
128
  this.inited = true;
128
129
  this.updateModel();
129
130
  } else {
130
131
  // ### if there's no instance one will created
132
+ console.log('### <<<<< dispatching model-construct-done >>>>>');
131
133
  await this.dispatchEvent(
132
134
  new CustomEvent('model-construct-done', {
133
135
  composed: false,
@@ -165,6 +167,8 @@ export class FxModel extends HTMLElement {
165
167
  }
166
168
 
167
169
  rebuild() {
170
+ console.log('### <<<<< rebuild() >>>>>');
171
+
168
172
  this.mainGraph = new DepGraph(false); // do: should be moved down below binds.length check but causes errors in tests.
169
173
  this.modelItems = [];
170
174
 
@@ -194,10 +198,13 @@ export class FxModel extends HTMLElement {
194
198
  * todo: use 'changed' flag on modelItems to determine subgraph for recalculation. Flag already exists but is not used.
195
199
  */
196
200
  recalculate() {
201
+
197
202
  if (!this.mainGraph) {
198
203
  return;
199
204
  }
200
205
 
206
+ console.log('### <<<<< recalculate() >>>>>');
207
+
201
208
  // console.log('changed nodes ', this.changed);
202
209
  this.computes = 0;
203
210
 
@@ -361,14 +368,13 @@ export class FxModel extends HTMLElement {
361
368
 
362
369
  if (this.modelItems.length === 0) return true;
363
370
 
364
- console.time('revalidate');
371
+ console.log('### <<<<< revalidate() >>>>>');
365
372
 
366
373
  // reset submission validation
367
374
  // this.parentNode.classList.remove('submit-validation-failed')
368
375
  let valid = true;
369
376
  this.modelItems.forEach(modelItem => {
370
377
  // console.log('validating node ', modelItem.node);
371
-
372
378
  const {bind} = modelItem;
373
379
  if (bind) {
374
380
  /*
@@ -382,7 +388,10 @@ export class FxModel extends HTMLElement {
382
388
  // console.log('modelItem validity computed: ', compute);
383
389
  modelItem.constraint = compute;
384
390
  this.formElement.addToRefresh(modelItem); // let fore know that modelItem needs refresh
385
- if (!compute) valid = false;
391
+ if (!compute) {
392
+ console.log('validation failed on modelitem ', modelItem);
393
+ valid = false;
394
+ }
386
395
  }
387
396
  }
388
397
  if (typeof bind.hasAttribute === 'function' && bind.hasAttribute('required')) {
@@ -393,6 +402,7 @@ export class FxModel extends HTMLElement {
393
402
  modelItem.required = compute;
394
403
  this.formElement.addToRefresh(modelItem); // let fore know that modelItem needs refresh
395
404
  if (!modelItem.node.textContent) {
405
+ console.log('validation failed on modelitem ', modelItem);
396
406
  valid = false;
397
407
  }
398
408
  // if (!compute) valid = false;
@@ -450,9 +460,23 @@ export class FxModel extends HTMLElement {
450
460
  // console.log('instances array ',Array.from(this.instances));
451
461
 
452
462
  const instArray = Array.from(this.instances);
453
- const found = instArray.find(inst => inst.id === id);
463
+ let found = instArray.find(inst => inst.id === id);
464
+ if(!found) {
465
+ const parentFore = this.fore.parentNode.closest('fx-fore');
466
+ if (parentFore) {
467
+ console.log('shared instances from parent', this.parentNode.id);
468
+ const parentInstances = parentFore.getModel().instances;
469
+ const shared = parentInstances.filter(shared => shared.hasAttribute('shared'));
470
+ found = shared.find(found => found.id === id);
471
+ }
472
+ }
454
473
  if(!found){
455
- return this.getDefaultInstance(); // if id is not found always defaults to first in doc order
474
+ // return this.getDefaultInstance(); // if id is not found always defaults to first in doc order
475
+ Fore.dispatch(this, 'error', {
476
+ origin: this,
477
+ message: `Instance '${id}' does not exist`,
478
+ level:'Error'
479
+ });
456
480
  }
457
481
  return found;
458
482
  }
@@ -144,6 +144,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
144
144
  const data = this._parse(serialized, instance);
145
145
  this._handleResponse(data);
146
146
  // this.dispatch('submit-done', {});
147
+ console.log('### <<<<< submit-done >>>>>');
147
148
  Fore.dispatch(this, 'submit-done', {});
148
149
  this.parameters.clear();
149
150
  return;
@@ -166,6 +167,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
166
167
  if (this.method === 'consume') {
167
168
  localStorage.removeItem(key);
168
169
  }
170
+ console.log('### <<<<< submit-done >>>>>');
169
171
  Fore.dispatch(this, 'submit-done', {});
170
172
  }
171
173
  if (this.method === 'post') {
@@ -173,6 +175,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
173
175
  const key = resolvedUrl.substring(resolvedUrl.indexOf(':') + 1);
174
176
  localStorage.setItem(key, serialized);
175
177
  this._handleResponse(instance.instanceData);
178
+ console.log('### <<<<< submit-done >>>>>');
176
179
  Fore.dispatch(this, 'submit-done', {});
177
180
  }
178
181
  if (this.method === 'delete') {
@@ -180,6 +183,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
180
183
  localStorage.removeItem(key);
181
184
  const newInst = new DOMParser().parseFromString('<data></data>', 'application/xml');
182
185
  this._handleResponse(newInst);
186
+ console.log('### <<<<< submit-done >>>>>');
183
187
  Fore.dispatch(this, 'submit-done', {});
184
188
  }
185
189
 
@@ -228,6 +232,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
228
232
  }
229
233
 
230
234
  // this.dispatch('submit-done', {});
235
+ console.log(`### <<<<< ${this.id} submit-done >>>>>`);
231
236
  Fore.dispatch(this, 'submit-done', {});
232
237
  } catch (error) {
233
238
  Fore.dispatch(this, 'submit-error', {error: error.message});
@@ -459,7 +459,7 @@ export class FxActionLog extends HTMLElement {
459
459
  */
460
460
  _logDetails(e) {
461
461
  const eventType = e.type;
462
- const path = XPathUtil.getPath(e.target, 'unknown');
462
+ const path = XPathUtil.getDocPath(e.target);
463
463
  // console.log('>>>> _logDetails', path);
464
464
  const cut = path.substring(path.indexOf('/fx-fore'), path.length);
465
465
  const xpath = `/${cut}`;
@@ -14,7 +14,7 @@ import { evaluateXPathToFirstNode} from '../xpath-evaluation.js';
14
14
  export default class AbstractControl extends foreElementMixin(HTMLElement) {
15
15
  constructor() {
16
16
  super();
17
- this.value = '';
17
+ this.value = null;
18
18
  this.display = this.style.display;
19
19
  this.required = false;
20
20
  this.readonly = false;
@@ -24,27 +24,6 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
24
24
  // this.attachShadow({ mode: 'open' });
25
25
  }
26
26
 
27
-
28
- // todo: discuss - this is a hack to circumvent that modelItems in toRefresh diverge from the modelItems in
29
- // the model in some situations. This code first looks for refresh
30
- /*
31
- getModelItem() {
32
- console.log('toRefreshModelItems', this.getOwnerForm().toRefresh);
33
- const s = this.modelItem.path;
34
- console.log('toRefreshModelItems path', s);
35
-
36
- const toRefresh = this.getOwnerForm().toRefresh;
37
- let mi;
38
- if(toRefresh){
39
- mi = this.getOwnerForm().toRefresh.find(m => m.path === s);
40
- }
41
-
42
- return mi? mi: super.getModelItem();
43
- // console.log('toRefreshModelItems realitem', mi);
44
-
45
- }
46
- */
47
-
48
27
  // eslint-disable-next-line class-methods-use-this
49
28
  getWidget() {
50
29
  throw new Error('You have to implement the method getWidget!');
@@ -65,6 +44,8 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
65
44
  // await this.updateComplete;
66
45
  // await this.getWidget();
67
46
  this.oldVal = this.nodeset ? this.nodeset : null;
47
+ // console.log('oldVal',this.oldVal);
48
+
68
49
  this.evalInContext();
69
50
 
70
51
  // todo this if should be removed - see above
@@ -105,7 +86,8 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
105
86
  }else{
106
87
  // ### this actually makes the control nonrelevant
107
88
  // todo: we should call a template function here to allow detachment of event-listeners and resetting eventual state
108
- this.style.display = 'none';
89
+ // this.style.display = 'none';
90
+ this.setAttribute('nonrelevant','');
109
91
  }
110
92
  return;
111
93
  }
@@ -124,6 +106,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
124
106
  } else {
125
107
  this.value = this.modelItem.value;
126
108
  }
109
+ // console.log('newVal',this.value);
127
110
 
128
111
  // console.log('value of widget',this.value);
129
112
 
@@ -160,9 +143,8 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
160
143
  Fore.dispatch(this,'init',{});
161
144
  }
162
145
  if (!this.getOwnerForm().ready) return; // state change event do not fire during init phase (initial refresh)
163
- if (currentVal !== this.value ) {
164
- // todo: discuss how to prevent unnecessary/unwanted value-changes e.g. when repeatitems are inserted
165
- // if (currentVal !== this.value && this.visited) {
146
+ // if oldVal is null we haven't received a concrete value yet
147
+ if (this.oldVal !== null && currentVal !== this.value) {
166
148
  Fore.dispatch(this, 'value-changed', { path: this.modelItem.path , value:this.modelItem.value});
167
149
  }
168
150
  }
@@ -337,20 +319,25 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
337
319
  handleRelevant() {
338
320
  // console.log('mip valid', this.modelItem.enabled);
339
321
  const item = this.modelItem.node;
322
+ this.removeAttribute('relevant');
323
+ this.removeAttribute('nonrelevant');
340
324
  if (Array.isArray(item) && item.length === 0) {
341
325
  this._dispatchEvent('nonrelevant');
342
- this.style.display = 'none';
326
+ this.setAttribute('nonrelevant','');
327
+ // this.style.display = 'none';
343
328
  return;
344
329
  }
345
330
  if (this.isEnabled() !== this.modelItem.relevant) {
346
331
  if (this.modelItem.relevant) {
347
332
  this._dispatchEvent('relevant');
348
333
  // this._fadeIn(this, this.display);
349
- this.style.display = this.display;
334
+ this.setAttribute('relevant','');
335
+ // this.style.display = this.display;
350
336
  } else {
351
337
  this._dispatchEvent('nonrelevant');
352
338
  // this._fadeOut(this);
353
- this.style.display = 'none';
339
+ this.setAttribute('nonrelevant','');
340
+ // this.style.display = 'none';
354
341
  }
355
342
  }
356
343
  }
@@ -360,11 +347,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
360
347
  }
361
348
 
362
349
  isValid() {
363
- // return this.valid;
364
- if (this.hasAttribute('invalid')) {
365
- return false;
366
- }
367
- return true;
350
+ return this.hasAttribute('invalid') ? false : true;
368
351
  }
369
352
 
370
353
  isReadonly() {
@@ -373,11 +356,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
373
356
  }
374
357
 
375
358
  isEnabled() {
376
- // if(this.style.display === 'none' || this.classList.contains('non-relevant')){
377
- if (this.style.display === 'none') {
378
- return false;
379
- }
380
- return true;
359
+ return !this.hasAttribute('nonrelevant');
381
360
  }
382
361
 
383
362
  // eslint-disable-next-line class-methods-use-this
@@ -123,12 +123,8 @@ export default class FxControl extends XfAbstractControl {
123
123
 
124
124
  this.addEventListener('keyup', () => {
125
125
  FxModel.dataChanged = true;
126
- /*
127
- if (!this.classList.contains('visited')) {
128
- this.classList.add('visited');
129
- }
130
- */
131
126
  });
127
+
132
128
  // ### convenience marker event
133
129
  if (this.updateEvent === 'enter') {
134
130
  this.widget.addEventListener('keyup', event => {
@@ -494,9 +490,13 @@ export default class FxControl extends XfAbstractControl {
494
490
  this.dispatchEvent(new CustomEvent('loaded', {detail: {fore: theFore}}));
495
491
  } catch (error) {
496
492
  // console.log('error', error);
497
- this.getOwnerForm().dispatchEvent(
498
- new CustomEvent('error', {detail: {message: `${this.url} not found`}}),
499
- );
493
+ Fore.dispatch(this, 'error', {
494
+ origin: this,
495
+ message: `control couldn't be loaded from url '${this.url}'`,
496
+ expr:xpath,
497
+ level:'Error'
498
+ });
499
+
500
500
  }
501
501
  }
502
502
 
@@ -550,9 +550,6 @@ export default class FxControl extends XfAbstractControl {
550
550
  // const nodeset = evaluateXPathToNodes(ref, inscope, this);
551
551
  const nodeset = evaluateXPath(ref, inscope, this);
552
552
 
553
- // ### bail out when nodeset is array and empty
554
- if (Array.isArray(nodeset) && nodeset.length === 0) return;
555
-
556
553
  // ### clear items
557
554
  const {children} = widget;
558
555
  Array.from(children).forEach(child => {
@@ -561,6 +558,9 @@ export default class FxControl extends XfAbstractControl {
561
558
  }
562
559
  });
563
560
 
561
+ // ### bail out when nodeset is array and empty
562
+ if (Array.isArray(nodeset) && nodeset.length === 0) return;
563
+
564
564
  // ### build the items
565
565
  const {template} = this;
566
566
  if (template) {
@@ -574,7 +574,7 @@ export default class FxControl extends XfAbstractControl {
574
574
  this.widget.insertBefore(option, firstTemplateChild);
575
575
  }
576
576
 
577
- if (nodeset.length) {
577
+ if (nodeset.length !== 0) {
578
578
  // console.log('nodeset', nodeset);
579
579
  const fragment = document.createDocumentFragment();
580
580
  // console.time('offscreen');
@@ -135,9 +135,9 @@ export class FxRepeatAttributes extends foreElementMixin(HTMLElement) {
135
135
  if (mutations[0].type === 'childList') {
136
136
  const added = mutations[0].addedNodes[0];
137
137
  if (added) {
138
- const instance = XPathUtil.resolveInstance(this);
139
138
 
140
- const path = XPathUtil.getPath(added, instance);
139
+ const instance = XPathUtil.resolveInstance(this,this.ref);
140
+ const path = XPathUtil.getPath(added, instance);
141
141
  // this.dispatch('path-mutated',{'path':path,'nodeset':this.nodeset,'index': this.index});
142
142
  // this.index = index;
143
143
  // const prev = mutations[0].previousSibling.previousElementSibling;