@jinntec/fore 2.6.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 (53) hide show
  1. package/dist/fore-dev.js +4470 -2643
  2. package/dist/fore.js +4415 -2620
  3. package/index.js +2 -0
  4. package/package.json +10 -4
  5. package/resources/fore.css +2 -6
  6. package/src/DependencyNotifyingDomFacade.js +27 -21
  7. package/src/ForeElementMixin.js +282 -277
  8. package/src/actions/abstract-action.js +7 -12
  9. package/src/actions/fx-append.js +23 -2
  10. package/src/actions/fx-call.js +2 -2
  11. package/src/actions/fx-delete.js +54 -29
  12. package/src/actions/fx-insert.js +23 -15
  13. package/src/actions/fx-refresh.js +15 -5
  14. package/src/actions/fx-replace.js +18 -3
  15. package/src/actions/fx-reset.js +6 -0
  16. package/src/actions/fx-send.js +10 -7
  17. package/src/actions/fx-setattribute.js +12 -0
  18. package/src/actions/fx-setfocus.js +11 -8
  19. package/src/actions/fx-setvalue.js +93 -93
  20. package/src/actions/fx-toggle.js +1 -1
  21. package/src/extract-predicate-deps.js +57 -0
  22. package/src/extractPredicateDependencies.js +36 -0
  23. package/src/fore.js +41 -16
  24. package/src/fx-bind.js +128 -23
  25. package/src/fx-connection.js +24 -7
  26. package/src/fx-fore.js +506 -259
  27. package/src/fx-instance.js +9 -11
  28. package/src/fx-model.js +154 -65
  29. package/src/fx-submission.js +19 -30
  30. package/src/fx-var.js +5 -0
  31. package/src/getInScopeContext.js +7 -8
  32. package/src/modelitem.js +247 -112
  33. package/src/tools/fx-action-log.js +21 -19
  34. package/src/tools/fx-log-settings.js +4 -2
  35. package/src/ui/TemplateExpression.js +12 -0
  36. package/src/ui/UIElement.js +125 -10
  37. package/src/ui/abstract-control.js +5 -0
  38. package/src/ui/fx-case.js +15 -3
  39. package/src/ui/fx-container.js +5 -0
  40. package/src/ui/fx-control-menu.js +23 -14
  41. package/src/ui/fx-control.js +55 -15
  42. package/src/ui/fx-items.js +10 -4
  43. package/src/ui/fx-repeat-attributes.js +111 -35
  44. package/src/ui/fx-repeat.js +332 -85
  45. package/src/ui/fx-repeat.updated.js +821 -0
  46. package/src/ui/fx-repeatitem.js +23 -20
  47. package/src/ui/fx-switch.js +5 -3
  48. package/src/ui/fx-upload.js +36 -40
  49. package/src/ui/repeat-base.js +532 -0
  50. package/src/withDraggability.js +8 -4
  51. package/src/xpath-evaluation.js +26 -8
  52. package/src/xpath-path.js +79 -0
  53. package/src/xpath-util.js +357 -289
@@ -1,152 +1,150 @@
1
1
  import { XPathUtil } from './xpath-util.js';
2
2
  import { FxModel } from './fx-model.js';
3
3
  import {
4
- evaluateXPath,
5
- evaluateXPathToFirstNode,
6
- evaluateXPathToString,
4
+ evaluateXPath,
5
+ evaluateXPathToFirstNode,
6
+ evaluateXPathToString,
7
7
  } from './xpath-evaluation.js';
8
8
  import getInScopeContext from './getInScopeContext.js';
9
9
  import { Fore } from './fore.js';
10
10
  import DependentXPathQueries from './DependentXPathQueries.js';
11
+ import { getPath } from './xpath-path.js';
11
12
 
12
13
  /**
13
14
  * Mixin containing all general functions that are shared by all Fore element classes.
14
15
  * @extends {HTMLElement}
15
16
  */
16
17
  export default class ForeElementMixin extends HTMLElement {
17
- static get properties() {
18
- return {
19
- /**
20
- * context object for evaluation
21
- */
22
- context: {
23
- type: Object,
24
- },
25
- /**
26
- * the model of this element
27
- */
28
- model: {
29
- type: Object,
30
- },
31
- /**
32
- * The modelitem object associated to the bound node holding the evaluated state.
33
- */
34
- modelItem: {
35
- type: Object,
36
- },
37
- /**
38
- * the node(s) bound by this element
39
- */
40
- nodeset: {
41
- type: Object,
42
- },
43
- /**
44
- * XPath binding expression pointing to bound node
45
- */
46
- ref: {
47
- type: String,
48
- },
49
- inScopeVariables: {
50
- type: Map,
51
- },
52
- };
53
- }
54
-
55
- constructor() {
56
- super();
57
- this.context = null;
58
- this.model = null;
59
- this.modelItem = null;
60
- this.ref = this.hasAttribute('ref') ? this.getAttribute('ref') : '';
61
- /**
62
- * @type {Map<string, import('./fx-var.js').FxVariable>}
63
- */
64
- this.inScopeVariables = new Map();
65
-
66
- this.dependencies = new DependentXPathQueries();
67
- }
68
-
69
- connectedCallback() {
70
- if (this.parentElement) {
71
- this.dependencies.setParentDependencies(
72
- this.parentElement?.closest('[ref]')?.dependencies,
73
- );
74
- }
75
- }
18
+ static get properties() {
19
+ return {
20
+ /**
21
+ * context object for evaluation
22
+ */
23
+ context: {
24
+ type: Object,
25
+ },
26
+ /**
27
+ * the model of this element
28
+ */
29
+ model: {
30
+ type: Object,
31
+ },
32
+ /**
33
+ * The modelitem object associated to the bound node holding the evaluated state.
34
+ */
35
+ modelItem: {
36
+ type: Object,
37
+ },
38
+ /**
39
+ * the node(s) bound by this element
40
+ */
41
+ nodeset: {
42
+ type: Object,
43
+ },
44
+ /**
45
+ * XPath binding expression pointing to bound node
46
+ */
47
+ ref: {
48
+ type: String,
49
+ },
50
+ inScopeVariables: {
51
+ type: Map,
52
+ },
53
+ };
54
+ }
76
55
 
56
+ constructor() {
57
+ super();
58
+ this.context = null;
59
+ this.model = null;
60
+ this.modelItem = null;
61
+ this.ref = this.hasAttribute('ref') ? this.getAttribute('ref') : '';
77
62
  /**
78
- * @returns {import('./fx-model.js').FxModel}
63
+ * @type {Map<string, import('./fx-var.js').FxVariable>}
79
64
  */
80
- getModel() {
81
- // console.log('getModel this ', this);
82
- if (this.model) {
83
- return this.model;
84
- }
85
- // const ownerForm = this.closest('fx-fore');
86
- // const ownerForm = this.getOwnerForm(this);
87
- const ownerForm = this.getOwnerForm();
88
- return ownerForm.querySelector('fx-model');
65
+ this.inScopeVariables = new Map();
66
+
67
+ this.dependencies = new DependentXPathQueries();
68
+ this.ownerForm = null;
69
+ }
70
+
71
+ connectedCallback() {
72
+ if (this.parentElement) {
73
+ this.dependencies.setParentDependencies(this.parentElement?.closest('[ref]')?.dependencies);
89
74
  }
90
75
 
91
- /**
92
- *
93
- * @returns {import('./fx-fore.js').FxFore} The fx-fore element associated with this form node
94
- */
95
- getOwnerForm() {
96
- let currentElement = this;
97
- while (currentElement && currentElement.parentNode) {
98
- // console.log('current ', currentElement);
76
+ // The fx-model linked to here won't ever change
77
+ this.model = this.getModel();
78
+ this.ownerForm = this.getOwnerForm();
79
+ }
99
80
 
100
- if (currentElement.nodeName.toUpperCase() === 'FX-FORE') {
101
- return currentElement;
102
- }
81
+ /**
82
+ * @returns {import('./fx-model.js').FxModel}
83
+ */
84
+ getModel() {
85
+ // console.log('getModel this ', this);
86
+ if (this.model) {
87
+ return this.model;
88
+ }
89
+ // const ownerForm = this.closest('fx-fore');
90
+ // const ownerForm = this.getOwnerForm(this);
91
+ const ownerForm = this.getOwnerForm();
92
+ return ownerForm.querySelector('fx-model');
93
+ }
103
94
 
104
- if (currentElement.parentNode instanceof DocumentFragment) {
105
- currentElement = currentElement.parentNode.host;
106
- } else {
107
- currentElement = currentElement.parentNode;
108
- }
109
- }
95
+ /**
96
+ *
97
+ * @returns {import('./fx-fore.js').FxFore} The fx-fore element associated with this form node
98
+ */
99
+ getOwnerForm() {
100
+ if (this.ownerForm) {
101
+ return this.ownerForm;
102
+ }
103
+ let currentElement = this;
104
+ while (currentElement && currentElement.parentNode) {
105
+ // console.log('current ', currentElement);
106
+ if (currentElement.nodeName.toUpperCase() === 'FX-FORE') {
110
107
  return currentElement;
108
+ }
109
+
110
+ if (currentElement.parentNode instanceof DocumentFragment) {
111
+ currentElement = currentElement.parentNode.host;
112
+ } else {
113
+ currentElement = currentElement.parentNode;
114
+ }
111
115
  }
116
+ return null;
117
+ }
112
118
 
113
- /**
114
- * evaluation of fx-bind and UiElements differ in details so that each class needs it's own implementation.
115
- */
116
- evalInContext() {
117
- this.dependencies.resetDependencies();
118
- // const inscopeContext = this.getInScopeContext();
119
- const model = this.getModel();
120
- if (!model) {
121
- return;
122
- }
123
- let inscopeContext;
124
- if (this.hasAttribute('context')) {
125
- inscopeContext = getInScopeContext(
126
- this.getAttributeNode('context') || this,
127
- this.context,
128
- );
129
- }
130
- if (this.hasAttribute('ref')) {
131
- inscopeContext = getInScopeContext(
132
- this.getAttributeNode('ref') || this,
133
- this.ref,
134
- );
135
- this.dependencies.addXPath(this.ref);
136
- }
137
- if (!inscopeContext && this.getModel().instances.length !== 0) {
138
- // ### always fall back to default context with there's neither a 'context' or 'ref' present
139
- inscopeContext = this.getModel()
140
- .getDefaultInstance()
141
- .getDefaultContext();
142
- // console.warn('no in scopeContext for ', this);
143
- // console.warn('using default context ', this);
144
- // return;
145
- }
146
- if (this.ref === '') {
147
- this.nodeset = inscopeContext;
148
- } else if (Array.isArray(inscopeContext)) {
149
- /*
119
+ /**
120
+ * evaluation of fx-bind and UiElements differ in details so that each class needs it's own implementation.
121
+ */
122
+ evalInContext() {
123
+ this.dependencies.resetDependencies();
124
+ // const inscopeContext = this.getInScopeContext();
125
+ const model = this.getModel();
126
+ if (!model) {
127
+ return;
128
+ }
129
+ let inscopeContext;
130
+ if (this.hasAttribute('context')) {
131
+ inscopeContext = getInScopeContext(this.getAttributeNode('context') || this, this.context);
132
+ }
133
+ if (this.hasAttribute('ref')) {
134
+ inscopeContext = getInScopeContext(this.getAttributeNode('ref') || this, this.ref);
135
+ this.dependencies.addXPath(this.ref);
136
+ }
137
+ if (!inscopeContext && this.getModel().instances.length !== 0) {
138
+ // ### always fall back to default context with there's neither a 'context' or 'ref' present
139
+ inscopeContext = this.getModel().getDefaultInstance().getDefaultContext();
140
+ // console.warn('no in scopeContext for ', this);
141
+ // console.warn('using default context ', this);
142
+ // return;
143
+ }
144
+ if (this.ref === '') {
145
+ this.nodeset = inscopeContext;
146
+ } else if (Array.isArray(inscopeContext)) {
147
+ /*
150
148
  inscopeContext.forEach(n => {
151
149
  if (XPathUtil.isSelfReference(this.ref)) {
152
150
  this.nodeset = inscopeContext;
@@ -157,177 +155,184 @@ export default class ForeElementMixin extends HTMLElement {
157
155
  }
158
156
  });
159
157
  */
160
- // this.nodeset = evaluateXPathToFirstNode(this.ref, inscopeContext[0], this);
161
- this.nodeset = evaluateXPath(this.ref, inscopeContext[0], this);
162
- } else {
163
- // this.nodeset = fx.evaluateXPathToFirstNode(this.ref, inscopeContext, null, {namespaceResolver: this.namespaceResolver});
164
- if (!inscopeContext) return;
165
- const { nodeType } = inscopeContext;
166
- if (nodeType && !XPathUtil.isAbsolutePath(this.ref)) {
167
- this.nodeset = evaluateXPathToFirstNode(
168
- this.ref,
169
- inscopeContext,
170
- this,
171
- );
172
- } else {
173
- [this.nodeset] = evaluateXPath(this.ref, inscopeContext, this);
174
- }
175
- }
176
- // console.log('UiElement evaluated to nodeset: ', this.nodeset);
158
+ // this.nodeset = evaluateXPathToFirstNode(this.ref, inscopeContext[0], this);
159
+ this.nodeset = evaluateXPath(this.ref, inscopeContext[0], this);
160
+ } else {
161
+ // this.nodeset = fx.evaluateXPathToFirstNode(this.ref, inscopeContext, null, {namespaceResolver: this.namespaceResolver});
162
+ if (!inscopeContext) return;
163
+ const { nodeType } = inscopeContext;
164
+ if (nodeType && !XPathUtil.isAbsolutePath(this.ref)) {
165
+ this.nodeset = evaluateXPathToFirstNode(this.ref, inscopeContext, this);
166
+ } else {
167
+ [this.nodeset] = evaluateXPath(this.ref, inscopeContext, this);
168
+ }
177
169
  }
170
+ // console.log('UiElement evaluated to nodeset: ', this.nodeset);
171
+ }
178
172
 
179
- /**
180
- * resolves template expressions for a single attribute
181
- * @param {string} expr an attribute value containing curly brackets containing XPath expressions to evaluate
182
- * @param {Node} node the attribute node used for scoped resolution
183
- * @returns {string}
184
- * @protected
185
- */
186
- evaluateAttributeTemplateExpression(expr, node) {
187
- const matches = expr.match(/{[^}]*}/g);
188
- if (matches) {
189
- matches.forEach((match) => {
190
- // console.log('match ', match);
191
- const naked = match.substring(1, match.length - 1);
192
- const inscope = getInScopeContext(node, naked);
193
- const result = evaluateXPathToString(naked, inscope, this);
194
- const replaced = expr.replaceAll(match, result);
195
- // console.log('replacing ', expr, ' with ', replaced);
196
- expr = replaced;
197
- });
198
- }
199
- return expr;
173
+ /**
174
+ * resolves template expressions for a single attribute
175
+ * @param {string} expr an attribute value containing curly brackets containing XPath expressions to evaluate
176
+ * @param {Node} node the attribute node used for scoped resolution
177
+ * @returns {string}
178
+ * @protected
179
+ */
180
+ evaluateAttributeTemplateExpression(expr, node) {
181
+ const matches = expr.match(/{[^}]*}/g);
182
+ if (matches) {
183
+ matches.forEach(match => {
184
+ // console.log('match ', match);
185
+ const naked = match.substring(1, match.length - 1);
186
+ const inscope = getInScopeContext(node, naked);
187
+ const result = evaluateXPathToString(naked, inscope, this);
188
+ const replaced = expr.replaceAll(match, result);
189
+ // console.log('replacing ', expr, ' with ', replaced);
190
+ expr = replaced;
191
+ });
200
192
  }
193
+ return expr;
194
+ }
195
+
196
+ isNotBound() {
197
+ return !this.hasAttribute('ref');
198
+ }
201
199
 
202
- isNotBound() {
203
- return !this.hasAttribute('ref');
200
+ isBound() {
201
+ return this.hasAttribute('ref');
202
+ }
203
+
204
+ getBindingExpr() {
205
+ if (this.hasAttribute('ref')) {
206
+ return this.getAttribute('ref');
207
+ }
208
+ // try to get closest parent bind
209
+ const parent = XPathUtil.getClosest('[ref]', this.parentNode);
210
+ if (!parent) {
211
+ return 'instance()'; // the default instance
204
212
  }
213
+ return parent.getAttribute('ref');
214
+ }
205
215
 
206
- isBound() {
207
- return this.hasAttribute('ref');
216
+ /**
217
+ * @returns {import('./fx-instance.js').FxInstance}
218
+ */
219
+ getInstance() {
220
+ if (this.ref.startsWith('instance(')) {
221
+ const instId = XPathUtil.getInstanceId(this.ref);
222
+ return this.getModel().getInstance(instId);
208
223
  }
224
+ return this.getModel().getInstance('default');
225
+ }
209
226
 
210
- getBindingExpr() {
211
- if (this.hasAttribute('ref')) {
212
- return this.getAttribute('ref');
213
- }
214
- // try to get closest parent bind
215
- const parent = XPathUtil.getClosest('[ref]', this.parentNode);
216
- if (!parent) {
217
- return 'instance()'; // the default instance
218
- }
219
- return parent.getAttribute('ref');
227
+ _getParentBindingElement(start) {
228
+ if (start.parentNode.host) {
229
+ const { host } = start.parentNode;
230
+ if (host.hasAttribute('ref')) {
231
+ return host;
232
+ }
233
+ } else if (start.parentNode) {
234
+ if (start.parentNode.hasAttribute('ref')) {
235
+ return this.parentNode;
236
+ }
237
+ this._getParentBindingElement(this.parentNode);
220
238
  }
239
+ return null;
240
+ }
221
241
 
222
- /**
223
- * @returns {import('./fx-instance.js').FxInstance}
224
- */
225
- getInstance() {
226
- if (this.ref.startsWith('instance(')) {
227
- const instId = XPathUtil.getInstanceId(this.ref);
228
- return this.getModel().getInstance(instId);
229
- }
230
- return this.getModel().getInstance('default');
242
+ /**
243
+ * @returns {import('./modelitem.js').ModelItem}
244
+ */
245
+ getModelItem() {
246
+ if (!this.getModel()) return;
247
+
248
+ // First try to find by node reference
249
+ const mi = this.getModel().getModelItem(this.nodeset);
250
+ if (mi) {
251
+ this.modelItem = mi;
231
252
  }
232
253
 
233
- _getParentBindingElement(start) {
234
- if (start.parentNode.host) {
235
- const { host } = start.parentNode;
236
- if (host.hasAttribute('ref')) {
237
- return host;
238
- }
239
- } else if (start.parentNode) {
240
- if (start.parentNode.hasAttribute('ref')) {
241
- return this.parentNode;
242
- }
243
- this._getParentBindingElement(this.parentNode);
244
- }
245
- return null;
254
+ const repeated = XPathUtil.getClosest('fx-repeatitem', this);
255
+ let existed;
256
+ if (repeated) {
257
+ const { index } = repeated;
258
+ if (Array.isArray(this.nodeset)) {
259
+ existed = this.getModel().getModelItem(this.nodeset[index - 1]);
260
+ } else {
261
+ existed = this.getModel().getModelItem(this.nodeset);
262
+ }
263
+ } else {
264
+ existed = this.nodeset ? this.getModel().getModelItem(this.nodeset) : null;
246
265
  }
247
266
 
248
- /**
249
- * @returns {import('./modelitem.js').ModelItem}
250
- */
251
- getModelItem() {
252
- if (!this.getModel()) return;
253
- const mi = this.getModel().getModelItem(this.nodeset);
254
- if (mi) {
255
- this.modelItem = mi;
256
- }
267
+ // If we couldn't find by node reference, try to find by path
268
+ if (!existed && this.nodeset) {
269
+ // Get the path for the current nodeset
270
+ const instanceId = XPathUtil.resolveInstance(this, this.ref);
271
+ let targetNode =
272
+ this.nodeset.nodeType === Node.TEXT_NODE ? this.nodeset.parentNode : this.nodeset;
257
273
 
258
- const repeated = XPathUtil.getClosest('fx-repeatitem', this);
259
- let existed;
260
- if (repeated) {
261
- const { index } = repeated;
262
- if (Array.isArray(this.nodeset)) {
263
- existed = this.getModel().getModelItem(this.nodeset[index - 1]);
264
- } else {
265
- existed = this.getModel().getModelItem(this.nodeset);
266
- }
267
- } else {
268
- existed = this.nodeset
269
- ? this.getModel().getModelItem(this.nodeset)
270
- : null;
271
- }
274
+ if (targetNode?.nodeType) {
275
+ const path = getPath(targetNode, instanceId);
272
276
 
273
- if (!existed) {
274
- const lazyCreatedModelItem = FxModel.lazyCreateModelItem(
275
- this.getModel(),
276
- this.ref,
277
- this.nodeset,
278
- this,
279
- );
280
- this.modelItem = lazyCreatedModelItem;
281
- return lazyCreatedModelItem;
282
- }
283
- this.modelItem = existed;
284
-
285
- return existed;
286
- }
277
+ // Try to find a ModelItem with this path
278
+ existed = this.getModel().modelItems.find(item => item.path === path);
287
279
 
288
- /**
289
- * Returns the effective value for the element.
290
- * a: look for 'value' attribute and if present evaluate it and return the resulting value
291
- * b: look for textContent and return the value if present
292
- * c: return null
293
- * @returns {string}
294
- */
295
- getValue() {
296
- if (this.hasAttribute('value')) {
297
- const valAttr = this.getAttribute('value');
298
- try {
299
- const inscopeContext = getInScopeContext(this, valAttr);
300
- return evaluateXPathToString(
301
- valAttr,
302
- inscopeContext,
303
- this.getOwnerForm(),
304
- );
305
- } catch (error) {
306
- console.error(error);
307
- Fore.dispatch(this, 'error', { message: error });
308
- }
309
- }
310
- if (this.textContent) {
311
- return this.textContent;
280
+ if (existed) {
281
+ // Update the node reference in the existing ModelItem
282
+ existed.node = targetNode;
312
283
  }
313
- return null;
314
- }
315
-
316
- /**
317
- * @returns {Node}
318
- */
319
- getInScopeContext() {
320
- return getInScopeContext(
321
- this.getAttributeNode('ref') || this,
322
- this.ref,
284
+ }
285
+ if (!existed) {
286
+ const lazyCreatedModelItem = FxModel.lazyCreateModelItem(
287
+ this.getModel(),
288
+ this.ref,
289
+ this.nodeset,
290
+ this,
323
291
  );
292
+ this.modelItem = lazyCreatedModelItem;
293
+ return lazyCreatedModelItem;
294
+ }
324
295
  }
296
+ this.modelItem = existed;
325
297
 
326
- /**
327
- * Set variables in scope here
328
- * @param {Map} inScopeVariables
329
- */
330
- setInScopeVariables(inScopeVariables) {
331
- this.inScopeVariables = inScopeVariables;
298
+ return existed;
299
+ }
300
+ /**
301
+ * Returns the effective value for the element.
302
+ * a: look for 'value' attribute and if present evaluate it and return the resulting value
303
+ * b: look for textContent and return the value if present
304
+ * c: return null
305
+ * @returns {string}
306
+ */
307
+ getValue() {
308
+ if (this.hasAttribute('value')) {
309
+ const valAttr = this.getAttribute('value');
310
+ try {
311
+ const inscopeContext = getInScopeContext(this, valAttr);
312
+ return evaluateXPathToString(valAttr, inscopeContext, this.getOwnerForm());
313
+ } catch (error) {
314
+ console.error(error);
315
+ Fore.dispatch(this, 'error', { message: error });
316
+ }
332
317
  }
318
+ if (this.textContent) {
319
+ return this.textContent;
320
+ }
321
+ return null;
322
+ }
323
+
324
+ /**
325
+ * @returns {Node}
326
+ */
327
+ getInScopeContext() {
328
+ return getInScopeContext(this.getAttributeNode('ref') || this, this.ref);
329
+ }
330
+
331
+ /**
332
+ * Set variables in scope here
333
+ * @param {Map} inScopeVariables
334
+ */
335
+ setInScopeVariables(inScopeVariables) {
336
+ this.inScopeVariables = inScopeVariables;
337
+ }
333
338
  }
@@ -4,6 +4,7 @@ import getInScopeContext from '../getInScopeContext.js';
4
4
  import { Fore } from '../fore.js';
5
5
  import { FxFore } from '../fx-fore.js';
6
6
  import { XPathUtil } from '../xpath-util.js';
7
+ import { getDocPath } from '../xpath-path.js';
7
8
 
8
9
  /**
9
10
  * @param {number} howLong How long to wait, in ms
@@ -177,7 +178,7 @@ export class AbstractAction extends ForeElementMixin {
177
178
  }
178
179
  } else {
179
180
  this.targetElement = this.parentNode;
180
- if(!this.targetElement || this.targetElement.nodeType !== Node.ELEMENT_NODE) return;
181
+ if (!this.targetElement || this.targetElement.nodeType !== Node.ELEMENT_NODE) return;
181
182
  this.targetElement.addEventListener(this.event, e => this.execute(e), {
182
183
  capture: this.phase === 'capture',
183
184
  });
@@ -194,7 +195,7 @@ export class AbstractAction extends ForeElementMixin {
194
195
  await Fore.dispatch(this, 'error', {
195
196
  origin: this,
196
197
  message: 'Action execution failed',
197
- expr: XPathUtil.getDocPath(this),
198
+ expr: error,
198
199
  level: 'Error',
199
200
  });
200
201
  // Return false to indicate failure. Any loops must be canceled
@@ -218,15 +219,9 @@ export class AbstractAction extends ForeElementMixin {
218
219
  // console.log(this, this.event);
219
220
  if (this.event) {
220
221
  if (this.event === 'submit-done') {
221
- console.info(
222
- `%csubmit-done ${this.event} #${this?.parentNode?.id}`,
223
- 'background:lime; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
224
- );
222
+ console.info(`📌 ${this.event} #${this?.parentNode?.id}`);
225
223
  } else {
226
- console.info(
227
- `%cexecuting ${this.constructor.name} ${this.event}`,
228
- 'background:lime; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
229
- );
224
+ console.info(`📌 ${this.constructor.name} ${this.event}`);
230
225
  }
231
226
  } else {
232
227
  console.info(
@@ -406,7 +401,7 @@ export class AbstractAction extends ForeElementMixin {
406
401
  this.actionPerformed();
407
402
  if (FxFore.outermostHandler === this) {
408
403
  console.log(
409
- `%cfinalizing outermost Action on ${this.getOwnerForm().id}`,
404
+ `%cfinalizing outermost Action on ${this.getOwnerForm()?.id}`,
410
405
  'background:darkblue; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
411
406
  this,
412
407
  );
@@ -480,7 +475,7 @@ export class AbstractAction extends ForeElementMixin {
480
475
  // console.log('running update cycle for outermostHandler', this);
481
476
  model.recalculate();
482
477
  model.revalidate();
483
- this.getOwnerForm().refresh(true);
478
+ this.getOwnerForm().refresh(false);
484
479
  this.dispatchActionPerformed();
485
480
  } else if (this.needsUpdate) {
486
481
  // console.log('Update delayed!');