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