@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.
- package/dist/fore-dev.js +2 -36
- package/dist/fore-dev.js.map +1 -1
- package/dist/fore.js +2 -30
- package/dist/fore.js.map +1 -1
- package/index.js +12 -0
- package/package.json +9 -5
- package/resources/fore.css +178 -92
- package/src/DependencyNotifyingDomFacade.js +1 -2
- package/src/ForeElementMixin.js +31 -5
- package/src/actions/abstract-action.js +379 -297
- package/src/actions/fx-action.js +0 -1
- package/src/actions/fx-append.js +1 -2
- package/src/actions/fx-confirm.js +12 -0
- package/src/actions/fx-copy.js +0 -1
- package/src/actions/fx-delete.js +31 -9
- package/src/actions/fx-dispatch.js +19 -5
- package/src/actions/fx-hide.js +19 -0
- package/src/actions/fx-insert.js +72 -8
- package/src/actions/fx-load.js +253 -0
- package/src/actions/fx-message.js +22 -7
- package/src/actions/fx-refresh.js +11 -1
- package/src/actions/fx-reload.js +12 -2
- package/src/actions/fx-replace.js +5 -4
- package/src/actions/fx-reset.js +48 -0
- package/src/actions/fx-return.js +0 -1
- package/src/actions/fx-send.js +40 -2
- package/src/actions/fx-setfocus.js +25 -7
- package/src/actions/fx-setvalue.js +32 -4
- package/src/actions/fx-show.js +14 -2
- package/src/actions/fx-toggle.js +0 -1
- package/src/actions/fx-update.js +9 -0
- package/src/events.js +0 -1
- package/src/fore.js +118 -63
- package/src/functions/common-function.js +28 -0
- package/src/fx-bind.js +7 -7
- package/src/fx-fore.js +152 -55
- package/src/fx-instance.js +55 -17
- package/src/fx-model.js +31 -33
- package/src/fx-submission.js +50 -47
- package/src/getInScopeContext.js +8 -10
- package/src/lab/fore-component.js +90 -0
- package/src/lab/instance-inspector.js +56 -0
- package/src/lab/template.html +16 -0
- package/src/relevance.js +27 -1
- package/src/tools/adi.js +1056 -0
- package/src/tools/fx-action-log.js +662 -0
- package/src/tools/fx-devtools.js +444 -0
- package/src/tools/fx-dom-inspector.js +609 -0
- package/src/tools/fx-json-instance.js +435 -0
- package/src/tools/fx-log-item.js +133 -0
- package/src/tools/fx-log-settings.js +474 -0
- package/src/tools/fx-minimap.js +194 -0
- package/src/tools/helpers.js +132 -0
- package/src/ui/abstract-control.js +41 -3
- package/src/ui/fx-action-log.js +358 -0
- package/src/ui/fx-alert.js +0 -1
- package/src/ui/fx-container.js +14 -3
- package/src/ui/fx-control.js +553 -474
- package/src/ui/fx-dialog.js +2 -0
- package/src/ui/fx-dom-inspector.js +1255 -0
- package/src/ui/fx-group.js +3 -4
- package/src/ui/fx-hint.js +2 -4
- package/src/ui/fx-inspector.js +5 -6
- package/src/ui/fx-items.js +55 -14
- package/src/ui/fx-output.js +36 -17
- package/src/ui/fx-repeat-attributes.js +10 -43
- package/src/ui/fx-repeat.js +5 -7
- package/src/ui/fx-switch.js +14 -3
- package/src/ui/fx-trigger.js +13 -1
- package/src/xpath-evaluation.js +109 -26
- package/src/xpath-util.js +55 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {foreElementMixin} from '../ForeElementMixin.js';
|
|
2
|
+
import {evaluateXPathToBoolean, resolveId} from '../xpath-evaluation.js';
|
|
3
3
|
import getInScopeContext from '../getInScopeContext.js';
|
|
4
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
235
|
-
|
|
252
|
+
if (e) {
|
|
253
|
+
this.currentEvent = e;
|
|
254
|
+
}
|
|
255
|
+
this.needsUpdate = false;
|
|
236
256
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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
|
-
|
|
324
|
+
await this.performSafe();
|
|
325
|
+
this._finalizePerform(resolveThisEvent);
|
|
253
326
|
}
|
|
254
327
|
|
|
255
|
-
|
|
256
|
-
|
|
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
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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
|
-
|
|
429
|
+
window.customElements.define('abstract-action', AbstractAction);
|
|
348
430
|
}
|