@jinntec/fore 1.10.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/fore.js CHANGED
@@ -18,6 +18,79 @@ export class Fore {
18
18
 
19
19
  static TYPE_DEFAULT = 'xs:string';
20
20
 
21
+ /**
22
+ * Loads and return a piece of HTML
23
+ * @param url - the Url to load from
24
+ * @returns {Promise<string>}
25
+ */
26
+ static async loadHtml(url){
27
+ try{
28
+ const response = await fetch(url, {
29
+ method: 'GET',
30
+ mode: 'cors',
31
+ credentials: 'same-origin',
32
+ headers: {
33
+ 'Content-Type': "text/html",
34
+ },
35
+ });
36
+ const responseContentType = response.headers.get('content-type').toLowerCase();
37
+ if (responseContentType.startsWith('text/html')) {
38
+ return response.text();
39
+ } else {
40
+ Fore.dispatch(this, 'error', {
41
+ message: `Response has wrong contentType '${responseContentType}'. Should be 'text/html'`,
42
+ level:'Error'
43
+ });
44
+ }
45
+ } catch (e){
46
+ Fore.dispatch(this, 'error', {
47
+ message: `Html couldn't be loaded from '${url}'`,
48
+ level:'Error'
49
+ });
50
+ }
51
+ }
52
+
53
+ /**
54
+ * loads a Fore element from given `src`. Always returns the first occurrence of a `<fx-fore>`. The retured element
55
+ * will replace the `replace` element in the DOM.
56
+ *
57
+ * @param replace the element with a `src` attribute to resolvé.
58
+ * @param src the Url to resolve
59
+ * @param selector a querySelector expression to fetch certain element from loaded document
60
+ * @returns {Promise<void>}
61
+ */
62
+ static async loadForeFromSrc(replace, src, selector){
63
+ if(!src){
64
+ Fore.dispatch(this, 'error', {
65
+ detail: {
66
+ message: `No 'src' attribute present`,
67
+ },
68
+ });
69
+ }
70
+ await Fore.loadHtml(src)
71
+ .then(data => {
72
+ const parsed = new DOMParser().parseFromString(data, 'text/html');
73
+ // const theFore = parsed.querySelector('fx-fore');
74
+ const foreElement = parsed.querySelector(selector);
75
+ // console.log('foreElement', foreElement)
76
+ if (!foreElement) {
77
+ Fore.dispatch(this, 'error', {
78
+ detail: {
79
+ message: `Fore element not found in '${src}'. Maybe wrapped within 'template' element?`,
80
+ },
81
+ });
82
+ }
83
+ foreElement.setAttribute('from-src', src);
84
+ const thisAttrs = replace.attributes;
85
+ Array.from(thisAttrs).forEach(attr =>{
86
+ if(attr.name !== 'src'){
87
+ foreElement.setAttribute(attr.name,attr.value);
88
+ }
89
+ });
90
+ replace.replaceWith(foreElement);
91
+ return foreElement;
92
+ });
93
+ }
21
94
  static buildPredicates(node){
22
95
  let attrPredicate='';
23
96
  Array.from(node.attributes).forEach(attr =>{
@@ -339,6 +412,7 @@ export class Fore {
339
412
  return 'done';
340
413
  }
341
414
 
415
+ /*
342
416
  static evaluateAttributeTemplateExpression(expr, node) {
343
417
  const matches = expr.match(/{[^}]*}/g);
344
418
  if (matches) {
@@ -354,6 +428,7 @@ export class Fore {
354
428
  }
355
429
  return expr;
356
430
  }
431
+ */
357
432
 
358
433
  static fadeInElement(element) {
359
434
  const duration = 600;
@@ -467,6 +542,7 @@ export class Fore {
467
542
  static stringifiedComponent(element){
468
543
  return `<${element.localName} ${Array.from(element.attributes).map(attr=>`${attr.name}="${attr.value}"`).join(' ')}>…</${element.localName}>`;
469
544
  }
545
+ /*
470
546
  static async loadForeFromUrl(hostElement, url) {
471
547
  // console.log('########## loading Fore from ', this.src, '##########');
472
548
  await fetch(url, {
@@ -538,7 +614,7 @@ export class Fore {
538
614
  // this.appendChild(imported);
539
615
  }
540
616
  })
541
- /*.catch(error => {
617
+ /!*.catch(error => {
542
618
  hostElement.dispatchEvent(
543
619
  new CustomEvent('error', {
544
620
  composed: false,
@@ -549,8 +625,9 @@ export class Fore {
549
625
  },
550
626
  }),
551
627
  );
552
- });*/
628
+ });*!/
553
629
  }
630
+ */
554
631
 
555
632
  /**
556
633
  * clear all text nodes and attribute values to get a 'clean' template.
package/src/fx-bind.js CHANGED
@@ -72,6 +72,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
72
72
  this._buildBindGraph();
73
73
  this._createModelItems();
74
74
  }
75
+ // todo: support json
75
76
 
76
77
  // ### process child bindings
77
78
  this._processChildren(model);
package/src/fx-fore.js CHANGED
@@ -26,6 +26,7 @@ import {FxRepeatAttributes} from './ui/fx-repeat-attributes.js';
26
26
  */
27
27
  export class FxFore extends HTMLElement {
28
28
  static outermostHandler = null;
29
+ static draggedItem = null;
29
30
 
30
31
  static get properties() {
31
32
  return {
@@ -56,6 +57,9 @@ export class FxFore extends HTMLElement {
56
57
  ready: {
57
58
  type: Boolean,
58
59
  },
60
+ strict:{
61
+ type: Boolean
62
+ },
59
63
  /**
60
64
  *
61
65
  */
@@ -100,6 +104,8 @@ export class FxFore extends HTMLElement {
100
104
  // updates are included in that one
101
105
  this.outermostHandler = null;
102
106
 
107
+ this.copiedElements = new WeakSet();
108
+
103
109
  const style = `
104
110
  :host {
105
111
  display: block;
@@ -176,7 +182,6 @@ export class FxFore extends HTMLElement {
176
182
  `;
177
183
 
178
184
  const html = `
179
- <noscript>This page uses Web Components and needs JavaScript to be enabled..</noscript>
180
185
  <!-- <slot name="errors"></slot> -->
181
186
  <jinn-toast id="message" gravity="bottom" position="left"></jinn-toast>
182
187
  <jinn-toast id="sticky" gravity="bottom" position="left" duration="-1" close="true" data-class="sticky-message"></jinn-toast>
@@ -204,7 +209,7 @@ export class FxFore extends HTMLElement {
204
209
 
205
210
  this.toRefresh = [];
206
211
  this.initialRun = true;
207
- this.someInstanceDataStructureChanged = false;
212
+ this._scanForNewTemplateExpressionsNextRefresh = false;
208
213
  this.repeatsFromAttributesCreated = false;
209
214
  this.validateOn = this.hasAttribute('validate-on') ? this.getAttribute('validate-on'):'update';
210
215
  // this.mergePartial = this.hasAttribute('merge-partial')? true:false;
@@ -214,6 +219,7 @@ export class FxFore extends HTMLElement {
214
219
  connectedCallback() {
215
220
  this.style.visibility = 'hidden';
216
221
  console.time('init');
222
+ this.strict = this.hasAttribute('strict') ? true : false;
217
223
  /*
218
224
  document.addEventListener('ready', (e) =>{
219
225
  if(e.target !== this){
@@ -255,6 +261,7 @@ export class FxFore extends HTMLElement {
255
261
  const slot = this.shadowRoot.querySelector('slot#default');
256
262
  slot.addEventListener('slotchange', async event => {
257
263
  // preliminary addition for auto-conversion of non-prefixed element into prefixed elements. See fore.js
264
+ console.log(`### <<<<< slotchange on '${this.id}' >>>>>`);
258
265
  if(this.inited) return;
259
266
  if(this.hasAttribute('convert')){
260
267
  this.replaceWith(Fore.copyDom(this));
@@ -280,8 +287,8 @@ export class FxFore extends HTMLElement {
280
287
  }
281
288
  if (!modelElement.inited) {
282
289
  console.info(
283
- `%cFore is processing URL ${window.location.href}`,
284
- "background:#64b5f6; color:white; padding:1rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;",
290
+ `%cFore is processing fx-fore#${this.id}`,
291
+ "background:#64b5f6; color:white; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;",
285
292
  );
286
293
 
287
294
  await modelElement.modelConstruct();
@@ -296,6 +303,9 @@ export class FxFore extends HTMLElement {
296
303
  this.addEventListener('path-mutated', () => {
297
304
  this.someInstanceDataStructureChanged = true;
298
305
  });
306
+ this.addEventListener('refresh', () => {
307
+ this.refresh(true);
308
+ });
299
309
 
300
310
  }
301
311
 
@@ -319,6 +329,15 @@ export class FxFore extends HTMLElement {
319
329
  }
320
330
  }
321
331
 
332
+ /**
333
+ * Raise a flag that there might be new template expressions under some node. This happens with
334
+ * repeats updating (new repeat items can have new template expressions) or switches changing their case (new case = new raw HTML)
335
+ */
336
+ scanForNewTemplateExpressionsNextRefresh() {
337
+ // TODO: also ask for the root of any new HTML: this can prevent some very deep queries.
338
+ this._scanForNewTemplateExpressionsNextRefresh = true;
339
+ }
340
+
322
341
  /**
323
342
  * loads a Fore from an URL given by `src`.
324
343
  *
@@ -327,54 +346,7 @@ export class FxFore extends HTMLElement {
327
346
  */
328
347
  async _loadFromSrc() {
329
348
  // console.log('########## loading Fore from ', this.src, '##########');
330
- await fetch(this.src, {
331
- method: 'GET',
332
- mode: 'cors',
333
- credentials: 'include',
334
- headers: {
335
- 'Content-Type': 'text/html',
336
- },
337
- })
338
- .then(response => {
339
- const responseContentType = response.headers.get('content-type').toLowerCase();
340
- console.log('********** responseContentType *********', responseContentType);
341
- if (responseContentType.startsWith('text/html')) {
342
- // const htmlResponse = response.text();
343
- // return new DOMParser().parseFromString(htmlResponse, 'text/html');
344
- // return response.text();
345
- return response.text().then(result =>
346
- // console.log('xml ********', result);
347
- new DOMParser().parseFromString(result, 'text/html'),
348
- );
349
- }
350
- return 'done';
351
- })
352
- .then(data => {
353
- // const theFore = fxEvaluateXPathToFirstNode('//fx-fore', data.firstElementChild);
354
- const theFore = data.querySelector('fx-fore');
355
-
356
- // console.log('thefore', theFore)
357
- if (!theFore) {
358
- Fore.dispatch(this, 'error', {
359
- detail: {
360
- message: `Fore element not found in '${this.src}'. Maybe wrapped within 'template' element?`,
361
- },
362
- });
363
- }
364
- theFore.setAttribute('from-src', this.src);
365
- const thisAttrs = this.attributes;
366
- Array.from(thisAttrs).forEach(attr =>{
367
- if(attr.name !== 'src'){
368
- theFore.setAttribute(attr.name,attr.value);
369
- }
370
- });
371
- this.replaceWith(theFore);
372
- })
373
- .catch(() => {
374
- Fore.dispatch(this, 'error', {
375
- message: `'${this.src}' not found or does not contain Fore element.`,
376
- });
377
- });
349
+ await Fore.loadForeFromSrc(this,this.src,'fx-fore');
378
350
  }
379
351
 
380
352
  /**
@@ -420,6 +392,7 @@ export class FxFore extends HTMLElement {
420
392
  }
421
393
 
422
394
  disconnectedCallback() {
395
+ this.removeEventListener('dragstart', this.dragstart);
423
396
  /*
424
397
  this.removeEventListener('model-construct-done', this._handleModelConstructDone);
425
398
  this.removeEventListener('message', this._displayMessage);
@@ -443,8 +416,11 @@ export class FxFore extends HTMLElement {
443
416
 
444
417
  Fore.refreshChildren(this, true);
445
418
  this._updateTemplateExpressions();
446
- this.someInstanceDataStructureChanged = false; // reset
419
+ this._scanForNewTemplateExpressionsNextRefresh = false; // reset
447
420
  this._processTemplateExpressions();
421
+
422
+ console.log(`### <<<<< refresh-done ${this.id} >>>>>`);
423
+
448
424
  Fore.dispatch(this, 'refresh-done', {});
449
425
 
450
426
  // console.groupEnd();
@@ -493,7 +469,7 @@ export class FxFore extends HTMLElement {
493
469
  return;
494
470
  }
495
471
  this.isRefreshing = true;
496
- console.log('### <<<<< refresh() >>>>>');
472
+ console.log(`### <<<<< refresh() on '${this.id}' >>>>>`);
497
473
 
498
474
  // refresh () {
499
475
  // ### refresh Fore UI elements
@@ -553,24 +529,44 @@ export class FxFore extends HTMLElement {
553
529
  }
554
530
 
555
531
  // ### refresh template expressions
556
- if (this.initialRun || this.someInstanceDataStructureChanged) {
532
+ if (this.initialRun || this._scanForNewTemplateExpressionsNextRefresh) {
557
533
  this._updateTemplateExpressions();
558
- this.someInstanceDataStructureChanged = false; // reset
534
+ this._scanForNewTemplateExpressionsNextRefresh = false; // reset
559
535
  }
536
+
560
537
  this._processTemplateExpressions();
561
538
 
562
539
  // console.log('### <<<<< dispatching refresh-done - end of UI update cycle >>>>>');
563
540
  // this.dispatchEvent(new CustomEvent('refresh-done'));
564
541
  // this.initialRun = false;
565
542
  this.style.visibility='visible';
543
+ console.log(`### <<<<< refresh-done ${this.id} >>>>>`);
566
544
  Fore.dispatch(this, 'refresh-done', {});
567
545
 
568
546
  // this.isRefreshing = true;
569
547
  // this.parentNode.closest('fx-fore')?.refresh(false, changedPaths);
570
- this.parentNode.closest('fx-fore')?.refresh(false);
571
- for (const subFore of this.querySelectorAll('fx-fore')) {
548
+
549
+ const subFores = Array.from(this.querySelectorAll('fx-fore'));
550
+ /*
551
+ calling the parent to refresh causes errors and inconsistent state. Also it is questionable
552
+ if a child should actually interact with its parent in this way.
553
+
554
+ This only affects the refreshing NOT the data mutation itself which is happening as expected.
555
+
556
+ Current solution is that a child that wants the parent to refresh must do so by adding an additional
557
+ event handler that dispatches an event upwards and having a handler in the parent to refresh itself.
558
+
559
+ So refreshed propagate downwards but not upwards which is at least an option to consider.
560
+
561
+ if(this.parentNode.nodeType !== Node.DOCUMENT_FRAGMENT_NODE){
562
+ // await this.parentNode.closest('fx-fore')?.refresh(false);
563
+ }
564
+ */
565
+ for (const subFore of subFores) {
572
566
  // subFore.refresh(false, changedPaths);
573
- subFore.refresh(false);
567
+ if(subFore.ready){
568
+ await subFore.refresh(false);
569
+ }
574
570
  }
575
571
  this.isRefreshing = false;
576
572
  }
@@ -672,11 +668,11 @@ export class FxFore extends HTMLElement {
672
668
  const naked = match.substring(1, match.length - 1);
673
669
  const inscope = getInScopeContext(node, naked);
674
670
  if (!inscope) {
671
+ console.warn('no inscope context for expr', naked);
675
672
  const errNode =
676
673
  node.nodeType === Node.TEXT_NODE || node.nodeType === Node.ATTRIBUTE_NODE
677
674
  ? node.parentNode
678
675
  : node;
679
- console.warn('no inscope context for ', errNode);
680
676
  return match;
681
677
  }
682
678
  // Templates are special: they use the namespace configuration from the place where they are
@@ -695,11 +691,17 @@ export class FxFore extends HTMLElement {
695
691
  }
696
692
  });
697
693
 
694
+ // Update to the new value. Don't do it though if nothing changed to prevent iframes or
695
+ // images from reloading for example
698
696
  if (node.nodeType === Node.ATTRIBUTE_NODE) {
699
697
  const parent = node.ownerElement;
700
- parent.setAttribute(node.nodeName, replaced);
698
+ if (parent.getAttribute(node.nodeName) !== replaced) {
699
+ parent.setAttribute(node.nodeName, replaced);
700
+ }
701
701
  } else if (node.nodeType === Node.TEXT_NODE) {
702
- node.textContent = replaced;
702
+ if (node.textContent !== replaced) {
703
+ node.textContent = replaced;
704
+ }
703
705
  }
704
706
  }
705
707
 
@@ -770,7 +772,11 @@ export class FxFore extends HTMLElement {
770
772
  const model = this.querySelector('fx-model');
771
773
 
772
774
  // ##### lazy creation should NOT take place if there's a parent Fore using shared instances
773
- const parentFore = this.parentNode.closest('fx-fore');
775
+ const parentFore = this.parentNode.nodeType !== Node.DOCUMENT_FRAGMENT_NODE ? this.parentNode.closest('fx-fore'): null;
776
+ if(this.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE){
777
+ console.log('fragment',this.parentNode)
778
+ }
779
+
774
780
  if(parentFore){
775
781
  const shared = parentFore.getModel().instances.filter(shared => shared.hasAttribute('shared'));
776
782
  if(shared.length !==0) return;
@@ -888,7 +894,7 @@ export class FxFore extends HTMLElement {
888
894
  */
889
895
  async _initUI() {
890
896
  // console.log('### _initUI()');
891
- console.log('### <<<<< _initUI >>>>>');
897
+ console.log(`### <<<<< _initUI '${this.id}' >>>>>`);
892
898
 
893
899
  if (!this.initialRun) return;
894
900
  this.classList.add('initialRun');
@@ -929,8 +935,51 @@ export class FxFore extends HTMLElement {
929
935
  Fore.dispatch(this, 'ready', {});
930
936
  // console.log('dataChanged', FxModel.dataChanged);
931
937
  console.timeEnd('init');
938
+
939
+ this.addEventListener('dragstart', this._handleDragStart);
940
+ // this.addEventListener('dragend', this._handleDragEnd);
941
+ this.handleDrop = event => this._handleDrop(event);
942
+ this.ownerDocument.body.addEventListener('drop', this.handleDrop);
943
+ this.ownerDocument.body.addEventListener('dragover', e=>{
944
+ e.preventDefault();
945
+ e.stopPropagation();
946
+ e.dataTransfer.dropEffect = "move";
947
+ });
932
948
  }
933
949
 
950
+ _handleDragStart (event) {
951
+ const draggedItem = event.target.closest('[draggable="true"]');
952
+ this.originalDraggedItem = draggedItem;
953
+ console.log('DRAG START', this);
954
+ if (draggedItem.getAttribute('drop-action') === 'copy') {
955
+ event.dataTransfer.dropEffect = 'copy';
956
+ event.dataTransfer.effectAllowed = 'copy';
957
+ this.draggedItem = draggedItem.cloneNode(true);
958
+ this.draggedItem.setAttribute('drop-action', 'move');
959
+ this.copiedElements.add(this.draggedItem);
960
+ } else {
961
+ event.dataTransfer.dropEffect = 'move';
962
+ event.dataTransfer.effectAllowed = 'move';
963
+ this.draggedItem = draggedItem;
964
+ }
965
+ }
966
+
967
+ _handleDrop (event) {
968
+ console.log('DROP ON BODY', this)
969
+ if (!this.draggedItem) {
970
+ return;
971
+ }
972
+ // A drop on 'body' should be a removal.
973
+ if (event.dataTransfer.dropEffect === 'none') {
974
+ if (this.copiedElements.has(this.originalDraggedItem)) {
975
+ this.originalDraggedItem.remove();
976
+ }
977
+ }
978
+ this.originalDraggedItem = null
979
+ this.draggedItem = null;
980
+ event.stopPropagation();
981
+ }
982
+
934
983
  registerLazyElement(element) {
935
984
  if (this.intersectionObserver) {
936
985
  // console.log('registerLazyElement',element);
@@ -986,8 +1035,9 @@ export class FxFore extends HTMLElement {
986
1035
  if(e.detail.expr){
987
1036
  console.error('Failing expression',e.detail.expr);
988
1037
  }
989
- console.error('---');
990
- this._displayError(e);
1038
+ if(this.strict){
1039
+ this._displayError(e);
1040
+ }
991
1041
  }
992
1042
 
993
1043
  _copyToClipboard(target){
@@ -110,6 +110,7 @@ export class FxInstance extends HTMLElement {
110
110
  async init() {
111
111
  // console.log('fx-instance init');
112
112
  await this._initInstance();
113
+ console.log(`### <<<<< instance ${this.id} loaded >>>>> `);
113
114
  this.dispatchEvent(
114
115
  new CustomEvent('instance-loaded', {
115
116
  composed: true,
package/src/fx-model.js CHANGED
@@ -106,7 +106,7 @@ export class FxModel extends HTMLElement {
106
106
  *
107
107
  */
108
108
  async modelConstruct() {
109
- console.log('### <<<<< dispatching model-construct >>>>>');
109
+ console.log(`### <<<<< dispatching model-construct for '${this.fore.id}' >>>>>`);
110
110
  // this.dispatchEvent(new CustomEvent('model-construct', { detail: this }));
111
111
  Fore.dispatch(this, 'model-construct', {model: this});
112
112
 
@@ -129,7 +129,7 @@ export class FxModel extends HTMLElement {
129
129
  this.updateModel();
130
130
  } else {
131
131
  // ### if there's no instance one will created
132
- console.log('### <<<<< dispatching model-construct-done >>>>>');
132
+ console.log(`### <<<<< dispatching model-construct-done for '${this.fore.id}' >>>>>`);
133
133
  await this.dispatchEvent(
134
134
  new CustomEvent('model-construct-done', {
135
135
  composed: false,
@@ -167,7 +167,7 @@ export class FxModel extends HTMLElement {
167
167
  }
168
168
 
169
169
  rebuild() {
170
- console.log('### <<<<< rebuild() >>>>>');
170
+ console.log(`### <<<<< rebuild() '${this.fore.id}' >>>>>`);
171
171
 
172
172
  this.mainGraph = new DepGraph(false); // do: should be moved down below binds.length check but causes errors in tests.
173
173
  this.modelItems = [];
@@ -203,7 +203,7 @@ export class FxModel extends HTMLElement {
203
203
  return;
204
204
  }
205
205
 
206
- console.log('### <<<<< recalculate() >>>>>');
206
+ console.log(`### <<<<< recalculate() '${this.fore.id}' >>>>>`);
207
207
 
208
208
  // console.log('changed nodes ', this.changed);
209
209
  this.computes = 0;
@@ -368,7 +368,7 @@ export class FxModel extends HTMLElement {
368
368
 
369
369
  if (this.modelItems.length === 0) return true;
370
370
 
371
- console.log('### <<<<< revalidate() >>>>>');
371
+ console.log(`### <<<<< revalidate() '${this.fore.id}' >>>>>`);
372
372
 
373
373
  // reset submission validation
374
374
  // this.parentNode.classList.remove('submit-validation-failed')
@@ -447,7 +447,10 @@ export class FxModel extends HTMLElement {
447
447
  }
448
448
 
449
449
  getDefaultInstance() {
450
- return this.instances[0];
450
+ if (this.instances.length) {
451
+ return this.instances[0];
452
+ }
453
+ return this.getInstance('default');
451
454
  }
452
455
 
453
456
  getDefaultInstanceData() {
@@ -459,18 +462,40 @@ export class FxModel extends HTMLElement {
459
462
  // console.log('instances ', this.instances);
460
463
  // console.log('instances array ',Array.from(this.instances));
461
464
 
462
- const instArray = Array.from(this.instances);
463
- let found = instArray.find(inst => inst.id === id);
465
+ let found;
466
+ if(id === 'default'){
467
+ found = this.instances[0];
468
+ }
469
+ // ### lookup in local instances first
464
470
  if(!found) {
465
- const parentFore = this.fore.parentNode.closest('fx-fore');
471
+ const instArray = Array.from(this.instances);
472
+ found = instArray.find(inst => inst.id === id);
473
+ const parentFore = this.fore.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE
474
+ ? this.fore.parentNode.host.closest('fx-fore')
475
+ : this.fore.parentNode.closest('fx-fore');
476
+
477
+ }
478
+ // ### lookup in parent Fore if present
479
+ if(!found){
480
+ // const parentFore = this.fore.parentNode.closest('fx-fore');
481
+ const parentFore = this.fore.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE
482
+ ? this.fore.parentNode.host.closest('fx-fore')
483
+ : this.fore.parentNode.closest('fx-fore');
466
484
  if (parentFore) {
467
485
  console.log('shared instances from parent', this.parentNode.id);
468
486
  const parentInstances = parentFore.getModel().instances;
469
487
  const shared = parentInstances.filter(shared => shared.hasAttribute('shared'));
470
488
  found = shared.find(found => found.id === id);
471
489
  }
490
+
472
491
  }
473
- if(!found){
492
+ if(found){
493
+ return found;
494
+ }
495
+ if (id === 'default') {
496
+ return this.getDefaultInstance(); // if id is not found always defaults to first in doc order
497
+ }
498
+ if(!found && this.fore.strict){
474
499
  // return this.getDefaultInstance(); // if id is not found always defaults to first in doc order
475
500
  Fore.dispatch(this, 'error', {
476
501
  origin: this,
@@ -478,7 +503,7 @@ export class FxModel extends HTMLElement {
478
503
  level:'Error'
479
504
  });
480
505
  }
481
- return found;
506
+ return null;
482
507
  }
483
508
 
484
509
  evalBinding(bindingExpr) {
@@ -48,14 +48,16 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
48
48
  ? this.getAttribute('serialization')
49
49
  : 'xml';
50
50
 
51
- this.url = this.hasAttribute('url') ? this.getAttribute('url'):null;
52
-
53
- this.targetref = this.hasAttribute('targetref') ? this.getAttribute('targetref') : null;
54
-
55
51
  this.mediatype = this.hasAttribute('mediatype')
56
52
  ? this.getAttribute('mediatype')
57
53
  : 'application/xml';
58
54
 
55
+ this.responseMediatype = this.hasAttribute('response-mediatype') ? this.getAttribute('response-mediatype') : this.mediatype;
56
+ this.url = this.hasAttribute('url') ? this.getAttribute('url') : null;
57
+
58
+ this.targetref = this.hasAttribute('targetref') ? this.getAttribute('targetref') : null;
59
+
60
+
59
61
  this.validate = this.getAttribute('validate') ? this.getAttribute('validate') : 'true';
60
62
  this.credentials = this.hasAttribute('credentials')
61
63
  ? this.getAttribute('credentials')
@@ -85,7 +87,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
85
87
 
86
88
  model.recalculate();
87
89
 
88
- if (this.validate === 'true') {
90
+ if (this.validate === 'true' && this.method !== 'get') {
89
91
  const valid = model.revalidate();
90
92
  if (!valid) {
91
93
  console.log('validation failed. Submission stopped');
@@ -134,6 +136,23 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
134
136
 
135
137
  // let serialized = serializer.serializeToString(relevant);
136
138
  if (this.method.toLowerCase() === 'get') {
139
+ /*
140
+ todo: serialize the bound instance element names as get parameters and using their text values
141
+ as param values. leave out empty params and create querystring from the result.Elements may
142
+ have exactly level deep or are otherwise ignored.
143
+ <data>
144
+ <id>1234</id>
145
+ <name>john</name>
146
+ <zip></zip>
147
+ <!-- ignored as no direct text value -->
148
+ <phone>
149
+ <mobile></mobile>
150
+ <phone>
151
+ </data>
152
+ results in: ?id=1234&name=john to be appended to this.url on fetch
153
+
154
+ */
155
+
137
156
  serialized = undefined;
138
157
  }
139
158
  // console.log('data being send', serialized);
@@ -182,6 +201,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
182
201
  const key = resolvedUrl.substring(resolvedUrl.indexOf(':') + 1);
183
202
  localStorage.removeItem(key);
184
203
  const newInst = new DOMParser().parseFromString('<data></data>', 'application/xml');
204
+ this.replace = 'instance';
185
205
  this._handleResponse(newInst);
186
206
  console.log('### <<<<< submit-done >>>>>');
187
207
  Fore.dispatch(this, 'submit-done', {});