jsf.js_next_gen 4.0.0-RC.3 → 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.
Files changed (183) hide show
  1. package/dist/docs/assets/main.js +56 -52
  2. package/dist/docs/assets/style.css +23 -0
  3. package/dist/window/faces-development.js +2860 -2999
  4. package/dist/window/faces-development.js.br +0 -0
  5. package/dist/window/faces-development.js.gz +0 -0
  6. package/dist/window/faces-development.js.map +1 -1
  7. package/dist/window/faces.js +1 -1
  8. package/dist/window/faces.js.LICENSE.txt +0 -2
  9. package/dist/window/faces.js.br +0 -0
  10. package/dist/window/faces.js.gz +0 -0
  11. package/dist/window/faces.js.map +1 -1
  12. package/dist/window/jsf-development.js +2865 -3004
  13. package/dist/window/jsf-development.js.br +0 -0
  14. package/dist/window/jsf-development.js.gz +0 -0
  15. package/dist/window/jsf-development.js.map +1 -1
  16. package/dist/window/jsf.js +1 -1
  17. package/dist/window/jsf.js.LICENSE.txt +0 -2
  18. package/dist/window/jsf.js.br +0 -0
  19. package/dist/window/jsf.js.gz +0 -0
  20. package/dist/window/jsf.js.map +1 -1
  21. package/package.json +16 -16
  22. package/src/main/test.xml +23 -0
  23. package/src/main/typescript/@types/definitions/index.d.ts +12 -7
  24. package/src/main/typescript/api/_api.ts +4 -3
  25. package/src/main/typescript/impl/AjaxImpl.ts +125 -41
  26. package/src/main/typescript/impl/core/Const.ts +52 -41
  27. package/src/main/typescript/impl/util/Assertions.ts +16 -8
  28. package/src/main/typescript/impl/util/ExtDomQuery.ts +12 -4
  29. package/src/main/typescript/impl/util/HiddenInputBuilder.ts +89 -0
  30. package/src/main/typescript/impl/util/Lang.ts +9 -11
  31. package/src/main/typescript/impl/util/URLCodec.ts +71 -0
  32. package/src/main/typescript/impl/xhrCore/ErrorData.ts +15 -10
  33. package/src/main/typescript/impl/xhrCore/EventData.ts +2 -2
  34. package/src/main/typescript/impl/xhrCore/IResponseProcessor.ts +15 -1
  35. package/src/main/typescript/impl/xhrCore/RequestDataResolver.ts +69 -24
  36. package/src/main/typescript/impl/xhrCore/ResonseDataResolver.ts +4 -4
  37. package/src/main/typescript/impl/xhrCore/Response.ts +55 -38
  38. package/src/main/typescript/impl/xhrCore/ResponseProcessor.ts +173 -98
  39. package/src/main/typescript/impl/xhrCore/XhrFormData.ts +64 -158
  40. package/src/main/typescript/impl/xhrCore/XhrRequest.ts +36 -21
  41. package/src/main/typescript/myfaces/OamSubmit.ts +29 -13
  42. package/src/main/typescript/test/frameworkBase/_ext/monadish/DomQueryTest.spec.ts +1 -1
  43. package/src/main/typescript/test/frameworkBase/_ext/shared/StandardInits.ts +72 -0
  44. package/src/main/typescript/test/frameworkBase/_ext/shared/XmlResponses.ts +40 -1
  45. package/src/main/typescript/test/impl/ImplTest.spec.ts +3 -3
  46. package/src/main/typescript/test/impl/ImplTest_23.spec.ts +3 -3
  47. package/src/main/typescript/test/xhrCore/EventTests.spec.ts +1 -1
  48. package/src/main/typescript/test/xhrCore/FileUploadTest.spec.ts +2 -0
  49. package/src/main/typescript/test/xhrCore/NamespacesRequestTest.spec.ts +203 -0
  50. package/src/main/typescript/test/xhrCore/OamSubmitTest.spec.ts +177 -0
  51. package/src/main/typescript/test/xhrCore/RequestParamsTest.spec.ts +128 -15
  52. package/src/main/typescript/test/xhrCore/RequestTest.spec.ts +70 -3
  53. package/src/main/typescript/test/xhrCore/RequestTest_23.spec.ts +39 -3
  54. package/src/main/typescript/test/xhrCore/ResponseTest.spec.ts +372 -34
  55. package/src/main/typescript/test/xhrCore/ResponseTest23.spec.ts +43 -9
  56. package/src/main/typescript/test/xhrCore/XhrFormDataTest.spec.ts +67 -49
  57. package/src/main/typescript/test.xml +6 -0
  58. package/src/main/typescript/tsconfig.json +2 -2
  59. package/src/test/resources/jsf-development.js +1 -1
  60. package/src/tmp/test.html +12 -88
  61. package/target/api/_api.js +16 -29
  62. package/target/api/_api.js.map +1 -1
  63. package/target/api/faces.js +4 -4
  64. package/target/api/faces.js.map +1 -1
  65. package/target/api/jsf.js +9 -9
  66. package/target/api/jsf.js.map +1 -1
  67. package/target/classes/com/example/jsfs_js_ts/DecoratedFacesJS.class +0 -0
  68. package/target/classes/com/example/jsfs_js_ts/DecoratingResourceHandlerWrapper.class +0 -0
  69. package/target/classes/com/example/jsfs_js_ts/FacesJSMapFileResourceWrapper.class +0 -0
  70. package/target/classes/com/example/jsfs_js_ts/FacesJSMappingDecorator.class +0 -0
  71. package/target/impl/AjaxImpl.js +155 -89
  72. package/target/impl/AjaxImpl.js.map +1 -1
  73. package/target/impl/PushImpl.js +45 -48
  74. package/target/impl/PushImpl.js.map +1 -1
  75. package/target/impl/core/Const.js +52 -40
  76. package/target/impl/core/Const.js.map +1 -1
  77. package/target/impl/core/Context.js +10 -0
  78. package/target/impl/core/Context.js.map +1 -0
  79. package/target/impl/core/ImplTypes.js +9 -14
  80. package/target/impl/core/ImplTypes.js.map +1 -1
  81. package/target/impl/i18n/Messages.js +3 -4
  82. package/target/impl/i18n/Messages.js.map +1 -1
  83. package/target/impl/util/Assertions.js +20 -24
  84. package/target/impl/util/Assertions.js.map +1 -1
  85. package/target/impl/util/AsyncQueue.js +28 -36
  86. package/target/impl/util/AsyncQueue.js.map +1 -1
  87. package/target/impl/util/ExtDomQuery.js +153 -221
  88. package/target/impl/util/ExtDomQuery.js.map +1 -1
  89. package/target/impl/util/HiddenElementBuilder.js +7 -0
  90. package/target/impl/util/HiddenElementBuilder.js.map +1 -0
  91. package/target/impl/util/HiddenInputBuilder.js +79 -0
  92. package/target/impl/util/HiddenInputBuilder.js.map +1 -0
  93. package/target/impl/util/Lang.js +23 -32
  94. package/target/impl/util/Lang.js.map +1 -1
  95. package/target/impl/util/URLCodec.js +69 -0
  96. package/target/impl/util/URLCodec.js.map +1 -0
  97. package/target/impl/xhrCore/ErrorData.js +41 -64
  98. package/target/impl/xhrCore/ErrorData.js.map +1 -1
  99. package/target/impl/xhrCore/EventData.js +10 -13
  100. package/target/impl/xhrCore/EventData.js.map +1 -1
  101. package/target/impl/xhrCore/RequestContext.js +11 -0
  102. package/target/impl/xhrCore/RequestContext.js.map +1 -0
  103. package/target/impl/xhrCore/RequestDataResolver.js +71 -27
  104. package/target/impl/xhrCore/RequestDataResolver.js.map +1 -1
  105. package/target/impl/xhrCore/ResonseDataResolver.js +16 -16
  106. package/target/impl/xhrCore/ResonseDataResolver.js.map +1 -1
  107. package/target/impl/xhrCore/Response.js +43 -28
  108. package/target/impl/xhrCore/Response.js.map +1 -1
  109. package/target/impl/xhrCore/ResponseProcessor.js +217 -162
  110. package/target/impl/xhrCore/ResponseProcessor.js.map +1 -1
  111. package/target/impl/xhrCore/XhrFormData.js +77 -199
  112. package/target/impl/xhrCore/XhrFormData.js.map +1 -1
  113. package/target/impl/xhrCore/XhrRequest.js +102 -103
  114. package/target/impl/xhrCore/XhrRequest.js.map +1 -1
  115. package/target/myfaces/OamSubmit.js +33 -24
  116. package/target/myfaces/OamSubmit.js.map +1 -1
  117. package/target/test/frameworkBase/LangTest.spec.js +46 -32
  118. package/target/test/frameworkBase/LangTest.spec.js.map +1 -1
  119. package/target/test/frameworkBase/_ext/monadish/DomQueryTest.spec.js +238 -228
  120. package/target/test/frameworkBase/_ext/monadish/DomQueryTest.spec.js.map +1 -1
  121. package/target/test/frameworkBase/_ext/monadish/LangTest.spec.js +45 -31
  122. package/target/test/frameworkBase/_ext/monadish/LangTest.spec.js.map +1 -1
  123. package/target/test/frameworkBase/_ext/monadish/MappingProbes.js +24 -33
  124. package/target/test/frameworkBase/_ext/monadish/MappingProbes.js.map +1 -1
  125. package/target/test/frameworkBase/_ext/monadish/MappingTest.spec.js +8 -8
  126. package/target/test/frameworkBase/_ext/monadish/MappingTest.spec.js.map +1 -1
  127. package/target/test/frameworkBase/_ext/monadish/MonadTest.spec.js +31 -31
  128. package/target/test/frameworkBase/_ext/monadish/MonadTest.spec.js.map +1 -1
  129. package/target/test/frameworkBase/_ext/monadish/StreamTest.spec.js +50 -48
  130. package/target/test/frameworkBase/_ext/monadish/StreamTest.spec.js.map +1 -1
  131. package/target/test/frameworkBase/_ext/shared/StandardInits.js +310 -132
  132. package/target/test/frameworkBase/_ext/shared/StandardInits.js.map +1 -1
  133. package/target/test/frameworkBase/_ext/shared/XmlResponses.js +235 -22
  134. package/target/test/frameworkBase/_ext/shared/XmlResponses.js.map +1 -1
  135. package/target/test/impl/ImplTest.spec.js +32 -59
  136. package/target/test/impl/ImplTest.spec.js.map +1 -1
  137. package/target/test/impl/ImplTest_23.spec.js +32 -59
  138. package/target/test/impl/ImplTest_23.spec.js.map +1 -1
  139. package/target/test/impl/SeparatorCharsTest.spec.js +17 -17
  140. package/target/test/impl/SeparatorCharsTest.spec.js.map +1 -1
  141. package/target/test/myfaces/OamSubmit.spec.js +25 -25
  142. package/target/test/myfaces/OamSubmit.spec.js.map +1 -1
  143. package/target/test/queue/AsynchronousProbe.js +23 -29
  144. package/target/test/queue/AsynchronousProbe.js.map +1 -1
  145. package/target/test/queue/AsynchronousQueueTest.spec.js +39 -70
  146. package/target/test/queue/AsynchronousQueueTest.spec.js.map +1 -1
  147. package/target/test/xhrCore/EventTests.spec.js +43 -74
  148. package/target/test/xhrCore/EventTests.spec.js.map +1 -1
  149. package/target/test/xhrCore/FakeWebsocket.js +14 -16
  150. package/target/test/xhrCore/FakeWebsocket.js.map +1 -1
  151. package/target/test/xhrCore/FileUploadTest.spec.js +47 -77
  152. package/target/test/xhrCore/FileUploadTest.spec.js.map +1 -1
  153. package/target/test/xhrCore/NamespacesRequestTest.spec.js +204 -0
  154. package/target/test/xhrCore/NamespacesRequestTest.spec.js.map +1 -0
  155. package/target/test/xhrCore/OamSubmitTest.spec.js +180 -0
  156. package/target/test/xhrCore/OamSubmitTest.spec.js.map +1 -0
  157. package/target/test/xhrCore/RequestParamsTest.spec.js +143 -72
  158. package/target/test/xhrCore/RequestParamsTest.spec.js.map +1 -1
  159. package/target/test/xhrCore/RequestTest.spec.js +173 -149
  160. package/target/test/xhrCore/RequestTest.spec.js.map +1 -1
  161. package/target/test/xhrCore/RequestTest_23.spec.js +127 -142
  162. package/target/test/xhrCore/RequestTest_23.spec.js.map +1 -1
  163. package/target/test/xhrCore/ResponseTest.spec.js +415 -100
  164. package/target/test/xhrCore/ResponseTest.spec.js.map +1 -1
  165. package/target/test/xhrCore/ResponseTest23.spec.js +152 -91
  166. package/target/test/xhrCore/ResponseTest23.spec.js.map +1 -1
  167. package/target/test/xhrCore/ShadowDomTest.spec.js +30 -61
  168. package/target/test/xhrCore/ShadowDomTest.spec.js.map +1 -1
  169. package/target/test/xhrCore/WebsocketTest.js +60 -93
  170. package/target/test/xhrCore/WebsocketTest.js.map +1 -1
  171. package/target/test/xhrCore/XhrFormDataTest.spec.js +79 -30
  172. package/target/test/xhrCore/XhrFormDataTest.spec.js.map +1 -1
  173. package/target/test-classes/.gz +0 -0
  174. package/target/test-classes/com/example/jsfs_js_ts/JsfsJsTsApplicationTests.class +0 -0
  175. package/target/test-classes/fileuploadtest.html +24 -0
  176. package/target/test-classes/jsf-development.js +3559 -0
  177. package/target/test-classes/jsf-development.js.br +0 -0
  178. package/target/test-classes/jsf-development.js.gz +0 -0
  179. package/target/test-classes/jsf-development.js.map +1 -0
  180. package/target/test-classes/jsf.js +3 -0
  181. package/target/test-classes/jsf.js.br +0 -0
  182. package/target/test-classes/jsf.js.gz +0 -0
  183. package/tmp.xml +36 -0
@@ -16,9 +16,6 @@
16
16
  import {Config, Lang, XMLQuery} from "mona-dish";
17
17
 
18
18
  import {DQ} from "mona-dish";
19
- import {ExtLang} from "./Lang";
20
- import getMessage = ExtLang.getMessage;
21
- import makeException = ExtLang.makeException;
22
19
  import {
23
20
  ATTR_URL,
24
21
  EMPTY_RESPONSE,
@@ -26,8 +23,10 @@ import {
26
23
  ON_ERROR,
27
24
  ON_EVENT,
28
25
  PHASE_PROCESS_RESPONSE,
29
- RESP_PARTIAL
26
+ XML_TAG_PARTIAL_RESP
30
27
  } from "../core/Const";
28
+ import {ExtLang} from "./Lang";
29
+
31
30
 
32
31
  /**
33
32
  * a set of internal code assertions
@@ -36,6 +35,8 @@ import {
36
35
  */
37
36
  export module Assertions {
38
37
 
38
+
39
+
39
40
  export function assertRequestIntegrity(options: Config, elem: DQ): void | never {
40
41
  /*assert if the onerror is set and once if it is set it must be of type function*/
41
42
  assertFunction(options.getIf(ON_ERROR).value);
@@ -43,12 +44,12 @@ export module Assertions {
43
44
  assertFunction(options.getIf(ON_EVENT).value);
44
45
  //improve the error messages if an empty elem is passed
45
46
  //Assertions.assertElementExists(elem);
46
- assert(elem.isPresent(), getMessage("ERR_MUST_BE_PROVIDED1", "{0}: source must be provided or exist", "source element id"), "faces.ajax.request", "ArgNotSet", )
47
+ assert(elem.isPresent(), ExtLang.getMessage("ERR_MUST_BE_PROVIDED1", "{0}: source must be provided or exist", "source element id"), "faces.ajax.request", "ArgNotSet", )
47
48
  }
48
49
 
49
50
  export function assertUrlExists(node: XMLQuery): void | never {
50
51
  if (node.attr(ATTR_URL).isAbsent()) {
51
- throw Assertions.raiseError(new Error(), getMessage("ERR_RED_URL", null, "processRedirect"), "processRedirect");
52
+ throw Assertions.raiseError(new Error(), ExtLang.getMessage("ERR_RED_URL", null, "processRedirect"), "processRedirect");
52
53
  }
53
54
  }
54
55
 
@@ -59,7 +60,7 @@ export module Assertions {
59
60
  export function assertValidXMLResponse(responseXML: XMLQuery) : void | never {
60
61
  assert(!responseXML.isAbsent(), EMPTY_RESPONSE, PHASE_PROCESS_RESPONSE);
61
62
  assert(!responseXML.isXMLParserError(), responseXML.parserErrorText(EMPTY_STR), PHASE_PROCESS_RESPONSE);
62
- assert(responseXML.querySelectorAll(RESP_PARTIAL).isPresent(), ERR_NO_PARTIAL_RESPONSE, PHASE_PROCESS_RESPONSE);
63
+ assert(responseXML.querySelectorAll(XML_TAG_PARTIAL_RESP).isPresent(), ERR_NO_PARTIAL_RESPONSE, PHASE_PROCESS_RESPONSE);
63
64
  }
64
65
 
65
66
  /**
@@ -79,7 +80,7 @@ export module Assertions {
79
80
  let finalMessage = message ?? EMPTY_STR;
80
81
 
81
82
  //TODO clean up the messy makeException, this is a perfect case for encapsulation and sane defaults
82
- return makeException(error, finalTitle, finalName, "Response", caller || (((<any>arguments).caller) ? (<any>arguments).caller.toString() : "_raiseError"), finalMessage);
83
+ return ExtLang.makeException(error, finalTitle, finalName, "Response", caller || (((<any>arguments).caller) ? (<any>arguments).caller.toString() : "_raiseError"), finalMessage);
83
84
  }
84
85
 
85
86
  /*
@@ -103,6 +104,13 @@ export module Assertions {
103
104
  export function assertFunction(value: any, msg = EMPTY_STR, caller=EMPTY_STR, title="Assertion Error"): asserts value is Function {
104
105
  assertType(value, "function", msg, caller, title);
105
106
  }
107
+
108
+ export function assertDelay(value: any) {
109
+ if(!(value >= 0)) { // >= 0 abbreviation which covers all cases of non positive values,
110
+ // including NaN and non numeric strings, no type equality is deliberate here,
111
+ throw new Error("Invalid delay value: " + value);
112
+ }
113
+ }
106
114
  }
107
115
 
108
116
 
@@ -201,8 +201,8 @@ export class ExtDomQuery extends DQ {
201
201
  return true;
202
202
  }
203
203
  let reference = element.attr("href")
204
- .orElse(element.attr("src").value)
205
- .orElse(element.attr("rel").value);
204
+ .orElseLazy(() => element.attr("src").value)
205
+ .orElseLazy(() => element.attr("rel").value);
206
206
 
207
207
  if (!reference.isPresent()) {
208
208
  return true;
@@ -235,7 +235,7 @@ export class ExtDomQuery extends DQ {
235
235
  * @param deep whether the search should go into embedded shadow dom elements
236
236
  * @return a DomQuery containing the found elements
237
237
  */
238
- static byId(selector: string | DomQuery | Element, deep = false): DomQuery {
238
+ static byId(selector: string | DomQuery | Element, deep = false): ExtDomQuery {
239
239
  const ret = DomQuery.byId(selector, deep);
240
240
  return new ExtDomQuery(ret);
241
241
  }
@@ -244,6 +244,9 @@ export class ExtDomQuery extends DQ {
244
244
  return (curScript.getAsElem(0).value as HTMLElement)?.nonce ?? curScript.attr("nonce").value;
245
245
  }
246
246
 
247
+ filter(func: (item: DomQuery) => boolean): ExtDomQuery {
248
+ return new ExtDomQuery(super.filter(func));
249
+ }
247
250
  }
248
251
 
249
252
  export const ExtDQ = ExtDomQuery;
@@ -254,6 +257,8 @@ export const ExtDQ = ExtDomQuery;
254
257
  */
255
258
  export class ExtConfig extends Config {
256
259
 
260
+ $nspEnabled = true;
261
+
257
262
  constructor(root: any) {
258
263
  super(root);
259
264
  }
@@ -323,7 +328,10 @@ export class ExtConfig extends Config {
323
328
  * @param accessPath the access paths to be remapped
324
329
  * @private returns an array of access paths with version remapped namespaces
325
330
  */
326
- private remap(accessPath: any[]) {
331
+ private remap(accessPath: string[]): string[] {
332
+ if(!this.$nspEnabled) {
333
+ return accessPath;
334
+ }
327
335
  return Stream.of(...accessPath).map(key => $nsp(key)).collect(new ArrayCollector());
328
336
  }
329
337
  }
@@ -0,0 +1,89 @@
1
+ /*! Licensed to the Apache Software Foundation (ASF) under one or more
2
+ * contributor license agreements. See the NOTICE file distributed with
3
+ * this work for additional information regarding copyright ownership.
4
+ * The ASF licenses this file to you under the Apache License, Version 2.0
5
+ * (the "License"); you may not use this file except in compliance with
6
+ * the License. You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ import {DomQuery, DQ, DQ$} from "mona-dish";
19
+ import {$faces, $nsp, HTML_CLIENT_WINDOW, HTML_VIEWSTATE, P_CLIENT_WINDOW, P_VIEWSTATE} from "../core/Const";
20
+
21
+ /**
22
+ * Builder for hidden inputs.
23
+ * ATM only ViewState and Client window
24
+ * are supported (per spec)
25
+ *
26
+ * Improves readability in the response processor!
27
+ */
28
+ export class HiddenInputBuilder {
29
+ private namingContainerId?: string;
30
+ private parent?: DomQuery;
31
+ private namedViewRoot: boolean = false;
32
+ private readonly name: string;
33
+ private readonly template: string;
34
+
35
+ constructor(private selector: string) {
36
+ const isViewState = selector.indexOf($nsp(P_VIEWSTATE)) != -1;
37
+ this.name = isViewState ? P_VIEWSTATE : P_CLIENT_WINDOW
38
+ this.template = isViewState ? HTML_VIEWSTATE : HTML_CLIENT_WINDOW
39
+ }
40
+
41
+ withNamingContainerId(namingContainer: string): HiddenInputBuilder {
42
+ this.namingContainerId = namingContainer;
43
+ return this;
44
+ }
45
+
46
+ withParent(parent: DomQuery): HiddenInputBuilder {
47
+ this.parent = parent;
48
+ return this;
49
+ }
50
+
51
+ withNamedViewRoot(namedViewRoot: boolean): HiddenInputBuilder {
52
+ this.namedViewRoot = namedViewRoot;
53
+ return this;
54
+ }
55
+
56
+
57
+ build(): DomQuery {
58
+ const SEP = $faces().separatorchar;
59
+
60
+ let existingStates = DQ$(`[name*='${$nsp(this.name)}']`);
61
+ let cnt = existingStates.stream.map(state => {
62
+ let ident: string = state.id.orElse("-1").value;
63
+ ident = ident.substring(ident.lastIndexOf(SEP)+1);
64
+ return parseInt(ident);
65
+ })
66
+ .filter(item => !isNaN(item))
67
+ .reduce((item1, item2) => Math.max(item1, item2), -1).value;
68
+ //the maximum new ident is the current max + 1
69
+ cnt++;
70
+
71
+
72
+ const newElement = DQ.fromMarkup($nsp(this.template));
73
+ newElement.id.value = ((this.namingContainerId?.length) ?
74
+ [this.namingContainerId, $nsp(this.name), cnt]:
75
+ [$nsp(this.name), cnt]).join(SEP);
76
+
77
+ //name must be prefixed with the naming container id as well according to the jsdocs
78
+ if(this.namedViewRoot) {
79
+ newElement.name.value = (this.namingContainerId?.length) ?
80
+ [this.namingContainerId, $nsp(this.name)].join(SEP): $nsp(this.name);
81
+ } else {
82
+ newElement.name.value = $nsp(this.name);
83
+ }
84
+
85
+
86
+ this?.parent?.append(newElement);
87
+ return newElement;
88
+ }
89
+ }
@@ -13,13 +13,11 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  *
16
- * todo replace singleton with module definition
17
- *
18
16
  */
19
17
 
20
18
  import {Lang as LangBase, Config, Optional, DomQuery, DQ, Stream} from "mona-dish";
21
19
  import {Messages} from "../i18n/Messages";
22
- import {EMPTY_STR, TAG_FORM} from "../core/Const";
20
+ import {EMPTY_STR, HTML_TAG_FORM} from "../core/Const";
23
21
  import {getEventTarget} from "../xhrCore/RequestDataResolver";
24
22
 
25
23
 
@@ -160,25 +158,25 @@ export module ExtLang {
160
158
  export function getForm(elem: Element, event ?: Event): DQ | never {
161
159
 
162
160
  let queryElem = new DQ(elem);
163
- let eventTarget = new DQ(getEventTarget(event));
161
+ let eventTarget = (event) ? new DQ(getEventTarget(event)) : DomQuery.absent;
164
162
 
165
- if (queryElem.isTag(TAG_FORM)) {
163
+ if (queryElem.isTag(HTML_TAG_FORM)) {
166
164
  return queryElem;
167
165
  }
168
166
 
169
167
  //html 5 for handling
170
- if (queryElem.attr(TAG_FORM).isPresent()) {
171
- let formId = queryElem.attr(TAG_FORM).value;
168
+ if (queryElem.attr(HTML_TAG_FORM).isPresent()) {
169
+ let formId = queryElem.attr(HTML_TAG_FORM).value;
172
170
  let foundForm = DQ.byId(formId, true);
173
171
  if (foundForm.isPresent()) {
174
172
  return foundForm;
175
173
  }
176
174
  }
177
175
 
178
- let form = queryElem.parents(TAG_FORM)
179
- .orElseLazy(() => queryElem.byTagName(TAG_FORM, true))
180
- .orElseLazy(() => eventTarget.parents(TAG_FORM))
181
- .orElseLazy(() => eventTarget.byTagName(TAG_FORM))
176
+ let form = queryElem.firstParent(HTML_TAG_FORM)
177
+ .orElseLazy(() => queryElem.byTagName(HTML_TAG_FORM, true))
178
+ .orElseLazy(() => eventTarget.firstParent(HTML_TAG_FORM))
179
+ .orElseLazy(() => eventTarget.byTagName(HTML_TAG_FORM))
182
180
  .first();
183
181
 
184
182
  assertFormExists(form);
@@ -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
+ }
@@ -14,11 +14,11 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import {
17
- EMPTY_STR,
17
+ EMPTY_STR, ERROR,
18
18
  ERROR_MESSAGE,
19
19
  ERROR_NAME,
20
20
  RESPONSE_TEXT,
21
- RESPONSE_XML,
21
+ RESPONSE_XML, SERVER_ERROR,
22
22
  SOURCE,
23
23
  STATUS,
24
24
  UNKNOWN
@@ -49,7 +49,8 @@ export enum ErrorType {
49
49
  export class ErrorData extends EventData implements IErrorData {
50
50
 
51
51
  type: string = "error";
52
- source: string;
52
+ source: HTMLElement;
53
+ sourceId: string;
53
54
  errorName: string;
54
55
  errorMessage: string;
55
56
 
@@ -63,12 +64,14 @@ export class ErrorData extends EventData implements IErrorData {
63
64
  serverErrorMessage: string;
64
65
  message: string;
65
66
 
66
- constructor(source: string, errorName: string, errorMessage: string, responseText: string = null, responseXML: any = null, responseCode: string = "200", status: string = "UNKNOWN", type = ErrorType.CLIENT_ERROR) {
67
+ constructor(source: string, errorName: string, errorMessage: string, responseText: string = null, responseXML: any = null, responseCode: string = "200", status: string = "", type = ErrorType.CLIENT_ERROR) {
67
68
  super();
68
- this.source = source;
69
- this.type = "error";
69
+ this.source = document.getElementById(source);
70
+ this.sourceId = source;
71
+ this.type = ERROR;
70
72
  this.errorName = errorName;
71
- this.message = this.errorMessage = errorMessage;
73
+ //tck requires that the type is prefixed to the message itself (jsdoc also) in case of a server error
74
+ this.message = this.errorMessage = (type == SERVER_ERROR) ? type + ": " + errorMessage : errorMessage;
72
75
  this.responseCode = responseCode;
73
76
  this.responseText = responseText;
74
77
  this.status = status;
@@ -81,10 +84,10 @@ export class ErrorData extends EventData implements IErrorData {
81
84
  }
82
85
 
83
86
  static fromClient(e: Error): ErrorData {
84
- return new ErrorData("client", e?.name ?? '', e?.message ?? '', e?.stack ?? '');
87
+ return new ErrorData((e as any)?.source ?? "client", e?.name ?? EMPTY_STR, e?.message ?? EMPTY_STR, e?.stack ?? EMPTY_STR);
85
88
  }
86
89
 
87
- static fromHttpConnection(source: any, name: string, message: string, responseText, responseCode: number, status: string = 'UNKNOWN'): ErrorData {
90
+ static fromHttpConnection(source: any, name: string, message: string, responseText, responseCode: number, status: string = EMPTY_STR): ErrorData {
88
91
  return new ErrorData(source, name, message, responseText, responseCode, `${responseCode}`, status, ErrorType.HTTP_ERROR);
89
92
  }
90
93
 
@@ -98,11 +101,13 @@ export class ErrorData extends EventData implements IErrorData {
98
101
  let status = getMsg(context, STATUS);
99
102
  let responseText = getMsg(context, RESPONSE_TEXT);
100
103
  let responseXML = getMsg(context, RESPONSE_XML);
104
+
105
+
101
106
  return new ErrorData(source, errorName, errorMessage, responseText, responseXML, errorCode + EMPTY_STR, status, errorType);
102
107
  }
103
108
 
104
109
  private static getMsg(context, param) {
105
- return getMessage(context.getIf(param).orElse(UNKNOWN).value);
110
+ return getMessage(context.getIf(param).orElse(EMPTY_STR).value);
106
111
  }
107
112
 
108
113
  static fromServerError(context: Config): ErrorData {
@@ -14,7 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import {Config, DQ} from "mona-dish";
17
- import {BEGIN, CTX_PARAM_PASS_THR, EVENT, P_PARTIAL_SOURCE, SOURCE} from "../core/Const";
17
+ import {BEGIN, CTX_PARAM_REQ_PASS_THR, EVENT, P_PARTIAL_SOURCE, SOURCE} from "../core/Const";
18
18
 
19
19
  export class EventData implements IEventData{
20
20
  type: string;
@@ -33,7 +33,7 @@ export class EventData implements IEventData{
33
33
 
34
34
  let sourceId: string = context.getIf(SOURCE)
35
35
  .orElseLazy(() => context.getIf(P_PARTIAL_SOURCE).value)
36
- .orElseLazy(() => context.getIf(CTX_PARAM_PASS_THR, P_PARTIAL_SOURCE).value)
36
+ .orElseLazy(() => context.getIf(CTX_PARAM_REQ_PASS_THR, P_PARTIAL_SOURCE).value)
37
37
  .value;
38
38
  if (sourceId) {
39
39
  eventData.source = DQ.byId(sourceId, true).first().value.value;
@@ -32,7 +32,6 @@ export interface IResponseProcessor {
32
32
  */
33
33
  replaceHead(shadowHead: XMLQuery | DQ): void;
34
34
 
35
-
36
35
  /**
37
36
  * adds new elements to the head
38
37
  *
@@ -40,6 +39,14 @@ export interface IResponseProcessor {
40
39
  */
41
40
  addToHead(newElements: XMLQuery | DQ): void;
42
41
 
42
+
43
+ /**
44
+ * adds new elements to the head in a deferred manner
45
+ *
46
+ * @param newElements the elements which need addition
47
+ */
48
+ addToHeadDeferred(newElements: XMLQuery | DQ): void;
49
+
43
50
  /**
44
51
  * replace the body
45
52
  *
@@ -142,4 +149,11 @@ export interface IResponseProcessor {
142
149
  * send last event
143
150
  */
144
151
  done(): void;
152
+
153
+ /**
154
+ * update internal state to
155
+ * check whether we still are in a named view root
156
+ * (can change after a navigation)
157
+ */
158
+ updateNamedViewRootState();
145
159
  }
@@ -14,20 +14,25 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import {AssocArrayCollector, Config, DomQuery, DQ, Stream} from "mona-dish";
17
+ import {Config, DomQuery, DQ} from "mona-dish";
18
18
  import {
19
- CTX_PARAM_DELAY,
20
- CTX_PARAM_TIMEOUT,
19
+ $faces,
20
+ $nsp,
21
+ CTX_OPTIONS_DELAY,
22
+ CTX_OPTIONS_TIMEOUT,
23
+ DELAY_NONE,
21
24
  EMPTY_FUNC,
22
25
  EMPTY_STR,
23
- ENCODED_URL,
24
- MF_NONE,
26
+ ENCODED_URL, NAMED_VIEWROOT, NAMING_CONTAINER_ID,
27
+ P_VIEWSTATE,
25
28
  REQ_TYPE_GET,
26
29
  REQ_TYPE_POST
27
30
  } from "../core/Const";
28
31
  import {XhrFormData} from "./XhrFormData";
29
32
  import {ExtLang} from "../util/Lang";
30
33
  import {ExtConfig, ExtDomQuery} from "../util/ExtDomQuery";
34
+ import {Assertions} from "../util/Assertions";
35
+
31
36
 
32
37
  /**
33
38
  * Resolver functions for various aspects of the request data
@@ -45,6 +50,7 @@ import {ExtConfig, ExtDomQuery} from "../util/ExtDomQuery";
45
50
  * @param funcName
46
51
  */
47
52
  export function resolveHandlerFunc(requestContext: Config, responseContext: Config, funcName: string) {
53
+ responseContext = responseContext || new Config({});
48
54
  return responseContext.getIf(funcName)
49
55
  .orElseLazy(() =>requestContext.getIf(funcName).value)
50
56
  .orElse(EMPTY_FUNC).value;
@@ -67,20 +73,52 @@ export function resolveFinalUrl(sourceForm: DomQuery, formData: XhrFormData, aja
67
73
  * it is either the id or the parent form of the element or an embedded form
68
74
  * of the element
69
75
  *
70
- * @param requestCtx
71
76
  * @param elem
72
77
  * @param event
73
78
  */
74
- export function resolveForm(requestCtx: Config, elem: DQ, event: Event): DQ {
75
- const configId = requestCtx.value?.myfaces?.form ?? MF_NONE;
76
- return DQ
77
- .byId(configId, true)
78
- .orElseLazy(() => ExtLang.getForm(elem.getAsElem(0).value, event));
79
+ export function resolveForm(elem: DQ, event: Event): DQ {
80
+ return ExtLang.getForm(elem.getAsElem(0).value, event);
81
+ }
82
+
83
+ export function resolveViewId(form: DQ): string {
84
+ const viewState = form.querySelectorAll(`input[type='hidden'][name*='${$nsp(P_VIEWSTATE)}']`).id.orElse("").value;
85
+ const divider = $faces().separatorchar;
86
+ const viewId = viewState.split(divider, 2)[0];
87
+ const viewStateViewId = viewId.indexOf($nsp(P_VIEWSTATE)) === -1 ? viewId : "";
88
+ // myfaces specific, we in non portlet environments prepend the viewId
89
+ // even without being in a naming container, the other components ignore that
90
+ return form.id.value.indexOf(viewStateViewId) === 0 ? viewStateViewId : "";
91
+ }
92
+
93
+ export function resolveViewRootId(form: DQ): string {
94
+ const viewState = form.querySelectorAll(`input[type='hidden'][name*='${$nsp(P_VIEWSTATE)}']`).attr("name").orElse("").value;
95
+ const divider = $faces().separatorchar;
96
+ const viewId = viewState.split(divider, 2)[0];
97
+ //different to the identifier the form id is never prepended to the viewstate
98
+ return viewId.indexOf($nsp(P_VIEWSTATE)) === -1 ? viewId : "";
99
+ }
100
+
101
+ /**
102
+ * as per jsdoc before the request it must be ensured that every post argument
103
+ * is prefixed with the naming container id (there is an exception in mojarra with
104
+ * the element=element param, which we have to follow here as well.
105
+ * (inputs are prefixed by name anyway normally this only affects our standard parameters)
106
+ * @private
107
+ */
108
+ export function resoveNamingContainerMapper(internalContext: Config): (key: string, value: any) => [string, any] {
109
+ const isNamedViewRoot = internalContext.getIf(NAMED_VIEWROOT).isPresent();
110
+ if(!isNamedViewRoot) {
111
+ return (key, value) => [key, value];
112
+ }
113
+ const partialId = internalContext.getIf(NAMING_CONTAINER_ID).value;
114
+ const SEP = $faces().separatorchar;
115
+ const prefix = partialId + SEP;
116
+ return (key: string, value: any) => (key.indexOf(prefix) == 0) ? [key, value] : [prefix + key, value];
79
117
  }
80
118
 
81
119
  export function resolveTimeout(options: Config): number {
82
120
  let getCfg = ExtLang.getLocalOrGlobalConfig;
83
- return options.getIf(CTX_PARAM_TIMEOUT).value ?? getCfg(options.value, CTX_PARAM_TIMEOUT, 0);
121
+ return options.getIf(CTX_OPTIONS_TIMEOUT).value ?? getCfg(options.value, CTX_OPTIONS_TIMEOUT, 0);
84
122
  }
85
123
 
86
124
  /**
@@ -89,9 +127,15 @@ export function resolveTimeout(options: Config): number {
89
127
  * @param options ... the options object, in most cases it will host the delay value
90
128
  */
91
129
  export function resolveDelay(options: Config): number {
92
- let getCfg = ExtLang.getLocalOrGlobalConfig;
93
-
94
- return options.getIf(CTX_PARAM_DELAY).value ?? getCfg(options.value, CTX_PARAM_DELAY, 0);
130
+ // null, 'none', or undefined will automatically be mapped to 0 aka no delay
131
+ // the config delay will be dropped not needed anymore, it does not really
132
+ // make sense anymore now that it is part of a local spec
133
+ let ret = options.getIf(CTX_OPTIONS_DELAY).orElse(0).value;
134
+ // if delay === none, no delay must be used, aka delay 0
135
+ ret = (DELAY_NONE === ret) ? 0 : ret;
136
+ // negative, or invalid values will automatically get a js exception
137
+ Assertions.assertDelay(ret);
138
+ return ret;
95
139
  }
96
140
 
97
141
  /**
@@ -138,14 +182,15 @@ export function getEventTarget(evt: Event): Element {
138
182
  * @param opts
139
183
  * @param el
140
184
  */
141
- export function resolveDefaults(event: Event, opts: Options | [[string, any]] , el: Element | string = null) {
185
+ export function resolveDefaults(event: Event, opts: Options | [[string, any]] , el: Element | string = null): any {
142
186
  //deep copy the options, so that further transformations to not backfire into the callers
143
- const resolvedEvent = event,
144
- options = new ExtConfig(opts).deepCopy,
145
- elem = DQ.byId(el || <Element>resolvedEvent.target, true),
146
- elementId = elem.id.value, requestCtx = new ExtConfig({}),
147
- internalCtx = new ExtConfig({}), windowId = resolveWindowId(options),
148
- isResetValues = true === options.value?.resetValues;
149
-
150
- return {resolvedEvent, options, elem, elementId, requestCtx, internalCtx, windowId, isResetValues};
187
+ const elem = DQ.byId(el || <Element>event.target, true);
188
+ const options = new ExtConfig(opts).deepCopy as ExtConfig;
189
+ return {
190
+ options: options,
191
+ elem: elem,
192
+ elementId: elem.id.value,
193
+ windowId: resolveWindowId(options),
194
+ isResetValues: true === options.value?.resetValues
195
+ };
151
196
  }
@@ -25,7 +25,7 @@ import {
25
25
  CTX_PARAM_SRC_FRM_ID,
26
26
  SEL_RESPONSE_XML,
27
27
  SOURCE,
28
- TAG_FORM,
28
+ HTML_TAG_FORM,
29
29
  UPDATE_ELEMS,
30
30
  UPDATE_FORMS,
31
31
  DEFERRED_HEAD_INSERTS
@@ -106,9 +106,9 @@ export function resolveSourceForm(internalContext: Config, elem: DQ): DQ {
106
106
  let sourceFormId = internalContext.getIf(CTX_PARAM_SRC_FRM_ID);
107
107
  let sourceForm = new DQ(sourceFormId.isPresent() ? document.forms[sourceFormId.value] : null);
108
108
 
109
- sourceForm = sourceForm.orElseLazy(() => elem.parents(TAG_FORM))
110
- .orElseLazy(() => elem.querySelectorAll(TAG_FORM))
111
- .orElseLazy(() => DQ.querySelectorAll(TAG_FORM));
109
+ sourceForm = sourceForm.orElseLazy(() => elem.firstParent(HTML_TAG_FORM))
110
+ .orElseLazy(() => elem.querySelectorAll(HTML_TAG_FORM))
111
+ .orElseLazy(() => DQ.querySelectorAll(HTML_TAG_FORM));
112
112
 
113
113
  return sourceForm;
114
114
  }