@jinntec/fore 1.4.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 +13 -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 -270
  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 +119 -63
  34. package/src/functions/common-function.js +28 -0
  35. package/src/fx-bind.js +7 -7
  36. package/src/fx-fore.js +207 -54
  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 +22 -8
  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 +409 -0
  67. package/src/ui/fx-repeat.js +12 -6
  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,306 +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
- * detail - event detail object
27
- */
28
- detail: {
29
- type: Object,
30
- },
31
- /**
32
- * wether nor not an action needs to run the update cycle
33
- */
34
- needsUpdate: {
35
- type: Boolean,
36
- },
37
- /**
38
- * event to listen for
39
- */
40
- event: {
41
- type: Object,
42
- },
43
- /**
44
- * id of target element to attach listener to
45
- */
46
- target: {
47
- type: String,
48
- },
49
- /**
50
- * boolean XPath expression. If true the action will be executed.
51
- */
52
- ifExpr: {
53
- type: String,
54
- },
55
- /**
56
- * boolean XPath expression. If true loop will be executed. If an ifExpr is present this also needs to be true
57
- * to actually run the action.
58
- */
59
- whileExpr: {
60
- type: String,
61
- },
62
- /**
63
- * delay before executing action in milliseconds
64
- */
65
- delay: {
66
- type: Number,
67
- },
68
- };
69
- }
70
-
71
- constructor() {
72
- super();
73
- this.detail = {};
74
- this.needsUpdate = false;
75
- }
76
-
77
- connectedCallback() {
78
- this.style.display = 'none';
79
- this.repeatContext = undefined;
80
-
81
- if (this.hasAttribute('event')) {
82
- this.event = this.getAttribute('event');
83
- } else {
84
- 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
+ };
85
98
  }
86
99
 
87
- this.target = this.getAttribute('target');
88
- if (this.target) {
89
- if (this.target === '#window') {
90
- window.addEventListener(this.event, e => this.execute(e));
91
- } else if (this.target === '#document') {
92
- document.addEventListener(this.event, e => this.execute(e));
93
- } else {
94
- this.targetElement = resolveId(this.target, this);
95
- this.targetElement.addEventListener(this.event, e => this.execute(e));
96
- }
97
- } else {
98
- this.targetElement = this.parentNode;
99
- this.targetElement.addEventListener(this.event, e => this.execute(e));
100
- // console.log('adding listener for ', this.event , ` to `, this);
100
+ constructor() {
101
+ super();
102
+ this.detail = {};
103
+ this.needsUpdate = false;
101
104
  }
102
105
 
103
- this.ifExpr = this.hasAttribute('if') ? this.getAttribute('if') : null;
104
- this.whileExpr = this.hasAttribute('while') ? this.getAttribute('while') : null;
105
- this.delay = this.hasAttribute('delay') ? Number(this.getAttribute('delay')) : 0;
106
- }
107
-
108
- /**
109
- * executes the action.
110
- *
111
- * Will first evaluate ifExpr and continue only if it evaluates to 'true'. The 'whileExpr' will be executed
112
- * considering the delay if present.
113
- *
114
- * After calling `perform' which actually implements the semantics of an concrete action
115
- * `actionPerformed` will make sure that update cycle is run if 'needsUpdate' is true.
116
- *
117
- * @param e
118
- */
119
- async execute(e) {
120
- let resolveThisEvent = () => {};
121
- if (e && e.listenerPromises) {
122
- e.listenerPromises.push(
123
- new Promise(resolve => {
124
- resolveThisEvent = resolve;
125
- }),
126
- );
127
- }
106
+ connectedCallback() {
107
+ this.style.display = 'none';
108
+ this.propagate = this.hasAttribute('propagate') ? this.getAttribute('propagate') : 'continue';
109
+ this.repeatContext = undefined;
128
110
 
129
- // console.log('executing', this);
130
-
131
- // console.log('executing e', e);
132
- // console.log('executing e phase', e.eventPhase);
133
- if (AbstractAction.outermostHandler === null) {
134
- console.time('outermostHandler');
135
- console.info(
136
- `%coutermost Action `,
137
- 'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
138
- this,
139
- );
140
- // console.log('starting outermost handler',this);
141
- AbstractAction.outermostHandler = this;
142
- }
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
+ }
143
124
 
144
- if (AbstractAction.outermostHandler !== this) {
145
- console.info(
146
- `%cAction `,
147
- 'background:orange; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
148
- this,
149
- );
150
- }
151
- // console.log('>>> outermostHandler', AbstractAction.outermostHandler);
125
+ /*
126
+ this.addEventListener('click', e => {
127
+ e.preventDefault();
128
+ e.stopPropagation();
129
+ });
130
+ */
152
131
 
153
- if (e && e.code) {
154
- const vars = new Map();
155
- vars.set('code', e.code);
156
- // this.setInScopeVariables(vars);
157
- this.setInScopeVariables(new Map([...this.inScopeVariables, ...vars]));
158
- }
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;
159
135
 
160
- if (e && e.detail) {
161
- this.detail = e.detail;
162
- const vars = new Map();
163
- Object.keys(e.detail).forEach(function(key, index) {
164
- // key: the name of the object key
165
- // index: the ordinal position of the key within the object
166
- vars.set(key, e.detail[key]);
167
- });
168
- if (vars.size !== 0) {
169
- console.log('event detail vars', vars);
170
- }
171
- this.setInScopeVariables(new Map([...this.inScopeVariables, ...vars]));
172
- }
173
- this.needsUpdate = false;
136
+ this._addUpdateListener();
174
137
 
175
- try {
176
- this.evalInContext();
177
- } catch (error) {
178
- console.warn('evaluation faild', error);
179
- }
180
- if (this.targetElement && this.targetElement.nodeset) {
181
- this.nodeset = this.targetElement.nodeset;
182
138
  }
183
139
 
184
- // First check if 'if' condition is true - otherwise exist right away
185
- if (this.ifExpr && !evaluateXPathToBoolean(this.ifExpr, getInScopeContext(this), this)) {
186
- this._finalizePerform(resolveThisEvent);
187
- return;
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
+ }
188
157
  }
189
158
 
190
- if (this.whileExpr) {
191
- // While: while the condition is true, delay a bit and execute the action
192
- const loop = async () => {
193
- // Start by waiting
194
- await wait(this.delay || 0);
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
+ }
195
202
 
196
- if (!this.ownerDocument.contains(this)) {
197
- // We are no longer in the document. Stop working
198
- return;
203
+ if (this.propagate === 'stop') {
204
+ // console.log('event propagation stopped', e)
205
+ e.stopPropagation();
206
+ }
207
+ if (this.defaultAction === 'cancel') {
208
+ e.preventDefault();
199
209
  }
200
210
 
201
- if (!evaluateXPathToBoolean(this.whileExpr, getInScopeContext(this), this)) {
202
- // Done with iterating
203
- return;
211
+ let resolveThisEvent = () => {};
212
+ if (e && e.listenerPromises) {
213
+ e.listenerPromises.push(
214
+ new Promise(resolve => {
215
+ resolveThisEvent = resolve;
216
+ }),
217
+ );
204
218
  }
205
219
 
206
- // Perform the action once
207
- this.perform();
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
+ }));
239
+ }
208
240
 
209
- // Go for one more iteration
210
- if (this.delay) {
211
- // If we have a delay, fire and forget this.
212
- // Otherwise, if we have no delay, keep waiting for all iterations to be done.
213
- // The while is then uninteruptable and immediate
214
- loop();
215
- 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
+ );
248
+ }
249
+ */
250
+ // console.log('>>> outermostHandler', FxFore.outermostHandler);
251
+
252
+ if (e) {
253
+ this.currentEvent = e;
254
+ }
255
+ this.needsUpdate = false;
256
+
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;
216
264
  }
217
- await loop();
218
- };
219
265
 
220
- // After loop is done call actionPerformed to update the model and UI
221
- await loop();
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
+ }
222
323
 
223
- this._finalizePerform(resolveThisEvent);
224
- return;
324
+ await this.performSafe();
325
+ this._finalizePerform(resolveThisEvent);
225
326
  }
226
327
 
227
- if (this.delay) {
228
- // Delay further execution until the delay is done
229
- await wait(this.delay);
230
- if (!this.ownerDocument.contains(this)) {
231
- // We are no longer in the document. Stop working
328
+ _finalizePerform(resolveThisEvent) {
329
+ this.currentEvent = null;
232
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
+ }
233
349
  resolveThisEvent();
234
- return;
235
- }
236
350
  }
237
351
 
238
- await this.perform();
239
- this._finalizePerform(resolveThisEvent);
240
-
241
- }
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
+ }
242
365
 
243
- _finalizePerform(resolveThisEvent) {
244
- this.actionPerformed();
245
- if (AbstractAction.outermostHandler === this) {
246
- AbstractAction.outermostHandler = null;
247
- console.info(
248
- `%coutermost Action done`,
249
- 'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
250
- this,
251
- );
252
- console.timeEnd('outermostHandler');
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
+ );
253
374
 
254
375
  }
255
- resolveThisEvent();
256
- }
257
-
258
- /**
259
- * Template method to be implemented by each action that is called by execute() as part of
260
- * the processing.
261
- *
262
- * This function should not called on any action directly - call execute() instead to ensure proper execution of 'if' and 'while'
263
- */
264
- async perform() {
265
- //todo: review - this evaluation seems redundant as we already evaluated in execute
266
- if (this.isBound() || this.nodeName === 'FX-ACTION') {
267
- this.evalInContext();
268
- }
269
- }
270
-
271
- /**
272
- * calls the update cycle if action signalled that update is needed.
273
- */
274
- actionPerformed() {
275
- const model = this.getModel();
276
- if(!model){
277
- return;
278
- }
279
- if (!model.inited) {
280
- return;
281
- }
282
- if (
283
- AbstractAction.outermostHandler &&
284
- !AbstractAction.outermostHandler.ownerDocument.contains(AbstractAction.outermostHandler)
285
- ) {
286
- // The old outermosthandler fell out of the document. An error has happened.
287
- // Just remove the old one and act like we are starting anew.
288
- console.warn('Unsetting outermost handler');
289
- 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);
290
415
  }
291
- // console.log('actionPerformed action parentNode ', this.parentNode);
292
- if (
293
- this.needsUpdate &&
294
- (AbstractAction.outermostHandler === this || !AbstractAction.outermostHandler)
295
- ) {
296
- console.log('Running actionperformed');
297
- model.recalculate();
298
- model.revalidate();
299
- model.parentNode.refresh(true);
300
- this.dispatchActionPerformed();
301
- } else if (this.needsUpdate) {
302
- // We need an update, but the outermost action handler may not. Make this clear!
303
- AbstractAction.outermostHandler.needsUpdate = true;
304
- 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', {});
305
425
  }
306
- }
307
-
308
- /**
309
- * dispathes action-performed event
310
- *
311
- * @event action-performed - whenever an action has been run
312
- */
313
- dispatchActionPerformed() {
314
- // console.log('action-performed ', this);
315
- Fore.dispatch(this, 'action-performed', {});
316
- }
317
426
  }
318
427
 
319
428
  if (!customElements.get('abstract-action')) {
320
- window.customElements.define('abstract-action', AbstractAction);
429
+ window.customElements.define('abstract-action', AbstractAction);
321
430
  }