@jinntec/fore 1.5.0 → 1.6.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 (71) hide show
  1. package/dist/fore-dev.js +2 -36
  2. package/dist/fore-dev.js.map +1 -1
  3. package/dist/fore.js +2 -30
  4. package/dist/fore.js.map +1 -1
  5. package/index.js +12 -0
  6. package/package.json +9 -5
  7. package/resources/fore.css +178 -92
  8. package/src/DependencyNotifyingDomFacade.js +1 -2
  9. package/src/ForeElementMixin.js +31 -5
  10. package/src/actions/abstract-action.js +379 -297
  11. package/src/actions/fx-action.js +0 -1
  12. package/src/actions/fx-append.js +1 -2
  13. package/src/actions/fx-confirm.js +12 -0
  14. package/src/actions/fx-copy.js +0 -1
  15. package/src/actions/fx-delete.js +31 -9
  16. package/src/actions/fx-dispatch.js +19 -5
  17. package/src/actions/fx-hide.js +19 -0
  18. package/src/actions/fx-insert.js +72 -8
  19. package/src/actions/fx-load.js +253 -0
  20. package/src/actions/fx-message.js +22 -7
  21. package/src/actions/fx-refresh.js +11 -1
  22. package/src/actions/fx-reload.js +12 -2
  23. package/src/actions/fx-replace.js +5 -4
  24. package/src/actions/fx-reset.js +48 -0
  25. package/src/actions/fx-return.js +0 -1
  26. package/src/actions/fx-send.js +40 -2
  27. package/src/actions/fx-setfocus.js +25 -7
  28. package/src/actions/fx-setvalue.js +32 -4
  29. package/src/actions/fx-show.js +14 -2
  30. package/src/actions/fx-toggle.js +0 -1
  31. package/src/actions/fx-update.js +9 -0
  32. package/src/events.js +0 -1
  33. package/src/fore.js +118 -63
  34. package/src/functions/common-function.js +28 -0
  35. package/src/fx-bind.js +7 -7
  36. package/src/fx-fore.js +152 -55
  37. package/src/fx-instance.js +55 -17
  38. package/src/fx-model.js +31 -33
  39. package/src/fx-submission.js +50 -47
  40. package/src/getInScopeContext.js +8 -10
  41. package/src/lab/fore-component.js +90 -0
  42. package/src/lab/instance-inspector.js +56 -0
  43. package/src/lab/template.html +16 -0
  44. package/src/relevance.js +27 -1
  45. package/src/tools/adi.js +1056 -0
  46. package/src/tools/fx-action-log.js +662 -0
  47. package/src/tools/fx-devtools.js +444 -0
  48. package/src/tools/fx-dom-inspector.js +609 -0
  49. package/src/tools/fx-json-instance.js +435 -0
  50. package/src/tools/fx-log-item.js +133 -0
  51. package/src/tools/fx-log-settings.js +474 -0
  52. package/src/tools/fx-minimap.js +194 -0
  53. package/src/tools/helpers.js +132 -0
  54. package/src/ui/abstract-control.js +41 -3
  55. package/src/ui/fx-action-log.js +358 -0
  56. package/src/ui/fx-alert.js +0 -1
  57. package/src/ui/fx-container.js +14 -3
  58. package/src/ui/fx-control.js +553 -474
  59. package/src/ui/fx-dialog.js +2 -0
  60. package/src/ui/fx-dom-inspector.js +1255 -0
  61. package/src/ui/fx-group.js +3 -4
  62. package/src/ui/fx-hint.js +2 -4
  63. package/src/ui/fx-inspector.js +5 -6
  64. package/src/ui/fx-items.js +55 -14
  65. package/src/ui/fx-output.js +36 -17
  66. package/src/ui/fx-repeat-attributes.js +10 -43
  67. package/src/ui/fx-repeat.js +5 -7
  68. package/src/ui/fx-switch.js +14 -3
  69. package/src/ui/fx-trigger.js +13 -1
  70. package/src/xpath-evaluation.js +109 -26
  71. package/src/xpath-util.js +55 -1
@@ -1,10 +1,12 @@
1
- import { foreElementMixin } from '../ForeElementMixin.js';
2
- import { evaluateXPathToBoolean, resolveId } from '../xpath-evaluation.js';
1
+ import {foreElementMixin} from '../ForeElementMixin.js';
2
+ import {evaluateXPathToBoolean, resolveId} from '../xpath-evaluation.js';
3
3
  import getInScopeContext from '../getInScopeContext.js';
4
- import { Fore } from '../fore.js';
4
+ import {Fore} from '../fore.js';
5
+ import {FxFore} from '../fx-fore.js';
6
+ import {XPathUtil} from '../xpath-util.js';
5
7
 
6
8
  async function wait(howLong) {
7
- return new Promise(resolve => setTimeout(() => resolve(), howLong));
9
+ return new Promise(resolve => setTimeout(() => resolve(), howLong));
8
10
  }
9
11
 
10
12
  /**
@@ -16,333 +18,413 @@ async function wait(howLong) {
16
18
  * @demo demo/index.html
17
19
  */
18
20
  export class AbstractAction extends foreElementMixin(HTMLElement) {
19
- static outermostHandler = null;
20
- static dataChanged = false;
21
-
22
- static get properties() {
23
- return {
24
- ...super.properties,
25
- /**
26
- * can be either 'cancel' or 'perform' (default)
27
- */
28
- defaultAction:{
29
- type: String
30
- },
31
- /**
32
- * delay before executing action in milliseconds
33
- */
34
- delay: {
35
- type: Number,
36
- },
37
- /**
38
- * detail - event detail object
39
- */
40
- detail: {
41
- type: Object,
42
- },
43
- /**
44
- * event to listen for
45
- */
46
- event: {
47
- type: Object,
48
- },
49
- handler:{
50
- type:Object,
51
- },
52
- /**
53
- * boolean XPath expression. If true the action will be executed.
54
- */
55
- ifExpr: {
56
- type: String,
57
- },
58
- /**
59
- * wether nor not an action needs to run the update cycle
60
- */
61
- needsUpdate: {
62
- type: Boolean,
63
- },
64
- /**
65
- * The observer if given is the element on which an event is triggered. It must be an ancestor of the target
66
- * element of an event.
67
- */
68
- observer:{
69
- type:Object,
70
- },
71
- /**
72
- * can be either 'stop' or 'continue' (default)
73
- */
74
- propagate:{
75
- type: String,
76
- },
77
- /**
78
- * id of target element to attach listener to
79
- */
80
- target: {
81
- type: String,
82
- },
83
- /**
84
- * boolean XPath expression. If true loop will be executed. If an ifExpr is present this also needs to be true
85
- * to actually run the action.
86
- */
87
- whileExpr: {
88
- type: String,
89
- },
90
- };
91
- }
92
-
93
- constructor() {
94
- super();
95
- this.detail = {};
96
- this.needsUpdate = false;
97
- }
98
-
99
- connectedCallback() {
100
- this.style.display = 'none';
101
- this.propagate = this.hasAttribute('propagate')? this.getAttribute('propagate'):'continue';
102
- this.repeatContext = undefined;
103
-
104
- if (this.hasAttribute('event')) {
105
- this.event = this.getAttribute('event');
106
- } else {
107
- this.event = 'activate';
21
+ static dataChanged = false;
22
+
23
+ static get properties() {
24
+ return {
25
+ ...super.properties,
26
+ /**
27
+ * can be either 'cancel' or 'perform' (default)
28
+ */
29
+ defaultAction: {
30
+ type: String
31
+ },
32
+ /**
33
+ * delay before executing action in milliseconds
34
+ */
35
+ delay: {
36
+ type: Number,
37
+ },
38
+ /**
39
+ * detail - event detail object
40
+ */
41
+ detail: {
42
+ type: Object,
43
+ },
44
+ /**
45
+ * event to listen for
46
+ */
47
+ event: {
48
+ type: Object,
49
+ },
50
+ handler: {
51
+ type: Object,
52
+ },
53
+ /**
54
+ * boolean XPath expression. If true the action will be executed.
55
+ */
56
+ ifExpr: {
57
+ type: String,
58
+ },
59
+ /**
60
+ * whether nor not an action needs to run the update cycle
61
+ */
62
+ needsUpdate: {
63
+ type: Boolean,
64
+ },
65
+ /**
66
+ * The observer if given is the element on which an event is triggered. It must be an ancestor of the target
67
+ * element of an event.
68
+ */
69
+ observer: {
70
+ type: Object,
71
+ },
72
+ /**
73
+ * can be either 'capture' or 'default' (default)
74
+ */
75
+ phase: {
76
+ type: String,
77
+ },
78
+ /**
79
+ * can be either 'stop' or 'continue' (default)
80
+ */
81
+ propagate: {
82
+ type: String,
83
+ },
84
+ /**
85
+ * id of target element to attach listener to
86
+ */
87
+ target: {
88
+ type: String,
89
+ },
90
+ /**
91
+ * boolean XPath expression. If true loop will be executed. If an ifExpr is present this also needs to be true
92
+ * to actually run the action.
93
+ */
94
+ whileExpr: {
95
+ type: String,
96
+ },
97
+ };
108
98
  }
109
99
 
110
- this.target = this.getAttribute('target');
111
- if (this.target) {
112
- if (this.target === '#window') {
113
- window.addEventListener(this.event, e => this.execute(e));
114
- } else if (this.target === '#document') {
115
- document.addEventListener(this.event, e => this.execute(e));
116
- } else {
117
- this.targetElement = resolveId(this.target, this);
118
- this.targetElement.addEventListener(this.event, e => this.execute(e));
119
- }
120
- } else {
121
- this.targetElement = this.parentNode;
122
- this.targetElement.addEventListener(this.event, e => this.execute(e));
123
- // console.log('adding listener for ', this.event , ` to `, this);
100
+ constructor() {
101
+ super();
102
+ this.detail = {};
103
+ this.needsUpdate = false;
124
104
  }
125
105
 
126
- this.ifExpr = this.hasAttribute('if') ? this.getAttribute('if') : null;
127
- this.whileExpr = this.hasAttribute('while') ? this.getAttribute('while') : null;
128
- this.delay = this.hasAttribute('delay') ? Number(this.getAttribute('delay')) : 0;
129
- }
130
-
131
- /**
132
- * executes the action.
133
- *
134
- * Will first evaluate ifExpr and continue only if it evaluates to 'true'. The 'whileExpr' will be executed
135
- * considering the delay if present.
136
- *
137
- * After calling `perform' which actually implements the semantics of an concrete action
138
- * `actionPerformed` will make sure that update cycle is run if 'needsUpdate' is true.
139
- *
140
- * @param e
141
- */
142
- async execute(e) {
143
- if(this.propagate === 'stop'){
144
- console.log('event propagation stopped', e)
145
- e.stopPropagation();
146
- }
106
+ connectedCallback() {
107
+ this.style.display = 'none';
108
+ this.propagate = this.hasAttribute('propagate') ? this.getAttribute('propagate') : 'continue';
109
+ this.repeatContext = undefined;
147
110
 
148
- let resolveThisEvent = () => {};
149
- if (e && e.listenerPromises) {
150
- e.listenerPromises.push(
151
- new Promise(resolve => {
152
- resolveThisEvent = resolve;
153
- }),
154
- );
155
- }
111
+ if (this.hasAttribute('event')) {
112
+ this.event = this.getAttribute('event');
113
+ }
114
+ if (this.hasAttribute('defaultAction')) {
115
+ this.defaultAction = this.getAttribute('defaultAction');
116
+ } else {
117
+ this.defaultAction = 'perform';
118
+ }
119
+ if (this.hasAttribute('phase')) {
120
+ this.phase = this.getAttribute('phase');
121
+ } else {
122
+ this.phase = 'default';
123
+ }
156
124
 
157
- // console.log('executing', this);
158
-
159
- // console.log('executing e', e);
160
- // console.log('executing e phase', e.eventPhase);
161
- if (AbstractAction.outermostHandler === null) {
162
- console.time('outermostHandler');
163
- console.info(
164
- `%coutermost Action `,
165
- 'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
166
- this,
167
- );
168
- // console.log('starting outermost handler',this);
169
- AbstractAction.outermostHandler = this;
170
- }
125
+ /*
126
+ this.addEventListener('click', e => {
127
+ e.preventDefault();
128
+ e.stopPropagation();
129
+ });
130
+ */
171
131
 
172
- if (AbstractAction.outermostHandler !== this) {
173
- console.info(
174
- `%cAction `,
175
- 'background:orange; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
176
- this,
177
- );
178
- }
179
- // console.log('>>> outermostHandler', AbstractAction.outermostHandler);
132
+ this.ifExpr = this.hasAttribute('if') ? this.getAttribute('if') : null;
133
+ this.whileExpr = this.hasAttribute('while') ? this.getAttribute('while') : null;
134
+ this.delay = this.hasAttribute('delay') ? Number(this.getAttribute('delay')) : 0;
180
135
 
181
- if (e && e.code) {
182
- const vars = new Map();
183
- vars.set('code', e.code);
184
- // this.setInScopeVariables(vars);
185
- this.setInScopeVariables(new Map([...this.inScopeVariables, ...vars]));
186
- }
136
+ this._addUpdateListener();
187
137
 
188
- if (e && e.detail) {
189
- this.detail = e.detail;
190
- const vars = new Map();
191
- Object.keys(e.detail).forEach(function(key, index) {
192
- // key: the name of the object key
193
- // index: the ordinal position of the key within the object
194
- vars.set(key, e.detail[key]);
195
- });
196
- if (vars.size !== 0) {
197
- console.log('event detail vars', vars);
198
- }
199
- this.setInScopeVariables(new Map([...this.inScopeVariables, ...vars]));
200
138
  }
201
- this.needsUpdate = false;
202
139
 
203
- try {
204
- this.evalInContext();
205
- } catch (error) {
206
- console.warn('evaluation faild', error);
207
- }
208
- if (this.targetElement && this.targetElement.nodeset) {
209
- this.nodeset = this.targetElement.nodeset;
140
+ _addUpdateListener() {
141
+ this.target = this.getAttribute('target');
142
+ if (this.target) {
143
+ if (this.target === '#window') {
144
+ window.addEventListener(this.event, e => this.execute(e), {capture: this.phase === 'capture'});
145
+ } else if (this.target === '#document') {
146
+ document.addEventListener(this.event, e => this.execute(e), {capture: this.phase === 'capture'});
147
+ } else {
148
+ this.targetElement = resolveId(this.target, this);
149
+ if (!this.targetElement) return; //does not or does not yet exist
150
+ this?.targetElement.addEventListener(this.event, e => this.execute(e), {capture: this.phase === 'capture'});
151
+ }
152
+ } else {
153
+ this.targetElement = this.parentNode;
154
+ this.targetElement.addEventListener(this.event, e => this.execute(e), {capture: this.phase === 'capture'});
155
+ // console.log('adding listener for ', this.event , ` to `, this);
156
+ }
210
157
  }
211
158
 
212
- // First check if 'if' condition is true - otherwise exist right away
213
- if (this.ifExpr && !evaluateXPathToBoolean(this.ifExpr, getInScopeContext(this), this)) {
214
- this._finalizePerform(resolveThisEvent);
215
- return;
216
- }
159
+ async performSafe() {
160
+ try {
161
+ await this.perform();
162
+ // Return true to indicate success
163
+ return true;
164
+ } catch (error) {
165
+ const stringifiedComponent = `<${this.localName} ${Array.from(this.attributes).map(attr=>`${attr.name}="${attr.value}"`).join(' ')}>…</${this.localName}>`;
166
+ await Fore.dispatch(this, 'error', {
167
+ message: `The action could not be performed. ${error} The error came from ${stringifiedComponent}`,
168
+ });
169
+ // Return false to indicate failure. Any loops must be canceled
170
+ return false;
171
+ }
172
+ }
173
+
174
+ /**
175
+ * executes the action.
176
+ *
177
+ * Will first evaluate ifExpr and continue only if it evaluates to 'true'. The 'whileExpr' will be executed
178
+ * considering the delay if present.
179
+ *
180
+ * After calling `perform' which actually implements the semantics of an concrete action
181
+ * `actionPerformed` will make sure that update cycle is run if 'needsUpdate' is true.
182
+ *
183
+ * @param e
184
+ */
185
+ async execute(e) {
186
+ // console.log('execute', this, e);
187
+ // console.log('execute', this.event);
188
+
189
+
190
+ if (e && e.target.nodeType !== Node.DOCUMENT_NODE ){
191
+ /*
192
+ ### ignore event if there's a parent fore and the current element is NOT part of it. This avoids
193
+ ### an event to fire twice on an inner one and the surrounding one(s).
194
+ ### e.target might be outside an fx-fore element and shouldn't get cancelled in that case.
195
+ */
196
+ if(e.target.closest('fx-fore') && e.target.closest('fx-fore') !== this.closest('fx-fore')) {
197
+ // Event originates from a sub-component. Ignore it!
198
+ // No need to stop propagation. All other listeners will also ignore it from here
199
+ return;
200
+ }
201
+ }
202
+
203
+ if (this.propagate === 'stop') {
204
+ // console.log('event propagation stopped', e)
205
+ e.stopPropagation();
206
+ }
207
+ if (this.defaultAction === 'cancel') {
208
+ e.preventDefault();
209
+ }
217
210
 
218
- if (this.whileExpr) {
219
- // While: while the condition is true, delay a bit and execute the action
220
- const loop = async () => {
221
- // Start by waiting
222
- await wait(this.delay || 0);
211
+ let resolveThisEvent = () => {};
212
+ if (e && e.listenerPromises) {
213
+ e.listenerPromises.push(
214
+ new Promise(resolve => {
215
+ resolveThisEvent = resolve;
216
+ }),
217
+ );
218
+ }
223
219
 
224
- if (!this.ownerDocument.contains(this)) {
225
- // We are no longer in the document. Stop working
226
- return;
220
+ // console.log('executing', this);
221
+ // console.log('executing e', e);
222
+ // console.log('executing e phase', e.eventPhase);
223
+ if (FxFore.outermostHandler === null) {
224
+ // console.time('outermostHandler');
225
+ /*
226
+ console.info(
227
+ `%coutermost Action `,
228
+ 'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
229
+ this,
230
+ );
231
+ */
232
+ // console.log('starting outermost handler',this);
233
+ FxFore.outermostHandler = this;
234
+ this.dispatchEvent(new CustomEvent('outermost-action-start', {
235
+ composed: true,
236
+ bubbles: true,
237
+ cancelable: true, detail: {cause: e?.type}
238
+ }));
227
239
  }
228
240
 
229
- if (!evaluateXPathToBoolean(this.whileExpr, getInScopeContext(this), this)) {
230
- // Done with iterating
231
- return;
241
+ /*
242
+ if (FxFore.outermostHandler !== this) {
243
+ console.info(
244
+ `%cAction `,
245
+ 'background:orange; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
246
+ this,
247
+ );
232
248
  }
249
+ */
250
+ // console.log('>>> outermostHandler', FxFore.outermostHandler);
233
251
 
234
- // Perform the action once
235
- this.perform();
252
+ if (e) {
253
+ this.currentEvent = e;
254
+ }
255
+ this.needsUpdate = false;
236
256
 
237
- // Go for one more iteration
238
- if (this.delay) {
239
- // If we have a delay, fire and forget this.
240
- // Otherwise, if we have no delay, keep waiting for all iterations to be done.
241
- // The while is then uninteruptable and immediate
242
- loop();
243
- return;
257
+ try {
258
+ this.evalInContext();
259
+ } catch (error) {
260
+ console.warn('evaluation failed', error);
261
+ }
262
+ if (this.targetElement && this.targetElement.nodeset) {
263
+ this.nodeset = this.targetElement.nodeset;
244
264
  }
245
- await loop();
246
- };
247
265
 
248
- // After loop is done call actionPerformed to update the model and UI
249
- await loop();
250
- this._finalizePerform(resolveThisEvent);
266
+ // First check if 'if' condition is true - otherwise exist right away
267
+ if (this.ifExpr && !evaluateXPathToBoolean(this.ifExpr, getInScopeContext(this), this)) {
268
+ this._finalizePerform(resolveThisEvent);
269
+ return;
270
+ }
271
+
272
+ // console.log('performing action', this);
273
+
274
+ if (this.whileExpr) {
275
+ // While: while the condition is true, delay a bit and execute the action
276
+ const loop = async () => {
277
+ // Start by waiting
278
+ await wait(this.delay || 0);
279
+
280
+ if (!XPathUtil.contains(this.getOwnerForm(), this)) {
281
+ // We are no longer in the document. Stop working
282
+ return;
283
+ }
284
+
285
+ if (!evaluateXPathToBoolean(this.whileExpr, getInScopeContext(this), this)) {
286
+ // Done with iterating
287
+ return;
288
+ }
289
+
290
+ // Perform the action once. But quit if it errored
291
+ if (!this.performSafe()) {
292
+ return;
293
+ }
294
+
295
+ // Go for one more iteration
296
+ if (this.delay) {
297
+ // If we have a delay, fire and forget this.
298
+ // Otherwise, if we have no delay, keep waiting for all iterations to be done.
299
+ // The while is then uninterruptable and immediate
300
+ loop();
301
+ return;
302
+ }
303
+ await loop();
304
+ };
305
+
306
+ // After loop is done call actionPerformed to update the model and UI
307
+ await loop();
308
+ this._finalizePerform(resolveThisEvent);
309
+
310
+ return;
311
+ }
312
+
313
+ if (this.delay) {
314
+ // Delay further execution until the delay is done
315
+ await wait(this.delay);
316
+ if (!XPathUtil.contains(this.getOwnerForm(), this)) {
317
+ // We are no longer in the document. Stop working
318
+ this.actionPerformed();
319
+ resolveThisEvent();
320
+ return;
321
+ }
322
+ }
251
323
 
252
- return;
324
+ await this.performSafe();
325
+ this._finalizePerform(resolveThisEvent);
253
326
  }
254
327
 
255
- if (this.delay) {
256
- // Delay further execution until the delay is done
257
- await wait(this.delay);
258
- if (!this.ownerDocument.contains(this)) {
259
- // We are no longer in the document. Stop working
328
+ _finalizePerform(resolveThisEvent) {
329
+ this.currentEvent = null;
260
330
  this.actionPerformed();
331
+ if (FxFore.outermostHandler === this) {
332
+ FxFore.outermostHandler = null;
333
+ /*
334
+ console.info(
335
+ `%coutermost Action done`,
336
+ 'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
337
+ this,
338
+ );
339
+ console.timeEnd('outermostHandler');
340
+ */
341
+ this.dispatchEvent(new CustomEvent('outermost-action-end', {
342
+ composed: true,
343
+ bubbles: true,
344
+ cancelable: true
345
+ }));
346
+
347
+
348
+ }
261
349
  resolveThisEvent();
262
- return;
263
- }
264
350
  }
265
351
 
266
- await this.perform();
267
- this._finalizePerform(resolveThisEvent);
268
- }
269
-
270
- _finalizePerform(resolveThisEvent) {
271
- this.actionPerformed();
272
- if (AbstractAction.outermostHandler === this) {
273
- AbstractAction.outermostHandler = null;
274
- console.info(
275
- `%coutermost Action done`,
276
- 'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
277
- this,
278
- );
279
- console.timeEnd('outermostHandler');
352
+ /**
353
+ * Template method to be implemented by each action that is called by execute() as part of
354
+ * the processing.
355
+ *
356
+ * This function should not called on any action directly - call execute() instead to ensure proper execution of 'if' and 'while'
357
+ */
358
+ async perform() {
359
+ // await Fore.dispatch(document, 'execute-action', {action:this, event:this.event});
360
+
361
+ //todo: review - this evaluation seems redundant as we already evaluated in execute
362
+ if (this.isBound() || this.nodeName === 'FX-ACTION') {
363
+ this.evalInContext();
364
+ }
365
+
366
+ this.dispatchEvent(
367
+ new CustomEvent('execute-action', {
368
+ composed: true,
369
+ bubbles: true,
370
+ cancelable: true,
371
+ detail: {action: this, event: this.event},
372
+ }),
373
+ );
280
374
 
281
375
  }
282
- resolveThisEvent();
283
- }
284
-
285
- /**
286
- * Template method to be implemented by each action that is called by execute() as part of
287
- * the processing.
288
- *
289
- * This function should not called on any action directly - call execute() instead to ensure proper execution of 'if' and 'while'
290
- */
291
- async perform() {
292
- //todo: review - this evaluation seems redundant as we already evaluated in execute
293
- if (this.isBound() || this.nodeName === 'FX-ACTION') {
294
- this.evalInContext();
295
- }
296
- }
297
-
298
- /**
299
- * calls the update cycle if action signalled that update is needed.
300
- */
301
- actionPerformed() {
302
- const model = this.getModel();
303
- if(!model){
304
- return;
305
- }
306
- if (!model.inited) {
307
- return;
308
- }
309
- if (
310
- AbstractAction.outermostHandler &&
311
- !AbstractAction.outermostHandler.ownerDocument.contains(AbstractAction.outermostHandler)
312
- ) {
313
- // The old outermosthandler fell out of the document. An error has happened.
314
- // Just remove the old one and act like we are starting anew.
315
- console.warn('Unsetting outermost handler');
316
- AbstractAction.outermostHandler = null;
376
+
377
+ /**
378
+ * calls the update cycle if action signalled that update is needed.
379
+ */
380
+ actionPerformed() {
381
+ const model = this.getModel();
382
+ if (!model) {
383
+ return;
384
+ }
385
+ if (!model.inited) {
386
+ return;
387
+ }
388
+ if (
389
+ FxFore.outermostHandler &&
390
+ !XPathUtil.contains(FxFore.outermostHandler.ownerDocument, FxFore.outermostHandler)
391
+ ) {
392
+ // The old outermostHandler fell out of the document. An error has happened.
393
+ // Just remove the old one and act like we are starting anew.
394
+ // console.warn('Unsetting outermost handler');
395
+ FxFore.outermostHandler = null;
396
+ }
397
+ // console.log('actionPerformed action parentNode ', this.parentNode);
398
+ if (
399
+ this.needsUpdate &&
400
+ (FxFore.outermostHandler === this || !FxFore.outermostHandler)
401
+ ) {
402
+ // console.log('running update cycle for outermostHandler', this);
403
+ model.recalculate();
404
+ model.revalidate();
405
+ model.parentNode.refresh(true);
406
+ this.dispatchActionPerformed();
407
+ } else if (this.needsUpdate) {
408
+ // console.log('Update delayed!');
409
+ // We need an update, but the outermost action handler is not done yet. Make this clear!
410
+ // console.log('running actionperformed on', this, ' to be updated by ', FxFore.outermostHandler);
411
+ FxFore.outermostHandler.needsUpdate = true;
412
+ }
413
+
414
+ // console.log('running actionperformed on', this, ' outermostHandler', FxFore.outermostHandler);
317
415
  }
318
- // console.log('actionPerformed action parentNode ', this.parentNode);
319
- if (
320
- this.needsUpdate &&
321
- (AbstractAction.outermostHandler === this || !AbstractAction.outermostHandler)
322
- ) {
323
- console.log('Running actionperformed');
324
- model.recalculate();
325
- model.revalidate();
326
- model.parentNode.refresh(true);
327
- this.dispatchActionPerformed();
328
- } else if (this.needsUpdate) {
329
- // We need an update, but the outermost action handler may not. Make this clear!
330
- AbstractAction.outermostHandler.needsUpdate = true;
331
- console.log('Update surpressed!');
416
+
417
+ /**
418
+ * dispatches action-performed event
419
+ *
420
+ * @event action-performed - whenever an action has been run
421
+ */
422
+ dispatchActionPerformed() {
423
+ // console.log('action-performed ', this);
424
+ Fore.dispatch(this, 'action-performed', {});
332
425
  }
333
- }
334
-
335
- /**
336
- * dispathes action-performed event
337
- *
338
- * @event action-performed - whenever an action has been run
339
- */
340
- dispatchActionPerformed() {
341
- // console.log('action-performed ', this);
342
- Fore.dispatch(this, 'action-performed', {});
343
- }
344
426
  }
345
427
 
346
428
  if (!customElements.get('abstract-action')) {
347
- window.customElements.define('abstract-action', AbstractAction);
429
+ window.customElements.define('abstract-action', AbstractAction);
348
430
  }