@jinntec/fore 1.10.1 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jinntec/fore",
3
- "version": "1.10.1",
3
+ "version": "1.10.2",
4
4
  "description": "Fore - declarative user interfaces in plain HTML",
5
5
  "module": "./index.js",
6
6
  "publishConfig": {
@@ -23,6 +23,7 @@ class FxToggle extends AbstractAction {
23
23
  super.perform();
24
24
  if (this.case) {
25
25
  const ownerForm = this.getOwnerForm();
26
+ // todo: id resolution!!!
26
27
  const caseElement = ownerForm.querySelector(`#${this.case}`);
27
28
  if(!caseElement){
28
29
  Fore.dispatch(this, 'error', { message: `fx-case id not found: ${this.case}` });
package/src/fore.js CHANGED
@@ -18,228 +18,6 @@ export class Fore {
18
18
 
19
19
  static TYPE_DEFAULT = 'xs:string';
20
20
 
21
- /**
22
- * recursively walks along a template instance that contains all nodes relevant for editing and
23
- * applying all nodes being present in partial instance onto it.
24
- *
25
- * @param start
26
- * @param partial
27
- * @returns {*}
28
- * @private
29
- */
30
- static combine(start, partial, foreElement,expr){
31
- if(!start) return;
32
-
33
- const appended = false;
34
- // ### get the path of the current element
35
- let path = evaluateXPath('path()',start,foreElement)[0];
36
- if(expr){
37
- path = expr;
38
- }
39
- // const attrMap = new Map();
40
- console.log('########process path', XPathUtil.shortenPath(path));
41
- const predicates = Fore.buildPredicates(start);
42
- // console.log('########process search', path);
43
- // ### search the path in the partial instance
44
- const toMerge = evaluateXPathToFirstNode( path,partial,foreElement);
45
- if(expr){
46
- console.log('skipped one - new toMerge', toMerge);
47
- }
48
- // console.log('tomerge node', toMerge);
49
- // if(toMerge.length === 1){}
50
- if(toMerge){
51
- // console.log('merging nodes', toMerge);
52
- const mergeAttrs = Fore.buildPredicates(toMerge);
53
- if(predicates === mergeAttrs) {
54
-
55
-
56
- // console.log('####### attr maps', attrMap, toMergeAttrMap);
57
- // console.log('########process merge attrs', mergeAttrs);
58
- if(start.getAttribute('type') !== toMerge.getAttribute('type') ){
59
- console.log('###### element type attr not matching', start, toMerge);
60
- const nextSibling = start.nextElementSibling;
61
- if(nextSibling && nextSibling.nodeName === start.nodeName){
62
- console.log('nextSibling', nextSibling, XPathUtil.shortenPath(path));
63
- console.log('start', start, XPathUtil.shortenPath(path));
64
- Fore.combine(start,partial,foreElement,path);
65
- }
66
- }
67
-
68
- // ### iterate the attributes of the template node
69
- // if(attrMap === toMergeAttrMap){
70
- // if(start.attributes){
71
- Array.from(start.attributes).forEach(attr => {
72
- // ### if the template attribute has a matching attribute in partial...
73
- if (toMerge.hasAttribute(attr.nodeName)) {
74
- if (attr.nodeName !== 'xmlns') {
75
- // console.log('overwrite attr', attr);
76
- const toMergeAttr = toMerge.getAttribute(attr.nodeName);
77
- // if (attr.nodeValue !== toMergeAttr.nodeValue) {
78
- // ### apply the attribute value from partial to template
79
- if(toMergeAttr){
80
- start.setAttribute(attr.nodeName, toMergeAttr)
81
- }
82
- // }
83
- }
84
- }
85
- });
86
- // }
87
- }else{
88
- console.log('###### element in template but not in partial',start);
89
- const nextSibling = start.nextElementSibling;
90
- if(nextSibling && nextSibling.nodeName === start.nodeName){
91
- Fore.combine(nextSibling,partial,foreElement,path);
92
- }
93
- }
94
- // ### if we don't have children we still might have text
95
- if(toMerge.children.length === 0){
96
- const toMergeText = toMerge.textContent;
97
- if(toMergeText){
98
- start.textContent = toMergeText;
99
- }
100
- }
101
-
102
- // ### if the template node does not have children but the partial has then copy them over
103
- if(start.children.length === 0 && toMerge.children.length !== 0){
104
- const mergeChildren = Array.from(toMerge.children);
105
- mergeChildren.forEach(child => {
106
- start.append(child);
107
- });
108
- }
109
- }
110
-
111
- // ### recurse
112
- if(start.children){
113
- Array.from(start.children).forEach(element => {
114
- /*
115
- console.log('stepping into element', element);
116
- if(element.getAttribute('type') !== toMerge.getAttribute('type')){
117
- // console.log('###### element in template but not in partial');
118
- // const nextSibling = start.nextElementSibling;
119
- const nextSibling = element.nextElementSibling;
120
- if(nextSibling && nextSibling.nodeName === toMerge.nodeName){
121
- console.log('nextSibling', nextSibling, XPathUtil.shortenPath(path));
122
- Fore.combine(nextSibling,partial,foreElement,path);
123
- }
124
- }
125
- */
126
- return Fore.combine(element, partial,foreElement,null);
127
-
128
-
129
- });
130
- }
131
- return start;
132
- }
133
- /*
134
- static combine(start, partial, foreElement,expr){
135
- if(!start) return;
136
- // ### get the path of the current element
137
- let path = evaluateXPath('path()',start,foreElement)[0];
138
- if(expr){
139
- path = expr;
140
- }
141
- // const attrMap = new Map();
142
- console.log('########process path', XPathUtil.shortenPath(path));
143
- const predicates = Fore.buildPredicates(start);
144
- /!*
145
- if(predicates){
146
- path = path.substring(1, path.lastIndexOf('['));
147
- }
148
- path += Fore.buildPredicates(start);
149
- *!/
150
- // console.log('########process search', path);
151
- // ### search the path in the partial instance
152
- const toMerge = evaluateXPathToFirstNode( path,partial,foreElement);
153
-
154
- // console.log('tomerge node', toMerge);
155
- // if(toMerge.length === 1){}
156
- if(toMerge){
157
- // console.log('merging nodes', toMerge);
158
- const mergeAttrs = Fore.buildPredicates(toMerge);
159
- if(predicates === mergeAttrs) {
160
-
161
-
162
- // console.log('####### attr maps', attrMap, toMergeAttrMap);
163
- // console.log('########process merge attrs', mergeAttrs);
164
- /!*
165
- if(toMerge.getAttribute('type') !== start.getAttribute('type')){
166
- // console.log('###### element in template but not in partial');
167
- // const nextSibling = start.nextElementSibling;
168
- const nextSibling = start.nextElementSibling;
169
- if(nextSibling && nextSibling.nodeName === start.nodeName){
170
- console.log('nextSibling', nextSibling, XPathUtil.shortenPath(path));
171
- Fore.combine(nextSibling,partial,foreElement,path);
172
- }
173
- }
174
- *!/
175
-
176
- // ### iterate the attributes of the template node
177
- // if(attrMap === toMergeAttrMap){
178
- // if(start.attributes){
179
- Array.from(start.attributes).forEach(attr => {
180
- // ### if the template attribute has a matching attribute in partial...
181
- if (toMerge.hasAttribute(attr.nodeName)) {
182
- if (attr.nodeName !== 'xmlns') {
183
- // console.log('overwrite attr', attr);
184
- const toMergeAttr = toMerge.getAttribute(attr.nodeName);
185
- // if (attr.nodeValue !== toMergeAttr.nodeValue) {
186
- // ### apply the attribute value from partial to template
187
- if(toMergeAttr){
188
- start.setAttribute(attr.nodeName, toMergeAttr)
189
- }
190
- // }
191
- }
192
- }
193
- });
194
- // }
195
- }else{
196
- console.log('###### element in template but not in partial',start);
197
- const nextSibling = start.nextElementSibling;
198
- if(nextSibling && nextSibling.nodeName === start.nodeName){
199
- Fore.combine(nextSibling,partial,foreElement,path);
200
- }
201
- }
202
- // ### if we don't have children we still might have text
203
- if(toMerge.children.length === 0){
204
- const toMergeText = toMerge.textContent;
205
- if(toMergeText){
206
- start.textContent = toMergeText;
207
- }
208
- }
209
-
210
- // ### if the template node does not have children but the partial has then copy them over
211
- if(start.children.length === 0 && toMerge.children.length !== 0){
212
- const mergeChildren = Array.from(toMerge.children);
213
- mergeChildren.forEach(child => {
214
- start.append(child);
215
- });
216
- }
217
- }
218
-
219
- // ### recurse
220
- if(start.children){
221
- Array.from(start.children).forEach(element => {
222
- /!*
223
- console.log('stepping into element', element);
224
- if(element.getAttribute('type') !== toMerge.getAttribute('type')){
225
- // console.log('###### element in template but not in partial');
226
- // const nextSibling = start.nextElementSibling;
227
- const nextSibling = element.nextElementSibling;
228
- if(nextSibling && nextSibling.nodeName === toMerge.nodeName){
229
- console.log('nextSibling', nextSibling, XPathUtil.shortenPath(path));
230
- Fore.combine(nextSibling,partial,foreElement,path);
231
- }
232
- }
233
- *!/
234
- return Fore.combine(element, partial,foreElement);
235
-
236
-
237
- });
238
- }
239
- return start;
240
- }
241
- */
242
-
243
21
  static buildPredicates(node){
244
22
  let attrPredicate='';
245
23
  Array.from(node.attributes).forEach(attr =>{
package/src/fx-fore.js CHANGED
@@ -768,30 +768,31 @@ export class FxFore extends HTMLElement {
768
768
  */
769
769
  async _lazyCreateInstance() {
770
770
  const model = this.querySelector('fx-model');
771
- // Inherit shared models from the parent component
772
771
 
772
+ // ##### lazy creation should NOT take place if there's a parent Fore using shared instances
773
773
  const parentFore = this.parentNode.closest('fx-fore');
774
- if (parentFore) {
775
- const sharedInstances = Array.from(parentFore.getModel().querySelectorAll('fx-instance')).filter(instance => instance.hasAttribute('shared'));
776
- for(const instance of sharedInstances) {
777
- this.getModel().instances.push(instance);
778
- }
779
- this.getModel().updateModel();
780
- }
781
-
782
-
783
- if (model.instances.length === 0) {
784
- // console.log('### lazy creation of instance');
785
- const generatedInstance = document.createElement('fx-instance');
786
- model.appendChild(generatedInstance);
774
+ if(parentFore){
775
+ const shared = parentFore.getModel().instances.filter(shared => shared.hasAttribute('shared'));
776
+ if(shared.length !==0) return;
777
+ }
787
778
 
788
- const generated = document.implementation.createDocument(null, 'data', null);
789
- // const newData = this._generateInstance(this, generated.firstElementChild);
790
- this._generateInstance(this, generated.firstElementChild);
791
- generatedInstance.instanceData = generated;
792
- model.instances.push(generatedInstance);
793
- // console.log('generatedInstance ', this.getModel().getDefaultInstanceData());
794
- 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);
795
796
  }
796
797
  }
797
798
 
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) {
@@ -458,7 +460,16 @@ export class FxModel extends HTMLElement {
458
460
  // console.log('instances array ',Array.from(this.instances));
459
461
 
460
462
  const instArray = Array.from(this.instances);
461
- 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
+ }
462
473
  if(!found){
463
474
  // return this.getDefaultInstance(); // if id is not found always defaults to first in doc order
464
475
  Fore.dispatch(this, 'error', {
@@ -18,7 +18,10 @@ class FxSwitch extends FxContainer {
18
18
  constructor() {
19
19
  super();
20
20
  this.formerCase = {};
21
+ this.selectedCase = null;
22
+ this.cases = null;
21
23
  }
24
+
22
25
  connectedCallback() {
23
26
  if (super.connectedCallback) {
24
27
  super.connectedCallback();
@@ -37,63 +40,83 @@ class FxSwitch extends FxContainer {
37
40
  </style>
38
41
  ${html}
39
42
  `;
43
+ this.cases = [];
44
+ this.formerCase=null;
40
45
  }
41
46
 
42
47
  async refresh(force) {
43
48
  super.refresh();
44
49
  // console.log('refresh on switch ');
45
- const cases = this.querySelectorAll(':scope > fx-case');
46
- let selectedCase = cases[0]; // first is always default
50
+ if(this.cases.length === 0){
51
+ this.cases = Array.from(this.querySelectorAll(':scope > fx-case'));
52
+ }
53
+
47
54
  if (this.isBound()) {
48
- Array.from(cases).forEach(caseElem => {
49
- const name = caseElem.getAttribute('name');
50
- if (name === this.modelItem?.value) {
51
- Fore.dispatch(caseElem,'select',{});
52
- caseElem.classList.add('selected-case');
53
- selectedCase = caseElem;
54
- } else {
55
- if(caseElem.classList.contains('selected-case')){
56
- Fore.dispatch(caseElem,'deselect',{});
57
- }
58
- caseElem.classList.remove('selected-case');
59
- }
60
- });
61
- } else {
62
- selectedCase = this.querySelector(':scope > .selected-case');
63
- // if none is selected select the first as default
64
- if (!selectedCase) {
65
- selectedCase = cases[0]; // if nothing is selected use the first case
66
- Fore.dispatch(selectedCase,'select',{});
67
- selectedCase.classList.add('selected-case');
68
- }
55
+ this._handleBoundSwitch();
69
56
  }
70
- if(this.formerCase !== selectedCase){
71
- const visited = selectedCase.querySelectorAll('.visited');
72
- Array.from(visited).forEach(v =>{
73
- v.classList.remove('visited');
74
- });
57
+ if(!this.selectedCase){
58
+ this.selectedCase = this.cases[0]; // first is always default
59
+ this.toggle(this.selectedCase);
75
60
  }
76
61
 
77
- Fore.refreshChildren(selectedCase,force);
78
- this.formerCase = selectedCase;
62
+ Fore.refreshChildren(this.selectedCase,force);
79
63
  }
80
64
 
65
+ _dispatchEvents(){
66
+ if(this.formerCase && this.formerCase !== this.selectedCase){
67
+ Fore.dispatch(this.formerCase,'deselect',{});
68
+ }
69
+ if(this.selectedCase.classList.contains('selected-case')){
70
+ Fore.dispatch(this.selectedCase,'select',{});
71
+ }
72
+ }
73
+
74
+ _resetVisited(){
75
+ const visited = this.selectedCase.querySelectorAll('.visited');
76
+ Array.from(visited).forEach(v =>{
77
+ v.classList.remove('visited');
78
+ });
79
+ }
80
+
81
+ /**
82
+ * handles switches being bound. If modelItem value matches the 'name' attribute that case will be toggled.
83
+ * @private
84
+ */
85
+ _handleBoundSwitch() {
86
+ Array.from(this.cases).forEach(caseElem => {
87
+ const name = caseElem.getAttribute('name');
88
+ if (name === this.modelItem?.value) {
89
+ this.toggle(caseElem);
90
+ }
91
+ });
92
+ }
93
+
94
+ /**
95
+ * Activates a fx-case element by switching CSS classes.
96
+ * Dispatches 'select' and 'deselect' events as appropriate.
97
+ *
98
+ * @param caseElement the fx-case element to activate
99
+ */
81
100
  toggle(caseElement) {
82
- const cases = this.querySelectorAll('fx-case');
83
- Array.from(cases).forEach(c => {
84
- if (caseElement === c) {
85
- // eslint-disable-next-line no-param-reassign
101
+ this.formerCase = this.selectedCase;
102
+ this.selectedCase = caseElement;
103
+ Array.from(this.cases).forEach(c => {
104
+ if (c === this.selectedCase) {
105
+ c.classList.remove('deselected-case');
86
106
  c.classList.add('selected-case');
87
- Fore.dispatch(c,'select',{});
88
- this.refresh();
107
+ c.inert = false;
89
108
  } else {
90
- // eslint-disable-next-line no-param-reassign
91
- if(c.classList.contains('selected-case')){
92
- Fore.dispatch(c,'deselect',{});
93
- }
94
109
  c.classList.remove('selected-case');
110
+ c.classList.add('deselected-case');
111
+ c.inert = true;
112
+ this._resetVisited();
95
113
  }
96
114
  });
115
+
116
+ if(this.selectedCase !== caseElement){
117
+ this.selectedCase = caseElement;
118
+ }
119
+ this._dispatchEvents();
97
120
  }
98
121
  }
99
122
 
@@ -982,7 +982,7 @@ const instance = (dynamicContext, string) => {
982
982
  bubbles: true,
983
983
  detail: {
984
984
  origin: 'functions',
985
- message: `Function not found '${localName}'`,
985
+ message: `Instance not found '${localName}'`,
986
986
  level:'Error'
987
987
  },
988
988
  }));
@@ -995,28 +995,6 @@ const instance = (dynamicContext, string) => {
995
995
  return null;
996
996
  }
997
997
  return context;
998
-
999
- /*
1000
- const inst = string
1001
- ? formElement.getModel().getInstance(string)
1002
- : formElement.getModel().getDefaultInstance();
1003
- */
1004
-
1005
- /*
1006
- const inst = string
1007
- ? resolveId(string, formElement, 'fx-instance')
1008
- : formElement.querySelector(`fx-instance`);
1009
-
1010
- if (lookup) {
1011
- const context = lookup.getDefaultContext();
1012
- if (!context) {
1013
- debugger;
1014
- return null;
1015
- }
1016
- return context;
1017
- }
1018
- return null;
1019
- */
1020
998
  };
1021
999
 
1022
1000
  registerCustomXPathFunction(