jsf.js_next_gen 4.0.0-RC.29 → 4.0.0-RC.30
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/window/faces-development.js +132 -155
- package/dist/window/faces-development.js.br +0 -0
- package/dist/window/faces-development.js.gz +0 -0
- package/dist/window/faces-development.js.map +1 -1
- package/dist/window/faces.js +1 -1
- package/dist/window/faces.js.br +0 -0
- package/dist/window/faces.js.gz +0 -0
- package/dist/window/faces.js.map +1 -1
- package/dist/window/jsf-development.js +132 -155
- package/dist/window/jsf-development.js.br +0 -0
- package/dist/window/jsf-development.js.gz +0 -0
- package/dist/window/jsf-development.js.map +1 -1
- package/dist/window/jsf.js +1 -1
- package/dist/window/jsf.js.br +0 -0
- package/dist/window/jsf.js.gz +0 -0
- package/dist/window/jsf.js.map +1 -1
- package/package.json +1 -1
- package/src/main/typescript/impl/AjaxImpl.ts +6 -2
- package/src/main/typescript/impl/util/URLCodec.ts +71 -0
- package/src/main/typescript/impl/xhrCore/RequestDataResolver.ts +1 -1
- package/src/main/typescript/impl/xhrCore/XhrFormData.ts +52 -165
- package/src/main/typescript/impl/xhrCore/XhrRequest.ts +4 -8
- package/src/main/typescript/test/xhrCore/RequestParamsTest.spec.ts +12 -6
- package/src/main/typescript/test/xhrCore/XhrFormDataTest.spec.ts +67 -50
- package/src/test/resources/jsf-development.js +1 -1
- package/target/impl/AjaxImpl.js +6 -3
- package/target/impl/AjaxImpl.js.map +1 -1
- package/target/impl/util/URLCodec.js +69 -0
- package/target/impl/util/URLCodec.js.map +1 -0
- package/target/impl/xhrCore/RequestDataResolver.js +1 -1
- package/target/impl/xhrCore/RequestDataResolver.js.map +1 -1
- package/target/impl/xhrCore/XhrFormData.js +44 -148
- package/target/impl/xhrCore/XhrFormData.js.map +1 -1
- package/target/impl/xhrCore/XhrRequest.js +3 -3
- package/target/impl/xhrCore/XhrRequest.js.map +1 -1
- package/target/test/xhrCore/RequestParamsTest.spec.js +10 -5
- package/target/test/xhrCore/RequestParamsTest.spec.js.map +1 -1
- package/target/test/xhrCore/XhrFormDataTest.spec.js +56 -34
- package/target/test/xhrCore/XhrFormDataTest.spec.js.map +1 -1
package/package.json
CHANGED
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
resolveForm,
|
|
64
64
|
resolveTimeout, resolveViewId, resolveViewRootId, resoveNamingContainerMapper
|
|
65
65
|
} from "./xhrCore/RequestDataResolver";
|
|
66
|
+
import {encodeFormData} from "./util/URLCodec";
|
|
66
67
|
|
|
67
68
|
/*
|
|
68
69
|
* allowed project stages
|
|
@@ -530,11 +531,14 @@ export module Implementation {
|
|
|
530
531
|
throw new Error(getMessage("ERR_VIEWSTATE"));
|
|
531
532
|
}
|
|
532
533
|
|
|
534
|
+
// determine the naming container scenario
|
|
533
535
|
const dummyContext = new Config({});
|
|
534
536
|
assignNamingContainerData(dummyContext, DQ.byId(form))
|
|
537
|
+
// fetch all non file input form elements
|
|
538
|
+
let formElements = element.deepElements.encodeFormElement()
|
|
535
539
|
|
|
536
|
-
|
|
537
|
-
return
|
|
540
|
+
// encode them! (file inputs are handled differently and are not part of the viewstate)
|
|
541
|
+
return encodeFormData(formElements, resoveNamingContainerMapper(dummyContext));
|
|
538
542
|
}
|
|
539
543
|
|
|
540
544
|
/**
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {ArrayCollector, Config, LazyStream, Stream} from "mona-dish";
|
|
2
|
+
import {ExtConfig, ExtDomQuery} from "./ExtDomQuery";
|
|
3
|
+
import {EMPTY_STR} from "../core/Const";
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* various routines for encoding and decoding url parameters
|
|
7
|
+
* into configs and vice versa
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* merges a list of key value entries into a target config
|
|
12
|
+
* @param target the target receiving the key value entries
|
|
13
|
+
* @param keyValueEntries a list of key value entries divided by =
|
|
14
|
+
* @param paramsMapper a key value remapper
|
|
15
|
+
*/
|
|
16
|
+
export function mergeKeyValueEntries(target: Config, keyValueEntries: string[], paramsMapper = (key, value) => [key, value]) {
|
|
17
|
+
|
|
18
|
+
function splitToKeyVal(line: string) {
|
|
19
|
+
return line.split(/=(.*)/gi);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function fixKeyWithoutVal(keyVal: string[]) {
|
|
23
|
+
return keyVal.length < 3 ? [keyVal?.[0] ?? [], keyVal?.[1] ?? []] : keyVal;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let toMerge = new ExtConfig({});
|
|
27
|
+
Stream.of(...keyValueEntries)
|
|
28
|
+
.map(line => splitToKeyVal(line))
|
|
29
|
+
//special case of having keys without values
|
|
30
|
+
.map(keyVal => fixKeyWithoutVal(keyVal))
|
|
31
|
+
.map(keyVal => paramsMapper(keyVal[0] as string, keyVal[1]))
|
|
32
|
+
.each(keyVal => {
|
|
33
|
+
toMerge.append(keyVal[0] as string).value = keyVal?.splice(1)?.join("") ?? "";
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
target.shallowMerge(toMerge);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* encodes a given form data into a url encoded string
|
|
41
|
+
* @param formData the form data config object
|
|
42
|
+
* @param paramsMapper the params mapper
|
|
43
|
+
* @param defaultStr a default string if nothing comes out of it
|
|
44
|
+
*/
|
|
45
|
+
export function encodeFormData(formData: Config,
|
|
46
|
+
paramsMapper = (inStr, inVal) => [inStr, inVal],
|
|
47
|
+
defaultStr = EMPTY_STR): string {
|
|
48
|
+
if (formData.isAbsent()) {
|
|
49
|
+
return defaultStr;
|
|
50
|
+
}
|
|
51
|
+
let assocValues = formData.value;
|
|
52
|
+
let entries = LazyStream.of(...Object.keys(assocValues))
|
|
53
|
+
.filter(key => assocValues.hasOwnProperty(key))
|
|
54
|
+
.flatMap(key => Stream.of(...assocValues[key]).map(val => paramsMapper(key, val)))
|
|
55
|
+
//we cannot encode file elements that is handled by multipart requests anyway
|
|
56
|
+
.filter(([, value]) => !(value instanceof ExtDomQuery.global().File))
|
|
57
|
+
.map(keyVal => `${encodeURIComponent(keyVal[0])}=${encodeURIComponent(keyVal[1])}`)
|
|
58
|
+
.collect(new ArrayCollector());
|
|
59
|
+
|
|
60
|
+
return entries.join("&")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* splits and decodes encoded values into strings containing of key=value
|
|
65
|
+
* @param encoded encoded string
|
|
66
|
+
*/
|
|
67
|
+
export function decodeEncodedValues(encoded: string): string[] {
|
|
68
|
+
return decodeURIComponent(encoded).split(/&/gi)
|
|
69
|
+
.filter(item => !!(item || '')
|
|
70
|
+
.replace(/\s+/g, ''));
|
|
71
|
+
}
|
|
@@ -108,7 +108,7 @@ export function resolveViewRootId(form: DQ): string {
|
|
|
108
108
|
export function resoveNamingContainerMapper(internalContext: Config): (key: string, value: any) => [string, any] {
|
|
109
109
|
const isNamedViewRoot = internalContext.getIf(NAMED_VIEWROOT).isPresent();
|
|
110
110
|
if(!isNamedViewRoot) {
|
|
111
|
-
return;
|
|
111
|
+
return (key, value) => [key, value];
|
|
112
112
|
}
|
|
113
113
|
const partialId = internalContext.getIf(NAMING_CONTAINER_ID).value;
|
|
114
114
|
const SEP = $faces().separatorchar;
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
17
|
-
import {$nsp, EMPTY_STR, IDENT_ALL, IDENT_FORM, P_VIEWSTATE} from "../core/Const";
|
|
18
|
-
import
|
|
19
|
-
import {
|
|
16
|
+
import {Config, DQ, LazyStream, Stream} from "mona-dish";
|
|
17
|
+
import {$faces, $nsp, EMPTY_STR, IDENT_ALL, IDENT_FORM, P_VIEWSTATE} from "../core/Const";
|
|
18
|
+
import {ExtConfig} from "../util/ExtDomQuery";
|
|
19
|
+
import {decodeEncodedValues, encodeFormData, mergeKeyValueEntries} from "../util/URLCodec";
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
type ParamsMapper<V, K> = (key: V, item: K) => [V, K];
|
|
@@ -48,31 +48,22 @@ export class XhrFormData extends Config {
|
|
|
48
48
|
* data collector from a given form
|
|
49
49
|
*
|
|
50
50
|
* @param dataSource either a form as DomQuery object or an encoded url string
|
|
51
|
-
* @param
|
|
51
|
+
* @param paramsMapper a remapper for the params keys and values
|
|
52
52
|
* @param executes the executes id list for the elements to being processed
|
|
53
53
|
* @param partialIds partial ids to collect, to reduce the data sent down
|
|
54
54
|
*/
|
|
55
|
-
constructor(private dataSource: DQ
|
|
55
|
+
constructor(private dataSource: DQ, private paramsMapper: ParamsMapper<string, any> = defaultParamsMapper, executes?: string[], private partialIds?: string[]) {
|
|
56
56
|
super({});
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
this.applyFormDataToConfig();
|
|
68
|
-
}
|
|
69
|
-
//now assign the external viewstate overrides
|
|
70
|
-
if ('undefined' != typeof viewState) {
|
|
71
|
-
this.assignEncodedString(viewState)
|
|
72
|
-
}
|
|
73
|
-
if (executes) {
|
|
74
|
-
this.postInit(...executes);
|
|
75
|
-
}
|
|
57
|
+
//encode and append the issuing item if not a partial ids array of ids is passed
|
|
58
|
+
/*
|
|
59
|
+
* Spec. 13.3.1
|
|
60
|
+
* Collect and encode input elements.
|
|
61
|
+
* Additionally the hidden element jakarta.faces.ViewState
|
|
62
|
+
* Enhancement partial page submit
|
|
63
|
+
*/
|
|
64
|
+
this.encodeSubmittableFields(this, this.dataSource, this.partialIds);
|
|
65
|
+
this.applyViewState(this.dataSource);
|
|
66
|
+
this.resolveRequestType(executes);
|
|
76
67
|
}
|
|
77
68
|
|
|
78
69
|
/**
|
|
@@ -80,29 +71,28 @@ export class XhrFormData extends Config {
|
|
|
80
71
|
* @param executes the executable dom nodes which need to be processed into the form data, which we can send
|
|
81
72
|
* in our ajax request
|
|
82
73
|
*/
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
74
|
+
resolveRequestType(executes?: Array<string>) {
|
|
75
|
+
if (!executes) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
let isMultiPartContainer = (id: string): boolean => {
|
|
86
79
|
if (id == IDENT_ALL) {
|
|
87
|
-
|
|
80
|
+
let namingContainer = this.remapKeyForNamingContainer("");
|
|
81
|
+
if (namingContainer.length) {
|
|
82
|
+
namingContainer = namingContainer.substring(0, namingContainer.length - 1);
|
|
83
|
+
return DQ.byId(namingContainer).isMultipartCandidate();
|
|
84
|
+
}
|
|
85
|
+
return DQ.byId(document.body).isMultipartCandidate();
|
|
88
86
|
} else if (id == IDENT_FORM) {
|
|
89
|
-
return
|
|
90
|
-
(<DQ>this.dataSource) :
|
|
91
|
-
(<DQ>this.dataSource).querySelectorAllDeep(INPUT_FILE);
|
|
87
|
+
return this.dataSource.isMultipartCandidate(true);
|
|
92
88
|
} else {
|
|
93
|
-
|
|
94
|
-
return element.
|
|
89
|
+
const element = DQ.byId(id, true);
|
|
90
|
+
return element.isMultipartCandidate();
|
|
95
91
|
}
|
|
96
92
|
};
|
|
97
93
|
|
|
98
|
-
let inputExists = (item: DQ) => {
|
|
99
|
-
return item.isPresent();
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
|
|
103
94
|
this.isMultipartRequest = LazyStream.of(...executes)
|
|
104
|
-
.
|
|
105
|
-
.filter(inputExists)
|
|
95
|
+
.filter(isMultiPartContainer)
|
|
106
96
|
.first().isPresent();
|
|
107
97
|
}
|
|
108
98
|
|
|
@@ -112,54 +102,16 @@ export class XhrFormData extends Config {
|
|
|
112
102
|
* @param form the form holding the view state value
|
|
113
103
|
*/
|
|
114
104
|
private applyViewState(form: DQ) {
|
|
105
|
+
if (this.getIf($nsp(P_VIEWSTATE)).isPresent()) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
115
108
|
let viewStateElement = form.querySelectorAllDeep(`[name*='${$nsp(P_VIEWSTATE)}'`);
|
|
116
109
|
let viewState = viewStateElement.inputValue;
|
|
117
|
-
// this.appendIf(viewState.isPresent(), P_VIEWSTATE).value = viewState.value;
|
|
118
110
|
this.appendIf(viewState.isPresent(), this.remapKeyForNamingContainer(viewStateElement.name.value)).value = viewState.value;
|
|
119
111
|
}
|
|
120
112
|
|
|
121
|
-
/**
|
|
122
|
-
* assigns an url encoded string to this xhrFormData object
|
|
123
|
-
* as key value entry
|
|
124
|
-
* @param encoded
|
|
125
|
-
*/
|
|
126
|
-
assignEncodedString(encoded: string) {
|
|
127
|
-
// this code filters out empty strings as key value pairs
|
|
128
|
-
let keyValueEntries = decodeURIComponent(encoded).split(/&/gi)
|
|
129
|
-
.filter(item => !!(item || '')
|
|
130
|
-
.replace(/\s+/g, ''));
|
|
131
|
-
this.assignString(keyValueEntries);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* assign a set of key value pairs passed as array ['key=val1', 'key2=val2']
|
|
136
|
-
* @param keyValueEntries
|
|
137
|
-
*/
|
|
138
|
-
assignString(keyValueEntries: string[]) {
|
|
139
|
-
let toMerge = new ExtConfig({});
|
|
140
|
-
|
|
141
|
-
function splitToKeyVal(line: string) {
|
|
142
|
-
return line.split(/=(.*)/gi);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function fixKeyWithoutVal(keyVal: string[]) {
|
|
146
|
-
return keyVal.length < 3 ? [keyVal?.[0] ?? [], keyVal?.[1] ?? []] : keyVal;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
Stream.of(...keyValueEntries)
|
|
150
|
-
.map(line => splitToKeyVal(line))
|
|
151
|
-
//special case of having keys without values
|
|
152
|
-
.map(keyVal => fixKeyWithoutVal(keyVal))
|
|
153
|
-
.map(keyVal => this.paramsMapper(keyVal[0] as string, keyVal[1]))
|
|
154
|
-
.each(keyVal => {
|
|
155
|
-
toMerge.append(keyVal[0] as string).value = keyVal?.splice(1)?.join("") ?? "";
|
|
156
|
-
});
|
|
157
|
-
//merge with overwrite but no append! (aka no double entries are allowed)
|
|
158
|
-
this.shallowMerge(toMerge);
|
|
159
|
-
}
|
|
160
113
|
|
|
161
114
|
/**
|
|
162
|
-
* @param paramsMapper ... pre encode the params if needed, default is to map them 1:1
|
|
163
115
|
* @returns a Form data representation, this is needed for file submits
|
|
164
116
|
*/
|
|
165
117
|
toFormData(): FormData {
|
|
@@ -168,66 +120,15 @@ export class XhrFormData extends Config {
|
|
|
168
120
|
return ret;
|
|
169
121
|
}
|
|
170
122
|
|
|
171
|
-
resolveSubmitIdentifier(elem: HTMLInputElement) {
|
|
172
|
-
let identifier = elem.name;
|
|
173
|
-
identifier = ((elem?.name ?? "").replace(/s+/gi, "") == "") ? elem.id : identifier;
|
|
174
|
-
return identifier;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
123
|
/**
|
|
178
124
|
* returns an encoded string representation of our xhr form data
|
|
179
125
|
*
|
|
180
126
|
* @param defaultStr optional default value if nothing is there to encode
|
|
181
127
|
*/
|
|
182
|
-
toString(
|
|
183
|
-
|
|
184
|
-
return defaultStr;
|
|
185
|
-
}
|
|
186
|
-
let entries = LazyStream.of(...Object.keys(this.value))
|
|
187
|
-
.filter(key => this.value.hasOwnProperty(key))
|
|
188
|
-
.flatMap(key => Stream.of(...this.value[key]).map(val => this.paramsMapper(key, val)))
|
|
189
|
-
//we cannot encode file elements that is handled by multipart requests anyway
|
|
190
|
-
.filter(([, value]) => !(value instanceof ExtDomQuery.global().File))
|
|
191
|
-
.map(keyVal => `${encodeURIComponent(keyVal[0])}=${encodeURIComponent(keyVal[1])}`)
|
|
192
|
-
.collect(new ArrayCollector());
|
|
193
|
-
|
|
194
|
-
return entries.join("&")
|
|
128
|
+
toString(defaultStr = EMPTY_STR): string {
|
|
129
|
+
return encodeFormData(this, this.paramsMapper, defaultStr);
|
|
195
130
|
}
|
|
196
131
|
|
|
197
|
-
/**
|
|
198
|
-
* helper to fetch all file inputs from as given root element
|
|
199
|
-
* @param rootElement
|
|
200
|
-
* @private
|
|
201
|
-
*/
|
|
202
|
-
private getFileInputs(rootElement: DQ): DQ {
|
|
203
|
-
const rootFileInputs = rootElement
|
|
204
|
-
.filter(elem => elem.matchesSelector("input[type='file']"))
|
|
205
|
-
const childFileInputs = rootElement
|
|
206
|
-
.querySelectorAll("input[type='file']");
|
|
207
|
-
|
|
208
|
-
return rootFileInputs.concat(childFileInputs);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* encode the given fields and apply the view state
|
|
213
|
-
* @private
|
|
214
|
-
*/
|
|
215
|
-
private applyFormDataToConfig() {
|
|
216
|
-
//encode and append the issuing item if not a partial ids array of ids is passed
|
|
217
|
-
/*
|
|
218
|
-
* Spec. 13.3.1
|
|
219
|
-
* Collect and encode input elements.
|
|
220
|
-
* Additionally the hidden element jakarta.faces.ViewState
|
|
221
|
-
* Enhancement partial page submit
|
|
222
|
-
*
|
|
223
|
-
*/
|
|
224
|
-
this.encodeSubmittableFields(this, <DQ>this.dataSource, this.partialIds);
|
|
225
|
-
if (this.getIf($nsp(P_VIEWSTATE)).isPresent()) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
this.applyViewState(<DQ>this.dataSource);
|
|
230
|
-
}
|
|
231
132
|
|
|
232
133
|
/**
|
|
233
134
|
* determines fields to submit
|
|
@@ -235,34 +136,16 @@ export class XhrFormData extends Config {
|
|
|
235
136
|
* @param {Node} parentItem - form element item is nested in
|
|
236
137
|
* @param {Array} partialIds - ids fo PPS
|
|
237
138
|
*/
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (parentItem.isAbsent()) throw 'NO_PAR_ITEM';
|
|
249
|
-
toEncode = parentItem;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
//lets encode the form elements
|
|
253
|
-
let formElements = toEncode.deepElements.encodeFormElement();
|
|
254
|
-
const mapped = this.remapKeysForNamingCoontainer(formElements);
|
|
255
|
-
this.shallowMerge(mapped);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
private remapKeysForNamingCoontainer(formElements: Config): Config {
|
|
259
|
-
let ret = new Config({});
|
|
260
|
-
formElements.stream.map(([key, item]) => this.paramsMapper(key, item))
|
|
261
|
-
.each( ([key, item]) => {
|
|
262
|
-
ret.assign(key).value = item;
|
|
263
|
-
});
|
|
264
|
-
return ret;
|
|
265
|
-
|
|
139
|
+
public encodeSubmittableFields(targetBuf: Config,
|
|
140
|
+
parentItem: DQ, partialIds ?: string[]) {
|
|
141
|
+
//encoded String
|
|
142
|
+
let viewStateStr = $faces().getViewState(parentItem.getAsElem(0).value);
|
|
143
|
+
// we now need to decode it and then merge it into the target buf
|
|
144
|
+
// which hosts already our overrides (aka do not override what is already there(
|
|
145
|
+
// after that we need to deal with form elements on a separate level
|
|
146
|
+
let target = new ExtConfig({});
|
|
147
|
+
mergeKeyValueEntries(target, decodeEncodedValues(viewStateStr), this.paramsMapper);
|
|
148
|
+
this.shallowMerge(target);
|
|
266
149
|
}
|
|
267
150
|
|
|
268
151
|
private remapKeyForNamingContainer(key: string): string {
|
|
@@ -271,10 +154,14 @@ export class XhrFormData extends Config {
|
|
|
271
154
|
|
|
272
155
|
private appendInputs(ret: any) {
|
|
273
156
|
Stream.ofAssoc(this.value)
|
|
274
|
-
.flatMap(([key, item])
|
|
157
|
+
.flatMap(([key, item]) =>
|
|
275
158
|
Stream.of(...(item as Array<any>)).map(item => {
|
|
276
159
|
return {key, item};
|
|
277
|
-
|
|
160
|
+
}))
|
|
161
|
+
.map(({key, item}) => {
|
|
162
|
+
key = this.remapKeyForNamingContainer(key);
|
|
163
|
+
return {key, item}
|
|
164
|
+
})
|
|
278
165
|
.each(({key, item}) => ret.append(key, item))
|
|
279
166
|
}
|
|
280
167
|
}
|
|
@@ -123,9 +123,6 @@ export class XhrRequest implements AsyncRunnable<XMLHttpRequest> {
|
|
|
123
123
|
};
|
|
124
124
|
|
|
125
125
|
try {
|
|
126
|
-
let formElement = this.sourceForm.getAsElem(0).value;
|
|
127
|
-
let viewState = $faces().getViewState(formElement);
|
|
128
|
-
|
|
129
126
|
// encoded we need to decode
|
|
130
127
|
// We generated a base representation of the current form
|
|
131
128
|
// in case someone has overloaded the viewState with additional decorators we merge
|
|
@@ -135,7 +132,7 @@ export class XhrRequest implements AsyncRunnable<XMLHttpRequest> {
|
|
|
135
132
|
// the partialIdsArray arr is almost deprecated legacy code where we allowed to send a separate list of partial
|
|
136
133
|
// ids for reduced load and server processing, this will be removed soon, we can handle the same via execute
|
|
137
134
|
// anyway TODO remove the partial ids array
|
|
138
|
-
let formData: XhrFormData = new XhrFormData(this.sourceForm, resoveNamingContainerMapper(this.internalContext),
|
|
135
|
+
let formData: XhrFormData = new XhrFormData(this.sourceForm, resoveNamingContainerMapper(this.internalContext), executesArr(), this.partialIdsArray);
|
|
139
136
|
|
|
140
137
|
this.contentType = formData.isMultipartRequest ? "undefined" : this.contentType;
|
|
141
138
|
|
|
@@ -143,11 +140,13 @@ export class XhrRequest implements AsyncRunnable<XMLHttpRequest> {
|
|
|
143
140
|
this.requestContext.$nspEnabled = false;
|
|
144
141
|
let requestContext = this.requestContext;
|
|
145
142
|
let requestPassThroughParams = requestContext.getIf(CTX_PARAM_REQ_PASS_THR) as ExtConfig;
|
|
143
|
+
|
|
144
|
+
// we are turning off here the jsf, faces remapping because we are now dealing with
|
|
145
|
+
// pass-through parameters
|
|
146
146
|
requestPassThroughParams.$nspEnabled = false;
|
|
147
147
|
// this is an extension where we allow pass through parameters to be sent down additionally
|
|
148
148
|
// this can be used and is used in the impl to enrich the post request parameters with additional
|
|
149
149
|
// information
|
|
150
|
-
|
|
151
150
|
try {
|
|
152
151
|
formData.shallowMerge(requestPassThroughParams, true, true);
|
|
153
152
|
} finally {
|
|
@@ -185,11 +184,8 @@ export class XhrRequest implements AsyncRunnable<XMLHttpRequest> {
|
|
|
185
184
|
// setting, they accept headers automatically
|
|
186
185
|
ignoreErr(() => xhrObject.setRequestHeader(REQ_ACCEPT, STD_ACCEPT));
|
|
187
186
|
|
|
188
|
-
|
|
189
|
-
|
|
190
187
|
this.sendEvent(BEGIN);
|
|
191
188
|
this.sendRequest(formData);
|
|
192
|
-
|
|
193
189
|
} catch (e) {
|
|
194
190
|
// _onError
|
|
195
191
|
this.handleError(e);
|
|
@@ -18,13 +18,20 @@ import {Implementation} from "../../impl/AjaxImpl";
|
|
|
18
18
|
import {StandardInits} from "../frameworkBase/_ext/shared/StandardInits";
|
|
19
19
|
|
|
20
20
|
import protocolPage = StandardInits.protocolPage;
|
|
21
|
-
import {DQ} from "mona-dish";
|
|
21
|
+
import {Config, DQ} from "mona-dish";
|
|
22
22
|
import {XhrFormData} from "../../impl/xhrCore/XhrFormData";
|
|
23
23
|
import {expect} from "chai";
|
|
24
24
|
import prefixPage = StandardInits.prefixEmbeddedPage;
|
|
25
25
|
import prefixEmbeddedPage = StandardInits.prefixEmbeddedPage;
|
|
26
26
|
import HTML_PREFIX_EMBEDDED_BODY = StandardInits.HTML_PREFIX_EMBEDDED_BODY;
|
|
27
27
|
import {it} from "mocha";
|
|
28
|
+
import {decodeEncodedValues, mergeKeyValueEntries} from "../../impl/util/URLCodec";
|
|
29
|
+
|
|
30
|
+
function getFormData(requestBody: string): Config {
|
|
31
|
+
let ret = new Config({});
|
|
32
|
+
mergeKeyValueEntries(ret, decodeEncodedValues(requestBody));
|
|
33
|
+
return ret;
|
|
34
|
+
}
|
|
28
35
|
|
|
29
36
|
describe("test for proper request param patterns identical to the old implementation", function () {
|
|
30
37
|
const UPDATE_INSERT_2 = {
|
|
@@ -85,10 +92,9 @@ describe("test for proper request param patterns identical to the old implementa
|
|
|
85
92
|
DQ.byId("cmd_update_insert2").click();
|
|
86
93
|
|
|
87
94
|
let requestBody = this.requests[0].requestBody;
|
|
88
|
-
let formData =
|
|
95
|
+
let formData = getFormData(requestBody);
|
|
89
96
|
|
|
90
97
|
expect(matches(formData.value, UPDATE_INSERT_2)).to.be.true;
|
|
91
|
-
|
|
92
98
|
});
|
|
93
99
|
|
|
94
100
|
|
|
@@ -98,7 +104,7 @@ describe("test for proper request param patterns identical to the old implementa
|
|
|
98
104
|
DQ.byId("cmd_update_insert2").click();
|
|
99
105
|
let requestBody = this.requests[0].requestBody;
|
|
100
106
|
//We check if the base64 encoded string matches the original
|
|
101
|
-
let formData =
|
|
107
|
+
let formData = getFormData(requestBody);
|
|
102
108
|
|
|
103
109
|
expect(decodeURIComponent(formData.getIf("jakarta.faces.ViewState").value) == probe).to.be.true;
|
|
104
110
|
});
|
|
@@ -110,7 +116,7 @@ describe("test for proper request param patterns identical to the old implementa
|
|
|
110
116
|
DQ.byId("cmd_update_insert2").click();
|
|
111
117
|
let requestBody = this.requests[0].requestBody;
|
|
112
118
|
//We check if the base64 encoded string matches the original
|
|
113
|
-
let formData =
|
|
119
|
+
let formData = getFormData(requestBody);
|
|
114
120
|
|
|
115
121
|
expect(decodeURIComponent(formData.getIf("jakarta.faces.ViewState").value) == probe).to.be.true;
|
|
116
122
|
});
|
|
@@ -123,7 +129,7 @@ describe("test for proper request param patterns identical to the old implementa
|
|
|
123
129
|
DQ.byId("cmd_update_insert2").click();
|
|
124
130
|
let requestBody = this.requests[0].requestBody;
|
|
125
131
|
//We check if the base64 encoded string matches the original
|
|
126
|
-
let formData =
|
|
132
|
+
let formData = getFormData(requestBody);
|
|
127
133
|
|
|
128
134
|
expect(decodeURIComponent(formData.getIf("jakarta.faces.ViewState").value) == probe).to.be.true;
|
|
129
135
|
});
|
|
@@ -19,58 +19,75 @@ import {DQ} from "mona-dish";
|
|
|
19
19
|
import * as sinon from 'sinon';
|
|
20
20
|
import {XhrFormData} from "../../impl/xhrCore/XhrFormData";
|
|
21
21
|
import {expect} from "chai";
|
|
22
|
+
import {StandardInits} from "../frameworkBase/_ext/shared/StandardInits";
|
|
23
|
+
import defaultMyFaces = StandardInits.defaultMyFaces;
|
|
24
|
+
import {Implementation} from "../../impl/AjaxImpl";
|
|
22
25
|
|
|
23
26
|
const jsdom = require("jsdom");
|
|
24
27
|
const {JSDOM} = jsdom;
|
|
25
28
|
|
|
26
29
|
describe('XhrFormData tests', function () {
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
31
|
+
beforeEach(async function () {
|
|
32
|
+
|
|
33
|
+
let waitForResult = defaultMyFaces();
|
|
34
|
+
|
|
35
|
+
return waitForResult.then((close) => {
|
|
36
|
+
|
|
37
|
+
this.xhr = sinon.useFakeXMLHttpRequest();
|
|
38
|
+
this.requests = [];
|
|
39
|
+
this.xhr.onCreate = (xhr) => {
|
|
40
|
+
this.requests.push(xhr);
|
|
41
|
+
};
|
|
42
|
+
(<any>global).XMLHttpRequest = this.xhr;
|
|
43
|
+
window.XMLHttpRequest = this.xhr;
|
|
44
|
+
|
|
45
|
+
this.jsfAjaxResponse = sinon.spy((<any>global).faces.ajax, "response");
|
|
46
|
+
|
|
47
|
+
this.closeIt = () => {
|
|
48
|
+
(<any>global).XMLHttpRequest = window.XMLHttpRequest = this.xhr.restore();
|
|
49
|
+
this.jsfAjaxResponse.restore();
|
|
50
|
+
Implementation.reset();
|
|
51
|
+
close();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
48
54
|
});
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
56
|
+
beforeEach(function () {
|
|
57
|
+
|
|
58
|
+
let waitForResult = defaultMyFaces();
|
|
59
|
+
|
|
60
|
+
return waitForResult.then((close) => {
|
|
61
|
+
(<any>global).window = window;
|
|
62
|
+
(<any>global).body = window.document.body;
|
|
63
|
+
(<any>global).document = window.document;
|
|
64
|
+
global.body.innerHTML = `
|
|
65
|
+
<div id="id_1"></div>
|
|
66
|
+
<div id="id_2" booga="blarg"></div>
|
|
67
|
+
<div id="id_3"></div>
|
|
68
|
+
<div id="id_4"></div>
|
|
69
|
+
`;
|
|
70
|
+
(<any>global).navigator = {
|
|
71
|
+
language: "en-En"
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
this.xhr = sinon.useFakeXMLHttpRequest();
|
|
75
|
+
this.requests = [];
|
|
76
|
+
this.xhr.onCreate = (xhr) => {
|
|
77
|
+
this.requests.push(xhr);
|
|
78
|
+
};
|
|
79
|
+
(<any>global).XMLHttpRequest = this.xhr;
|
|
80
|
+
window.XMLHttpRequest = this.xhr;
|
|
81
|
+
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
this.afterEach(function () {
|
|
85
|
+
(<any>global).XMLHttpRequest = window.XMLHttpRequest = this.xhr.restore();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("must have multiple values for a name", function () {
|
|
90
|
+
window.document.body.innerHTML = `<form id="page::form">
|
|
74
91
|
<tobago-select-many-checkbox id="page:animals">
|
|
75
92
|
<label for="page:animals">Checkbox Group</label>
|
|
76
93
|
<label><input type="checkbox" name="page:animals" id="page:animals::0" value="Cat" checked="checked">Cat</label>
|
|
@@ -84,11 +101,11 @@ describe('XhrFormData tests', function () {
|
|
|
84
101
|
</div>
|
|
85
102
|
</form>`;
|
|
86
103
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
global.debugf2 = true;
|
|
105
|
+
const xhrFormData = new XhrFormData(DQ.byId("page::form"));
|
|
106
|
+
const formData = xhrFormData.toString();
|
|
90
107
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
108
|
+
expect(formData).to.contain("animals=Cat");
|
|
109
|
+
expect(formData).to.contain("animals=Fox");
|
|
110
|
+
});
|
|
94
111
|
});
|
|
@@ -3121,7 +3121,7 @@ var XhrFormData = /** @class */ (function (_super) {
|
|
|
3121
3121
|
*/
|
|
3122
3122
|
XhrFormData.prototype.assignEncodedString = function (encoded) {
|
|
3123
3123
|
var keyValueEntries = decodeURIComponent(encoded).split(/&/gi);
|
|
3124
|
-
this.
|
|
3124
|
+
this.assignKeyValueEntries(keyValueEntries);
|
|
3125
3125
|
};
|
|
3126
3126
|
XhrFormData.prototype.assignString = function (keyValueEntries) {
|
|
3127
3127
|
var toMerge = new mona_dish_1.Config({});
|