@jinntec/fore 1.2.0 → 1.4.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 +8 -8
- package/dist/fore-dev.js.map +1 -1
- package/dist/fore.js +7 -7
- package/dist/fore.js.map +1 -1
- package/index.js +1 -0
- package/package.json +2 -2
- package/resources/fore.css +100 -72
- package/src/ForeElementMixin.js +4 -0
- package/src/actions/abstract-action.js +102 -18
- package/src/actions/fx-action.js +9 -10
- package/src/actions/fx-append.js +1 -1
- package/src/actions/fx-confirm.js +3 -3
- package/src/actions/fx-copy.js +68 -0
- package/src/actions/fx-delete.js +53 -62
- package/src/actions/fx-dispatch.js +1 -1
- package/src/actions/fx-hide.js +4 -2
- package/src/actions/fx-insert.js +1 -1
- package/src/actions/fx-message.js +26 -2
- package/src/actions/fx-refresh.js +2 -2
- package/src/actions/fx-reload.js +30 -0
- package/src/actions/fx-replace.js +1 -1
- package/src/actions/fx-return.js +1 -1
- package/src/actions/fx-send.js +13 -3
- package/src/actions/fx-setfocus.js +33 -6
- package/src/actions/fx-setvalue.js +5 -5
- package/src/actions/fx-show.js +2 -1
- package/src/actions/fx-toggle.js +6 -1
- package/src/actions/fx-update.js +1 -1
- package/src/events.js +24 -0
- package/src/fore.js +128 -17
- package/src/fx-bind.js +6 -1
- package/src/fx-fore.js +93 -41
- package/src/fx-instance.js +95 -70
- package/src/fx-model.js +430 -441
- package/src/fx-submission.js +423 -405
- package/src/getInScopeContext.js +88 -82
- package/src/modelitem.js +5 -3
- package/src/relevance.js +1 -1
- package/src/ui/abstract-control.js +108 -22
- package/src/ui/fx-alert.js +0 -1
- package/src/ui/fx-container.js +22 -26
- package/src/ui/fx-control.js +84 -34
- package/src/ui/fx-group.js +5 -0
- package/src/ui/fx-inspector.js +5 -0
- package/src/ui/fx-output.js +14 -14
- package/src/ui/fx-repeat.js +2 -2
- package/src/ui/fx-repeatitem.js +5 -3
- package/src/ui/fx-switch.js +20 -8
- package/src/ui/fx-trigger.js +26 -19
- package/src/xpath-evaluation.js +49 -26
- package/src/xpath-util.js +26 -28
package/src/fx-submission.js
CHANGED
|
@@ -1,465 +1,483 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import {Fore} from './fore.js';
|
|
2
|
+
import {Relevance} from './relevance.js';
|
|
3
|
+
import {foreElementMixin} from './ForeElementMixin.js';
|
|
4
|
+
import {evaluateXPathToString, evaluateXPath} from './xpath-evaluation.js';
|
|
5
5
|
import getInScopeContext from './getInScopeContext.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* todo: validate='false'
|
|
9
9
|
*/
|
|
10
10
|
export class FxSubmission extends foreElementMixin(HTMLElement) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
this.attachShadow({mode: 'open'});
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
connectedCallback() {
|
|
17
|
+
// this.style.display = 'none';
|
|
18
|
+
this.methods = ['get', 'put', 'post', 'delete', 'head', 'urlencoded-post'];
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
this.model = this.parentNode;
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
// ### initialize properties with defaults
|
|
23
|
+
// if (!this.hasAttribute('id')) throw new Error('id is required');
|
|
24
|
+
if (!this.hasAttribute('id')) console.warn('id is required');
|
|
25
|
+
this.id = this.getAttribute('id');
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
/** if present should be a existing instance id */
|
|
28
|
+
this.instance = this.hasAttribute('instance') ? this.getAttribute('instance') : null;
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
/** if present will determine XPath where to insert a response into when mode is 'replace' */
|
|
31
|
+
this.into = this.hasAttribute('into') ? this.getAttribute('into') : null;
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
/** http method */
|
|
34
|
+
this.method = this.hasAttribute('method') ? this.getAttribute('method') : 'get';
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
/** relevance processing - one of 'remove, keep or empty' */
|
|
37
|
+
this.nonrelevant = this.hasAttribute('nonrelevant')
|
|
38
|
+
? this.getAttribute('nonrelevant')
|
|
39
|
+
: 'remove';
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
/** replace might be 'all', 'instance' or 'none' */
|
|
42
|
+
this.replace = this.hasAttribute('replace') ? this.getAttribute('replace') : 'all';
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
this.serialization = this.hasAttribute('serialization')
|
|
45
|
+
? this.getAttribute('serialization')
|
|
46
|
+
: 'xml';
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
// if (!this.hasAttribute('url')) throw new Error(`url is required for submission: ${this.id}`);
|
|
49
|
+
if (!this.hasAttribute('url')) console.warn(`url is required for submission: ${this.id}`);
|
|
50
|
+
this.url = this.getAttribute('url');
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
this.targetref = this.hasAttribute('targetref') ? this.getAttribute('targetref') : null;
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
this.mediatype = this.hasAttribute('mediatype')
|
|
55
|
+
? this.getAttribute('mediatype')
|
|
56
|
+
: 'application/xml';
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
this.validate = this.getAttribute('validate') ? this.getAttribute('validate') : 'true';
|
|
59
|
+
this.shadowRoot.innerHTML = this.renderHTML();
|
|
60
|
+
}
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
// eslint-disable-next-line class-methods-use-this
|
|
63
|
+
renderHTML() {
|
|
64
|
+
return `
|
|
65
65
|
<slot></slot>
|
|
66
66
|
`;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async submit() {
|
|
70
|
-
await Fore.dispatch(this, 'submit', { submission: this });
|
|
71
|
-
this._submit();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async _submit() {
|
|
75
|
-
console.log('submitting....', this.getAttribute('id'));
|
|
76
|
-
this.evalInContext();
|
|
77
|
-
const model = this.getModel();
|
|
78
|
-
|
|
79
|
-
model.recalculate();
|
|
80
|
-
|
|
81
|
-
if (this.validate==='true') {
|
|
82
|
-
const valid = model.revalidate();
|
|
83
|
-
if (!valid) {
|
|
84
|
-
console.log('validation failed. Bubmission stopped');
|
|
85
|
-
// ### allow alerts to pop up
|
|
86
|
-
// this.dispatch('submit-error', {});
|
|
87
|
-
Fore.dispatch(this, 'submit-error', {});
|
|
88
|
-
this.getModel().parentNode.refresh();
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
console.log('model updated....');
|
|
93
|
-
await this._serializeAndSend();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* resolves template expressions for a single attribute
|
|
98
|
-
* @param expr the attribute value to evaluate
|
|
99
|
-
* @param node the attribute node used for scoped resolution
|
|
100
|
-
* @returns {*}
|
|
101
|
-
* @private
|
|
102
|
-
*/
|
|
103
|
-
_evaluateAttributeTemplateExpression(expr, node) {
|
|
104
|
-
const matches = expr.match(/{[^}]*}/g);
|
|
105
|
-
if (matches) {
|
|
106
|
-
matches.forEach(match => {
|
|
107
|
-
console.log('match ', match);
|
|
108
|
-
const naked = match.substring(1, match.length - 1);
|
|
109
|
-
const inscope = getInScopeContext(node, naked);
|
|
110
|
-
const result = evaluateXPathToString(naked, inscope, this.getOwnerForm());
|
|
111
|
-
const replaced = expr.replaceAll(match, result);
|
|
112
|
-
console.log('replacing ', expr, ' with ', replaced);
|
|
113
|
-
expr = replaced;
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
return expr;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* sends the data after evaluating
|
|
121
|
-
*
|
|
122
|
-
* @private
|
|
123
|
-
*/
|
|
124
|
-
async _serializeAndSend() {
|
|
125
|
-
const resolvedUrl = this._evaluateAttributeTemplateExpression(this.url, this);
|
|
126
|
-
|
|
127
|
-
const instance = this.getInstance();
|
|
128
|
-
console.log('instance type', instance.type);
|
|
129
|
-
|
|
130
|
-
let serialized;
|
|
131
|
-
if (this.serialization === 'none') {
|
|
132
|
-
serialized = undefined;
|
|
133
|
-
} else {
|
|
134
|
-
// const relevant = this.selectRelevant(instance.type);
|
|
135
|
-
const relevant = Relevance.selectRelevant(this, instance.type);
|
|
136
|
-
serialized = this._serialize(instance.type, relevant);
|
|
137
67
|
}
|
|
138
68
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
// console.log('data being send', serialized);
|
|
144
|
-
// console.log('submitting data',serialized);
|
|
145
|
-
|
|
146
|
-
// if (resolvedUrl === '#echo') {
|
|
147
|
-
if (resolvedUrl.startsWith('#echo')) {
|
|
148
|
-
let data = this._parse(serialized, instance);
|
|
149
|
-
this._handleResponse(data);
|
|
150
|
-
// this.dispatch('submit-done', {});
|
|
151
|
-
Fore.dispatch(this, 'submit-done', {});
|
|
152
|
-
return;
|
|
69
|
+
async submit() {
|
|
70
|
+
await Fore.dispatch(this, 'submit', {submission: this});
|
|
71
|
+
await this._submit();
|
|
153
72
|
}
|
|
154
73
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
74
|
+
async _submit() {
|
|
75
|
+
console.log('submitting....', this.getAttribute('id'));
|
|
76
|
+
this.evalInContext();
|
|
77
|
+
const model = this.getModel();
|
|
78
|
+
|
|
79
|
+
model.recalculate();
|
|
80
|
+
|
|
81
|
+
if (this.validate === 'true') {
|
|
82
|
+
const valid = model.revalidate();
|
|
83
|
+
if (!valid) {
|
|
84
|
+
console.log('validation failed. Submission stopped');
|
|
85
|
+
this.getOwnerForm().classList.add('submit-validation-failed');
|
|
86
|
+
// ### allow alerts to pop up
|
|
87
|
+
// this.dispatch('submit-error', {});
|
|
88
|
+
Fore.dispatch(this, 'submit-error', {});
|
|
89
|
+
this.getModel().parentNode.refresh(true);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
console.log('model updated....');
|
|
94
|
+
await this._serializeAndSend();
|
|
161
95
|
}
|
|
162
96
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
97
|
+
/**
|
|
98
|
+
* resolves template expressions for a single attribute
|
|
99
|
+
* @param expr the attribute value to evaluate
|
|
100
|
+
* @param node the attribute node used for scoped resolution
|
|
101
|
+
* @returns {*}
|
|
102
|
+
* @private
|
|
103
|
+
*/
|
|
104
|
+
_evaluateAttributeTemplateExpression(expr, node) {
|
|
105
|
+
const matches = expr.match(/{[^}]*}/g);
|
|
106
|
+
if (matches) {
|
|
107
|
+
matches.forEach(match => {
|
|
108
|
+
console.log('match ', match);
|
|
109
|
+
const naked = match.substring(1, match.length - 1);
|
|
110
|
+
const inscope = getInScopeContext(node, naked);
|
|
111
|
+
const result = evaluateXPathToString(naked, inscope, this.getOwnerForm());
|
|
112
|
+
const replaced = expr.replaceAll(match, result);
|
|
113
|
+
console.log('replacing ', expr, ' with ', replaced);
|
|
114
|
+
expr = replaced;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return expr;
|
|
179
118
|
}
|
|
180
119
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
120
|
+
/**
|
|
121
|
+
* sends the data after evaluating
|
|
122
|
+
*
|
|
123
|
+
* @private
|
|
124
|
+
*/
|
|
125
|
+
async _serializeAndSend() {
|
|
126
|
+
const resolvedUrl = this._evaluateAttributeTemplateExpression(this.url, this);
|
|
184
127
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
this.method = 'post';
|
|
188
|
-
}
|
|
128
|
+
const instance = this.getInstance();
|
|
129
|
+
console.log('instance type', instance.type);
|
|
189
130
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
credentials: 'include',
|
|
199
|
-
headers,
|
|
200
|
-
body: serialized,
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
if (!response.ok || response.status > 400) {
|
|
204
|
-
// this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
|
|
205
|
-
Fore.dispatch(this, 'submit-error', { message: `Error while submitting ${this.id}` });
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
131
|
+
let serialized;
|
|
132
|
+
if (this.serialization === 'none') {
|
|
133
|
+
serialized = undefined;
|
|
134
|
+
} else {
|
|
135
|
+
// const relevant = this.selectRelevant(instance.type);
|
|
136
|
+
const relevant = Relevance.selectRelevant(this, instance.type);
|
|
137
|
+
serialized = this._serialize(instance.type, relevant);
|
|
138
|
+
}
|
|
208
139
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
140
|
+
// let serialized = serializer.serializeToString(relevant);
|
|
141
|
+
if (this.method.toLowerCase() === 'get') {
|
|
142
|
+
serialized = undefined;
|
|
143
|
+
}
|
|
144
|
+
// console.log('data being send', serialized);
|
|
145
|
+
// console.log('submitting data',serialized);
|
|
146
|
+
|
|
147
|
+
// if (resolvedUrl === '#echo') {
|
|
148
|
+
if (resolvedUrl.startsWith('#echo')) {
|
|
149
|
+
const data = this._parse(serialized, instance);
|
|
150
|
+
this._handleResponse(data);
|
|
151
|
+
// this.dispatch('submit-done', {});
|
|
152
|
+
Fore.dispatch(this, 'submit-done', {});
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (resolvedUrl.startsWith('localStore:')) {
|
|
157
|
+
|
|
158
|
+
if (this.method === 'get' || this.method === 'consume') {
|
|
159
|
+
// let data = this._parse(serialized, instance);
|
|
160
|
+
this.replace = 'instance';
|
|
161
|
+
const key = resolvedUrl.substring(resolvedUrl.indexOf(':') + 1);
|
|
162
|
+
const serialized = localStorage.getItem(key);
|
|
163
|
+
if (!serialized) {
|
|
164
|
+
Fore.dispatch(this, 'submit-error', {message: `Error reading key ${key} from localstorage`});
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
let data = this._parse(serialized, instance);
|
|
168
|
+
this._handleResponse(data);
|
|
169
|
+
if (this.method === 'consume') {
|
|
170
|
+
localStorage.removeItem(key);
|
|
171
|
+
}
|
|
172
|
+
Fore.dispatch(this, 'submit-done', {});
|
|
173
|
+
}
|
|
174
|
+
if (this.method === 'post') {
|
|
175
|
+
// let data = this._parse(serialized, instance);
|
|
176
|
+
const key = resolvedUrl.substring(resolvedUrl.indexOf(':') + 1);
|
|
177
|
+
localStorage.setItem(key, serialized);
|
|
178
|
+
this._handleResponse(instance.instanceData);
|
|
179
|
+
Fore.dispatch(this, 'submit-done', {});
|
|
180
|
+
}
|
|
181
|
+
if (this.method === 'delete') {
|
|
182
|
+
const key = resolvedUrl.substring(resolvedUrl.indexOf(':') + 1);
|
|
183
|
+
localStorage.removeItem(key);
|
|
184
|
+
const newInst = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
185
|
+
this._handleResponse(newInst);
|
|
186
|
+
Fore.dispatch(this, 'submit-done', {});
|
|
187
|
+
}
|
|
228
188
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
232
191
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
192
|
+
// ### setting headers
|
|
193
|
+
const headers = this._getHeaders();
|
|
194
|
+
console.log('headers', headers);
|
|
195
|
+
|
|
196
|
+
if (!this.methods.includes(this.method.toLowerCase())) {
|
|
197
|
+
// this.dispatch('error', { message: `Unknown method ${this.method}` });
|
|
198
|
+
Fore.dispatch(this, 'error', {message: `Unknown method ${this.method}`});
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
const response = await fetch(resolvedUrl, {
|
|
203
|
+
method: this.method,
|
|
204
|
+
mode: 'cors',
|
|
205
|
+
credentials: 'include',
|
|
206
|
+
headers,
|
|
207
|
+
body: serialized,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
if (!response.ok || response.status > 400) {
|
|
211
|
+
// this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
|
|
212
|
+
Fore.dispatch(this, 'submit-error', {message: `Error while submitting ${this.id}`});
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const contentType = response.headers.get('content-type').toLowerCase();
|
|
217
|
+
if (
|
|
218
|
+
contentType.startsWith('text/plain') ||
|
|
219
|
+
contentType.startsWith('text/html') ||
|
|
220
|
+
contentType.startsWith('text/markdown')
|
|
221
|
+
) {
|
|
222
|
+
const text = await response.text();
|
|
223
|
+
this._handleResponse(text);
|
|
224
|
+
} else if (contentType.startsWith('application/json')) {
|
|
225
|
+
const json = await response.json();
|
|
226
|
+
this._handleResponse(json);
|
|
227
|
+
} else if (contentType.startsWith('application/xml')) {
|
|
228
|
+
const text = await response.text();
|
|
229
|
+
const xml = new DOMParser().parseFromString(text, 'application/xml');
|
|
230
|
+
this._handleResponse(xml);
|
|
231
|
+
} else {
|
|
232
|
+
const blob = await response.blob();
|
|
233
|
+
this._handleResponse(blob);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// this.dispatch('submit-done', {});
|
|
237
|
+
Fore.dispatch(this, 'submit-done', {});
|
|
238
|
+
} catch (error) {
|
|
239
|
+
Fore.dispatch(this, 'submit-error', {error: error.message});
|
|
240
|
+
}
|
|
253
241
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
242
|
+
|
|
243
|
+
_parse(serialized, instance) {
|
|
244
|
+
let data = null;
|
|
245
|
+
if (serialized && instance.type === 'xml') {
|
|
246
|
+
data = new DOMParser().parseFromString(serialized, 'application/xml');
|
|
247
|
+
}
|
|
248
|
+
if (serialized && instance.type === 'json') {
|
|
249
|
+
data = JSON.parse(serialized);
|
|
250
|
+
}
|
|
251
|
+
return data;
|
|
257
252
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
253
|
+
|
|
254
|
+
_serialize(instanceType, relevantNodes) {
|
|
255
|
+
if (this.serialization === 'application/x-www-form-urlencoded') {
|
|
256
|
+
// this.method = 'post';
|
|
257
|
+
const params = new URLSearchParams();
|
|
258
|
+
// console.log('nodes to serialize', relevantNodes);
|
|
259
|
+
Array.from(relevantNodes.children).forEach(child => {
|
|
260
|
+
params.append(child.nodeName, child.textContent);
|
|
261
|
+
});
|
|
262
|
+
return params;
|
|
263
|
+
}
|
|
264
|
+
if (instanceType === 'xml') {
|
|
265
|
+
const serializer = new XMLSerializer();
|
|
266
|
+
return serializer.serializeToString(relevantNodes);
|
|
267
|
+
}
|
|
268
|
+
if (instanceType === 'json') {
|
|
269
|
+
// console.warn('JSON serialization is not yet supported')
|
|
270
|
+
return JSON.stringify(relevantNodes);
|
|
271
|
+
}
|
|
272
|
+
throw new Error('unknown instance type ', instanceType);
|
|
261
273
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
274
|
+
|
|
275
|
+
_getHeaders() {
|
|
276
|
+
const headers = new Headers();
|
|
277
|
+
|
|
278
|
+
// ### set content-type header according to type of instance
|
|
279
|
+
const instance = this.getInstance();
|
|
280
|
+
const contentType = Fore.getContentType(instance, this.serialization);
|
|
281
|
+
headers.append('Content-Type', contentType);
|
|
282
|
+
// ### needed to overwrite browsers' setting of 'Accept' header
|
|
283
|
+
if (headers.has('Accept')) {
|
|
284
|
+
headers.delete('Accept');
|
|
285
|
+
}
|
|
286
|
+
// headers.append('Accept', 'application/xml');
|
|
287
|
+
|
|
288
|
+
// ### add header defined by fx-header elements
|
|
289
|
+
const headerElems = this.querySelectorAll('fx-header');
|
|
290
|
+
Array.from(headerElems).forEach(header => {
|
|
291
|
+
const {name} = header;
|
|
292
|
+
const val = header.getValue();
|
|
293
|
+
headers.append(name, val);
|
|
294
|
+
});
|
|
295
|
+
return headers;
|
|
275
296
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const headerElems = this.querySelectorAll('fx-header');
|
|
280
|
-
Array.from(headerElems).forEach(header => {
|
|
281
|
-
const { name } = header;
|
|
282
|
-
const val = header.getValue();
|
|
283
|
-
headers.append(name, val);
|
|
284
|
-
});
|
|
285
|
-
return headers;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
_getUrlExpr() {
|
|
289
|
-
return this.storedTemplateExpressions.find(stored => stored.node.nodeName === 'url');
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
_getTargetInstance() {
|
|
293
|
-
let targetInstance;
|
|
294
|
-
if (this.instance) {
|
|
295
|
-
targetInstance = this.model.getInstance(this.instance);
|
|
296
|
-
} else {
|
|
297
|
-
targetInstance = this.model.getInstance('default');
|
|
297
|
+
|
|
298
|
+
_getUrlExpr() {
|
|
299
|
+
return this.storedTemplateExpressions.find(stored => stored.node.nodeName === 'url');
|
|
298
300
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
+
|
|
302
|
+
_getTargetInstance() {
|
|
303
|
+
let targetInstance;
|
|
304
|
+
if (this.instance) {
|
|
305
|
+
targetInstance = this.model.getInstance(this.instance);
|
|
306
|
+
} else {
|
|
307
|
+
targetInstance = this.model.getInstance('default');
|
|
308
|
+
}
|
|
309
|
+
if (!targetInstance) {
|
|
310
|
+
throw new Error(`target instance not found: ${targetInstance}`);
|
|
311
|
+
}
|
|
312
|
+
return targetInstance;
|
|
301
313
|
}
|
|
302
|
-
return targetInstance;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* handles replacement of instance data from response data.
|
|
307
|
-
*
|
|
308
|
-
* Please note that data might be
|
|
309
|
-
* @param data
|
|
310
|
-
* @private
|
|
311
|
-
*/
|
|
312
|
-
_handleResponse(data) {
|
|
313
|
-
console.log('_handleResponse ', data);
|
|
314
314
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
315
|
+
/**
|
|
316
|
+
* handles replacement of instance data from response data.
|
|
317
|
+
*
|
|
318
|
+
* Please note that data might be
|
|
319
|
+
* @param data
|
|
320
|
+
* @private
|
|
321
|
+
*/
|
|
322
|
+
_handleResponse(data) {
|
|
323
|
+
console.log('_handleResponse ', data);
|
|
318
324
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
this.
|
|
328
|
-
targetInstance
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
325
|
+
/*
|
|
326
|
+
// ### responses need to be handled depending on their type.
|
|
327
|
+
if(this.type === 'json'){
|
|
328
|
+
|
|
329
|
+
}
|
|
330
|
+
*/
|
|
331
|
+
|
|
332
|
+
if (this.replace === 'instance') {
|
|
333
|
+
const targetInstance = this._getTargetInstance();
|
|
334
|
+
if (targetInstance) {
|
|
335
|
+
if (this.targetref) {
|
|
336
|
+
const [theTarget] = evaluateXPath(
|
|
337
|
+
this.targetref,
|
|
338
|
+
targetInstance.instanceData.firstElementChild,
|
|
339
|
+
this,
|
|
340
|
+
);
|
|
341
|
+
console.log('theTarget', theTarget);
|
|
342
|
+
const clone = data.firstElementChild;
|
|
343
|
+
const parent = theTarget.parentNode;
|
|
344
|
+
parent.replaceChild(clone, theTarget);
|
|
345
|
+
console.log('finally ', parent);
|
|
346
|
+
} else if (this.into) {
|
|
347
|
+
const [theTarget] = evaluateXPath(
|
|
348
|
+
this.into,
|
|
349
|
+
targetInstance.instanceData.firstElementChild,
|
|
350
|
+
this,
|
|
351
|
+
);
|
|
352
|
+
console.log('theTarget', theTarget);
|
|
353
|
+
if (data.nodeType === Node.DOCUMENT_NODE) {
|
|
354
|
+
theTarget.appendChild(data.firstElementChild);
|
|
355
|
+
} else {
|
|
356
|
+
theTarget.innerHTML = data;
|
|
357
|
+
}
|
|
358
|
+
} else {
|
|
359
|
+
const instanceData = data;
|
|
360
|
+
targetInstance.instanceData = instanceData;
|
|
361
|
+
console.log('### replaced instance ', this.getModel().instances);
|
|
362
|
+
console.log('### replaced instance ', targetInstance.instanceData);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Skip any refreshes if the model is not yet inited
|
|
366
|
+
if (this.model.inited) {
|
|
367
|
+
this.model.updateModel(); // force update
|
|
368
|
+
this.getOwnerForm().refresh(true);
|
|
369
|
+
}
|
|
370
|
+
} else {
|
|
371
|
+
throw new Error(`target instance not found: ${targetInstance}`);
|
|
372
|
+
}
|
|
349
373
|
}
|
|
350
374
|
|
|
351
|
-
this.
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
375
|
+
if (this.replace === 'all') {
|
|
376
|
+
document.getElementsByTagName('html')[0].innerHTML = data;
|
|
377
|
+
}
|
|
378
|
+
if (this.replace === 'target') {
|
|
379
|
+
const target = this.getAttribute('target');
|
|
380
|
+
const targetNode = document.querySelector(target);
|
|
381
|
+
targetNode.innerHTML = data;
|
|
382
|
+
}
|
|
383
|
+
if (this.replace === 'redirect') {
|
|
384
|
+
window.location.href = data;
|
|
385
|
+
}
|
|
356
386
|
}
|
|
357
387
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
388
|
+
/**
|
|
389
|
+
* select relevant nodes
|
|
390
|
+
*
|
|
391
|
+
* @returns {*}
|
|
392
|
+
*/
|
|
393
|
+
/*
|
|
394
|
+
selectRelevant(type) {
|
|
395
|
+
console.log('selectRelevant' ,type)
|
|
396
|
+
switch (type){
|
|
397
|
+
case 'xml':
|
|
398
|
+
return this._relevantXmlNodes();
|
|
399
|
+
default:
|
|
400
|
+
console.warn(`relevance selection not supported for type:${this.type}`);
|
|
401
|
+
return this.nodeset;
|
|
402
|
+
}
|
|
368
403
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
/*
|
|
377
|
-
selectRelevant(type) {
|
|
378
|
-
console.log('selectRelevant' ,type)
|
|
379
|
-
switch (type){
|
|
380
|
-
case 'xml':
|
|
381
|
-
return this._relevantXmlNodes();
|
|
382
|
-
default:
|
|
383
|
-
console.warn(`relevance selection not supported for type:${this.type}`);
|
|
404
|
+
*/
|
|
405
|
+
|
|
406
|
+
// todo: support for 'empty'
|
|
407
|
+
/*
|
|
408
|
+
_relevantXmlNodes() {
|
|
409
|
+
// ### no relevance selection - current nodeset is used 'as-is'
|
|
410
|
+
if (this.nonrelevant === 'keep') {
|
|
384
411
|
return this.nodeset;
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
*/
|
|
388
|
-
|
|
389
|
-
// todo: support for 'empty'
|
|
390
|
-
/*
|
|
391
|
-
_relevantXmlNodes() {
|
|
392
|
-
// ### no relevance selection - current nodeset is used 'as-is'
|
|
393
|
-
if (this.nonrelevant === 'keep') {
|
|
394
|
-
return this.nodeset;
|
|
395
|
-
}
|
|
412
|
+
}
|
|
396
413
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
414
|
+
// first check if nodeset of submission is relevant - otherwise bail out
|
|
415
|
+
const mi = this.getModel().getModelItem(this.nodeset);
|
|
416
|
+
if (mi && !mi.relevant) return null;
|
|
400
417
|
|
|
401
|
-
|
|
402
|
-
|
|
418
|
+
const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
419
|
+
const root = doc.firstElementChild;
|
|
403
420
|
|
|
404
|
-
|
|
405
|
-
|
|
421
|
+
if (this.nodeset.children.length === 0 && this._isRelevant(this.nodeset)) {
|
|
422
|
+
return this.nodeset;
|
|
423
|
+
}
|
|
424
|
+
return this._filterRelevant(this.nodeset, root);
|
|
406
425
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
426
|
+
*/
|
|
427
|
+
|
|
428
|
+
/*
|
|
429
|
+
_filterRelevant(node, result) {
|
|
430
|
+
const { childNodes } = node;
|
|
431
|
+
Array.from(childNodes).forEach(n => {
|
|
432
|
+
if (this._isRelevant(n)) {
|
|
433
|
+
const clone = n.cloneNode(false);
|
|
434
|
+
result.appendChild(clone);
|
|
435
|
+
const { attributes } = n;
|
|
436
|
+
if (attributes) {
|
|
437
|
+
Array.from(attributes).forEach(attr => {
|
|
438
|
+
if (this._isRelevant(attr)) {
|
|
439
|
+
clone.setAttribute(attr.nodeName, attr.value);
|
|
440
|
+
} else if (this.nonrelevant === 'empty') {
|
|
441
|
+
clone.setAttribute(attr.nodeName, '');
|
|
442
|
+
} else {
|
|
443
|
+
clone.removeAttribute(attr.nodeName);
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
return this._filterRelevant(n, clone);
|
|
429
448
|
}
|
|
430
|
-
return
|
|
431
|
-
}
|
|
432
|
-
return
|
|
433
|
-
});
|
|
434
|
-
return result;
|
|
435
|
-
}
|
|
436
|
-
*/
|
|
437
|
-
|
|
438
|
-
/*
|
|
439
|
-
_isRelevant(node) {
|
|
440
|
-
const mi = this.getModel().getModelItem(node);
|
|
441
|
-
if (!mi || mi.relevant) {
|
|
442
|
-
return true;
|
|
449
|
+
return null;
|
|
450
|
+
});
|
|
451
|
+
return result;
|
|
443
452
|
}
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
*/
|
|
453
|
+
*/
|
|
447
454
|
|
|
448
|
-
_handleError() {
|
|
449
|
-
// this.dispatch('submit-error', {});
|
|
450
|
-
Fore.dispatch(this, 'submit-error', {});
|
|
451
455
|
/*
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
456
|
+
_isRelevant(node) {
|
|
457
|
+
const mi = this.getModel().getModelItem(node);
|
|
458
|
+
if (!mi || mi.relevant) {
|
|
459
|
+
return true;
|
|
460
|
+
}
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
*/
|
|
464
|
+
|
|
465
|
+
_handleError() {
|
|
466
|
+
// this.dispatch('submit-error', {});
|
|
467
|
+
Fore.dispatch(this, 'submit-error', {});
|
|
468
|
+
/*
|
|
469
|
+
console.log('ERRRORRRRR');
|
|
470
|
+
this.dispatchEvent(
|
|
471
|
+
new CustomEvent('submit-error', {
|
|
472
|
+
composed: true,
|
|
473
|
+
bubbles: true,
|
|
474
|
+
detail: {},
|
|
475
|
+
}),
|
|
476
|
+
);
|
|
477
|
+
*/
|
|
478
|
+
}
|
|
462
479
|
}
|
|
480
|
+
|
|
463
481
|
if (!customElements.get('fx-submission')) {
|
|
464
|
-
|
|
482
|
+
customElements.define('fx-submission', FxSubmission);
|
|
465
483
|
}
|