@jinntec/fore 2.5.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/fore-dev.js +36088 -9
  2. package/dist/fore.js +35918 -9
  3. package/index.js +3 -1
  4. package/package.json +10 -4
  5. package/resources/fore.css +30 -5
  6. package/src/DataObserver.js +181 -0
  7. package/src/DependencyNotifyingDomFacade.js +27 -21
  8. package/src/DependentXPathQueries.js +32 -0
  9. package/src/ForeElementMixin.js +60 -26
  10. package/src/actions/abstract-action.js +24 -29
  11. package/src/actions/fx-append.js +25 -2
  12. package/src/actions/fx-call.js +2 -2
  13. package/src/actions/fx-delete.js +58 -21
  14. package/src/actions/fx-hide.js +1 -1
  15. package/src/actions/fx-insert.js +62 -48
  16. package/src/actions/fx-load.js +7 -2
  17. package/src/actions/fx-refresh.js +15 -5
  18. package/src/actions/fx-replace.js +18 -3
  19. package/src/actions/fx-reset.js +6 -0
  20. package/src/actions/fx-send.js +10 -7
  21. package/src/actions/fx-setattribute.js +12 -0
  22. package/src/actions/fx-setfocus.js +11 -8
  23. package/src/actions/fx-setvalue.js +20 -2
  24. package/src/actions/fx-show.js +4 -2
  25. package/src/actions/fx-toggle.js +1 -1
  26. package/src/extract-predicate-deps.js +57 -0
  27. package/src/extractPredicateDependencies.js +36 -0
  28. package/src/fore.js +78 -36
  29. package/src/fx-bind.js +128 -23
  30. package/src/fx-connection.js +24 -7
  31. package/src/fx-fore.js +552 -306
  32. package/src/fx-instance.js +9 -11
  33. package/src/fx-model.js +154 -65
  34. package/src/fx-submission.js +45 -51
  35. package/src/fx-var.js +5 -0
  36. package/src/getInScopeContext.js +8 -8
  37. package/src/modelitem.js +218 -72
  38. package/src/tools/fx-action-log.js +21 -19
  39. package/src/tools/fx-log-settings.js +4 -2
  40. package/src/ui/TemplateExpression.js +12 -0
  41. package/src/ui/UIElement.js +206 -0
  42. package/src/ui/abstract-control.js +15 -7
  43. package/src/ui/fx-case.js +15 -3
  44. package/src/ui/fx-container.js +10 -3
  45. package/src/ui/fx-control-menu.js +207 -0
  46. package/src/ui/fx-control.js +116 -32
  47. package/src/ui/fx-dialog.js +2 -2
  48. package/src/ui/fx-group.js +14 -0
  49. package/src/ui/fx-items.js +10 -4
  50. package/src/ui/fx-repeat-attributes.js +111 -35
  51. package/src/ui/fx-repeat.js +364 -87
  52. package/src/ui/fx-repeat.updated.js +821 -0
  53. package/src/ui/fx-repeatitem.js +23 -20
  54. package/src/ui/fx-switch.js +5 -3
  55. package/src/ui/fx-upload.js +36 -40
  56. package/src/ui/repeat-base.js +532 -0
  57. package/src/withDraggability.js +8 -4
  58. package/src/xpath-evaluation.js +26 -8
  59. package/src/xpath-path.js +79 -0
  60. package/src/xpath-util.js +107 -11
  61. package/dist/fore-dev.js.map +0 -1
  62. package/dist/fore.js.map +0 -1
  63. package/src/ui/fx-select.js +0 -89
@@ -1,6 +1,7 @@
1
1
  import { Fore } from '../fore.js';
2
- import ForeElementMixin from '../ForeElementMixin.js';
2
+ // import ForeElementMixin from '../ForeElementMixin.js';
3
3
  import { withDraggability } from '../withDraggability.js';
4
+ import { UIElement } from './UIElement.js';
4
5
 
5
6
  /**
6
7
  * `fx-repeat`
@@ -9,9 +10,9 @@ import { withDraggability } from '../withDraggability.js';
9
10
  * @customElement
10
11
  * @demo demo/index.html
11
12
  *
12
- * @extends {ForeElementMixin}
13
+ * @extends {UIElement}
13
14
  */
14
- export class FxRepeatitem extends withDraggability(ForeElementMixin, true) {
15
+ export class FxRepeatitem extends withDraggability(UIElement, true) {
15
16
  static get properties() {
16
17
  return {
17
18
  ...super.properties,
@@ -32,6 +33,8 @@ export class FxRepeatitem extends withDraggability(ForeElementMixin, true) {
32
33
  this.attachShadow({ mode: 'open', delegatesFocus: true });
33
34
 
34
35
  this.dropTarget = null;
36
+ // TODO: rename to position?
37
+ this.index = -1;
35
38
  }
36
39
 
37
40
  connectedCallback() {
@@ -72,7 +75,7 @@ export class FxRepeatitem extends withDraggability(ForeElementMixin, true) {
72
75
  }
73
76
  */
74
77
 
75
- _dispatchIndexChange() {
78
+ async _dispatchIndexChange() {
76
79
  /**
77
80
  * @type {import('./fx-repeat.js').FxRepeat}
78
81
  */
@@ -81,31 +84,31 @@ export class FxRepeatitem extends withDraggability(ForeElementMixin, true) {
81
84
  // The index did not really change if it did not change :wink:
82
85
  return;
83
86
  }
84
- this.dispatchEvent(
87
+ await this.dispatchEvent(
85
88
  new CustomEvent('item-changed', {
86
89
  composed: false,
87
90
  bubbles: true,
88
91
  detail: { item: this, index: this.index },
89
92
  }),
90
93
  );
94
+
95
+ // Refresh after all of the listeners for that item-changed have had their turn to update!
96
+ this.getOwnerForm().refresh();
91
97
  }
92
98
 
93
- refresh(force) {
94
- this.modelItem = this.getModelItem();
95
- // ### register ourselves as boundControl
96
- if (!this.modelItem.boundControls.includes(this)) {
97
- this.modelItem.boundControls.push(this);
98
-
99
- if (this.modelItem && !this.modelItem.relevant) {
100
- this.removeAttribute('relevant');
101
- this.setAttribute('nonrelevant', '');
102
- } else {
103
- this.removeAttribute('nonrelevant');
104
- this.setAttribute('relevant', '');
105
- }
99
+ async refresh(force = false) {
100
+ // this.modelItem = this.getModelItem();
101
+ this.attachObserver();
102
+ // console.log('🔄 repeatitem modelitem', this.getModelItem());
103
+
104
+ if (this.modelItem && !this.modelItem.relevant) {
105
+ this.removeAttribute('relevant');
106
+ this.setAttribute('nonrelevant', '');
107
+ } else {
108
+ this.removeAttribute('nonrelevant');
109
+ this.setAttribute('relevant', '');
106
110
  }
107
- // Always recurse for these refreshes, especially when forced
108
- Fore.refreshChildren(this, force);
111
+ await Fore.refreshChildren(this, force);
109
112
  }
110
113
  }
111
114
 
@@ -48,7 +48,7 @@ class FxSwitch extends FxContainer {
48
48
 
49
49
  async refresh(force) {
50
50
  super.refresh(force);
51
- // console.log('refresh on switch ');
51
+ console.log('🔄 fx-switch refresh', force);
52
52
  if (this.cases.length === 0) {
53
53
  this.cases = Array.from(this.querySelectorAll(':scope > fx-case'));
54
54
  }
@@ -65,7 +65,7 @@ class FxSwitch extends FxContainer {
65
65
  }
66
66
 
67
67
  _dispatchEvents() {
68
- if(this.selectedCase === this.formerCase) return;
68
+ if (this.selectedCase === this.formerCase) return;
69
69
  if (this.formerCase && this.formerCase !== this.selectedCase) {
70
70
  Fore.dispatch(this.formerCase, 'deselect', {});
71
71
  }
@@ -75,7 +75,7 @@ class FxSwitch extends FxContainer {
75
75
  }
76
76
 
77
77
  _resetVisited() {
78
- if(this.visitedResetted) return;
78
+ if (this.visitedResetted) return;
79
79
 
80
80
  const visited = this.selectedCase.querySelectorAll('.visited');
81
81
  Array.from(visited).forEach(v => {
@@ -95,6 +95,8 @@ class FxSwitch extends FxContainer {
95
95
  this.toggle(caseElem);
96
96
  }
97
97
  });
98
+
99
+ this.attachObserver();
98
100
  }
99
101
 
100
102
  /**
@@ -18,7 +18,6 @@ const WIDGETCLASS = 'widget';
18
18
  * @customElement
19
19
  */
20
20
 
21
-
22
21
  export default class FxUpload extends XfAbstractControl {
23
22
  constructor() {
24
23
  super();
@@ -41,9 +40,8 @@ export default class FxUpload extends XfAbstractControl {
41
40
  };
42
41
  }
43
42
  connectedCallback() {
44
-
45
43
  this.updateEvent = 'change';
46
- this.accept = this.hasAttribute('accept') ? this.getAttribute('accept'):'';
44
+ this.accept = this.hasAttribute('accept') ? this.getAttribute('accept') : '';
47
45
  this.label = this.hasAttribute('label') ? this.getAttribute('label') : null;
48
46
  const style = `
49
47
  :host{
@@ -75,16 +73,16 @@ export default class FxUpload extends XfAbstractControl {
75
73
  // ### convenience marker event
76
74
  if (this.debounceDelay) {
77
75
  listenOn.addEventListener(
78
- this.updateEvent,
79
- debounce(
80
- this,
81
- () => {
82
- // console.log('eventlistener ', this.updateEvent);
83
- // console.info('handling Event:', event.type, listenOn);
84
- this._importUploadedContent();
85
- },
86
- this.debounceDelay,
87
- ),
76
+ this.updateEvent,
77
+ debounce(
78
+ this,
79
+ () => {
80
+ // console.log('eventlistener ', this.updateEvent);
81
+ // console.info('handling Event:', event.type, listenOn);
82
+ this._importUploadedContent();
83
+ },
84
+ this.debounceDelay,
85
+ ),
88
86
  );
89
87
  } else {
90
88
  listenOn.addEventListener(this.updateEvent, async event => {
@@ -94,31 +92,34 @@ export default class FxUpload extends XfAbstractControl {
94
92
  this.boundInitialized = false;
95
93
  this.fileNameExpr = this.getAttribute('filename');
96
94
  this.mimetypeExpr = this.getAttribute('mimetype');
97
-
98
95
  }
99
96
 
100
97
  async _importUploadedContent(event) {
101
- console.log('_importUploadedContent',event);
98
+ console.log('_importUploadedContent', event);
102
99
  const file = event.target.files[0];
103
100
 
104
101
  this.evalInContext();
105
102
  // update file ref
106
- const fileNode = evaluateXPathToFirstNode(this.fileNameExpr,this.nodeset,this.getOwnerForm());
107
- if(fileNode){
103
+ const fileNode = evaluateXPathToFirstNode(this.fileNameExpr, this.nodeset, this.getOwnerForm());
104
+ if (fileNode) {
108
105
  this.fileName = fileNode.nodeValue = file.name;
109
106
  }
110
107
  this.mimetype = file.type;
111
108
 
112
109
  // update mediatype
113
- const mimetypeNode = evaluateXPathToFirstNode(this.mimetypeExpr,this.nodeset, this.getOwnerForm());
114
- if(mimetypeNode){
110
+ const mimetypeNode = evaluateXPathToFirstNode(
111
+ this.mimetypeExpr,
112
+ this.nodeset,
113
+ this.getOwnerForm(),
114
+ );
115
+ if (mimetypeNode) {
115
116
  mimetypeNode.nodeValue = this.mimetype;
116
117
  }
117
118
 
118
119
  let content = await this._readFile(file);
119
120
  // const setval = this.shadowRoot.getElementById('setvalue');
120
- console.log('content',content);
121
- if(file.type.endsWith('xml')){
121
+ console.log('content', content);
122
+ if (file.type.endsWith('xml')) {
122
123
  const uploadedXML = new DOMParser().parseFromString(content, 'application/xml');
123
124
  content = uploadedXML.firstElementChild;
124
125
  }
@@ -132,30 +133,27 @@ export default class FxUpload extends XfAbstractControl {
132
133
  const reader = new FileReader();
133
134
 
134
135
  // Determine how to read the file based on MIME type
135
- const isTextFile = file.type.startsWith("text/");
136
- const readMethod = isTextFile ? "readAsText" : "readAsDataURL";
136
+ const isTextFile = file.type.startsWith('text/');
137
+ const readMethod = isTextFile ? 'readAsText' : 'readAsDataURL';
137
138
 
138
139
  reader.onload = () => {
139
140
  const result = reader.result;
140
141
  // If it's a binary file, return only the Base64 content without the MIME prefix
141
142
  if (!isTextFile) {
142
- const base64Content = result.split(",")[1]; // Remove MIME prefix
143
+ const base64Content = result.split(',')[1]; // Remove MIME prefix
143
144
  resolve(base64Content);
144
145
  } else {
145
146
  resolve(result); // Return plain text
146
147
  }
147
148
  };
148
149
 
149
- reader.onerror = () => reject(new Error("Error reading file"));
150
+ reader.onerror = () => reject(new Error('Error reading file'));
150
151
 
151
152
  // Start reading the file
152
153
  reader[readMethod](file);
153
154
  });
154
155
  }
155
156
 
156
-
157
-
158
-
159
157
  /**
160
158
  * updates the model with a new value by executing it's `<fx-setvalue>` action.
161
159
  *
@@ -165,15 +163,15 @@ export default class FxUpload extends XfAbstractControl {
165
163
  * @param val the new value to be set
166
164
  */
167
165
  setValue(val) {
168
- this.value=val;
166
+ this.value = val;
169
167
  const modelitem = this.getModelItem();
170
168
 
171
- if(this.mimetype.endsWith('xml')){
169
+ if (this.mimetype.endsWith('xml')) {
172
170
  this.nodeset.textContent = '';
173
- this.nodeset.append(document.importNode(val,true));
174
- }else{
171
+ this.nodeset.append(document.importNode(val, true));
172
+ } else {
175
173
  modelitem.value = val;
176
- if(this.mimetype.startsWith('text/')){
174
+ if (this.mimetype.startsWith('text/')) {
177
175
  const cdata = this.nodeset.ownerDocument.createCDATASection(val);
178
176
  this.nodeset.textContent = '';
179
177
  this.nodeset.append(cdata);
@@ -183,7 +181,6 @@ export default class FxUpload extends XfAbstractControl {
183
181
  }
184
182
  }
185
183
 
186
-
187
184
  if (this.getAttribute('class')) {
188
185
  this.classList.add('visited');
189
186
  } else {
@@ -198,16 +195,18 @@ export default class FxUpload extends XfAbstractControl {
198
195
  // const setval = this.shadowRoot.getElementById('setvalue');
199
196
  // setval.setValue(modelitem, val);
200
197
 
198
+ /* deprecated
201
199
  if (this.modelItem instanceof ModelItem && !this.modelItem?.boundControls.includes(this)) {
202
200
  this.modelItem.boundControls.push(this);
203
201
  }
202
+ */
204
203
  const model = this.getModel();
205
204
  Fore.dispatch(this, 'value-changed', {
206
205
  path: this.modelItem.path,
207
206
  value: this.modelItem.value,
208
- oldvalue: "",
209
- instanceId:this.modelItem.instanceId,
210
- foreId:this.getOwnerForm().id
207
+ oldvalue: '',
208
+ instanceId: this.modelItem.instanceId,
209
+ foreId: this.getOwnerForm().id,
211
210
  });
212
211
  this.getModel().updateModel();
213
212
  this.getOwnerForm().refresh(true);
@@ -215,7 +214,6 @@ export default class FxUpload extends XfAbstractControl {
215
214
  // console.log('data', this.getOwnerForm().getModel().getDefaultInstanceData());
216
215
  }
217
216
 
218
-
219
217
  renderHTML(ref) {
220
218
  return `
221
219
  ${this.label ? `${this.label}` : ''}
@@ -267,8 +265,6 @@ export default class FxUpload extends XfAbstractControl {
267
265
  Fore.refreshChildren(this, force);
268
266
  }
269
267
 
270
-
271
-
272
268
  evalLabel(optionLabel, node, newEntry) {
273
269
  const labelExpr = optionLabel.substring(1, optionLabel.length - 1);
274
270
  if (!labelExpr) return;