jsf.js_next_gen 4.0.2-beta.1 → 4.0.2-beta.10

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 (106) hide show
  1. package/dist/docs/assets/main.js +3 -3
  2. package/dist/docs/assets/search.js +1 -1
  3. package/dist/docs/assets/style.css +450 -362
  4. package/dist/docs/functions/faces.ajax.addOnError.html +41 -32
  5. package/dist/docs/functions/faces.ajax.addOnEvent.html +41 -32
  6. package/dist/docs/functions/faces.ajax.request.html +41 -32
  7. package/dist/docs/functions/faces.ajax.response.html +42 -32
  8. package/dist/docs/functions/faces.getClientWindow.html +32 -34
  9. package/dist/docs/functions/faces.getProjectStage.html +31 -34
  10. package/dist/docs/functions/faces.getViewState.html +33 -35
  11. package/dist/docs/functions/faces.push.close.html +40 -31
  12. package/dist/docs/functions/faces.push.init.html +62 -45
  13. package/dist/docs/functions/faces.push.open.html +40 -31
  14. package/dist/docs/functions/faces.util.chain.html +39 -31
  15. package/dist/docs/functions/myfaces.ab.html +40 -39
  16. package/dist/docs/functions/myfaces.onDomReady.html +25 -29
  17. package/dist/docs/index.html +45 -72
  18. package/dist/docs/modules/faces.ajax.html +36 -29
  19. package/dist/docs/modules/faces.html +35 -38
  20. package/dist/docs/modules/faces.push.html +34 -27
  21. package/dist/docs/modules/faces.util.html +30 -23
  22. package/dist/docs/modules/myfaces.html +21 -27
  23. package/dist/docs/modules.html +15 -23
  24. package/dist/docs/variables/faces.contextpath.html +28 -30
  25. package/dist/docs/variables/faces.implversion.html +29 -31
  26. package/dist/docs/variables/faces.separatorchar.html +28 -30
  27. package/dist/docs/variables/faces.specversion.html +29 -31
  28. package/dist/docs/variables/myfaces.oam.html +21 -26
  29. package/dist/window/faces-development.js +166 -68
  30. package/dist/window/faces-development.js.map +1 -1
  31. package/dist/window/faces.js +1 -1
  32. package/dist/window/faces.js.map +1 -1
  33. package/dist/window/jsf-development.js +166 -68
  34. package/dist/window/jsf-development.js.map +1 -1
  35. package/dist/window/jsf.js +1 -1
  36. package/dist/window/jsf.js.map +1 -1
  37. package/faulty_response.html +167 -0
  38. package/package.json +17 -18
  39. package/src/main/typescript/impl/AjaxImpl.ts +22 -19
  40. package/src/main/typescript/impl/PushImpl.ts +1 -1
  41. package/src/main/typescript/impl/util/FileUtils.ts +3 -2
  42. package/src/main/typescript/impl/util/HiddenInputBuilder.ts +2 -2
  43. package/src/main/typescript/impl/xhrCore/XhrRequest.ts +28 -8
  44. package/src/main/typescript/test/frameworkBase/_ext/shared/StandardInits.ts +50 -0
  45. package/src/main/typescript/test/impl/ImplTest.spec.ts +85 -0
  46. package/src/main/typescript/test/xhrCore/RequestParamsTest.spec.ts +299 -1
  47. package/src/main/typescript/test/xhrCore/RequestTest.spec.ts +245 -1
  48. package/src/main/typescript/test/xhrCore/ResponseTest.spec.ts +3 -3
  49. package/target/api/_api.js +2 -2
  50. package/target/api/_api.js.map +1 -1
  51. package/target/classes/com/example/jsfs_js_ts/DecoratedFacesJS.class +0 -0
  52. package/target/classes/com/example/jsfs_js_ts/DecoratingResourceHandlerWrapper.class +0 -0
  53. package/target/classes/com/example/jsfs_js_ts/FacesJSMapFileResourceWrapper.class +0 -0
  54. package/target/classes/com/example/jsfs_js_ts/FacesJSMappingDecorator.class +0 -0
  55. package/target/impl/AjaxImpl.js +22 -20
  56. package/target/impl/AjaxImpl.js.map +1 -1
  57. package/target/impl/PushImpl.js +4 -4
  58. package/target/impl/PushImpl.js.map +1 -1
  59. package/target/impl/util/Assertions.js +1 -1
  60. package/target/impl/util/Assertions.js.map +1 -1
  61. package/target/impl/util/FileUtils.js +3 -2
  62. package/target/impl/util/FileUtils.js.map +1 -1
  63. package/target/impl/util/HiddenInputBuilder.js +2 -2
  64. package/target/impl/util/HiddenInputBuilder.js.map +1 -1
  65. package/target/impl/util/Lang.js +1 -1
  66. package/target/impl/util/Lang.js.map +1 -1
  67. package/target/impl/xhrCore/ErrorData.js +1 -1
  68. package/target/impl/xhrCore/ErrorData.js.map +1 -1
  69. package/target/impl/xhrCore/Response.js +1 -1
  70. package/target/impl/xhrCore/Response.js.map +1 -1
  71. package/target/impl/xhrCore/XhrRequest.js +25 -7
  72. package/target/impl/xhrCore/XhrRequest.js.map +1 -1
  73. package/target/myfaces/OamSubmit.js +1 -1
  74. package/target/myfaces/OamSubmit.js.map +1 -1
  75. package/target/test/frameworkBase/_ext/shared/StandardInits.js +47 -1
  76. package/target/test/frameworkBase/_ext/shared/StandardInits.js.map +1 -1
  77. package/target/test/frameworkBase/_ext/shared/XmlResponses.js +1 -1
  78. package/target/test/frameworkBase/_ext/shared/XmlResponses.js.map +1 -1
  79. package/target/test/impl/ImplTest.spec.js +64 -0
  80. package/target/test/impl/ImplTest.spec.js.map +1 -1
  81. package/target/test/xhrCore/RequestParamsTest.spec.js +283 -0
  82. package/target/test/xhrCore/RequestParamsTest.spec.js.map +1 -1
  83. package/target/test/xhrCore/RequestTest.spec.js +212 -0
  84. package/target/test/xhrCore/RequestTest.spec.js.map +1 -1
  85. package/target/test/xhrCore/ResponseTest.spec.js +3 -3
  86. package/target/test-classes/.gz +0 -0
  87. package/target/test-classes/com/example/jsfs_js_ts/JsfsJsTsApplicationTests.class +0 -0
  88. package/target/test-classes/fileuploadtest.html +24 -0
  89. package/target/test-classes/jsf-development.js +3559 -0
  90. package/target/test-classes/jsf-development.js.br +0 -0
  91. package/target/test-classes/jsf-development.js.gz +0 -0
  92. package/target/test-classes/jsf-development.js.map +1 -0
  93. package/target/test-classes/jsf.js +3 -0
  94. package/target/test-classes/jsf.js.br +0 -0
  95. package/target/test-classes/jsf.js.gz +0 -0
  96. package/webpack.config.ts +1 -23
  97. package/dist/window/faces-development.js.br +0 -0
  98. package/dist/window/faces-development.js.gz +0 -0
  99. package/dist/window/faces.js.br +0 -0
  100. package/dist/window/faces.js.gz +0 -0
  101. package/dist/window/jsf-development.js.br +0 -0
  102. package/dist/window/jsf-development.js.gz +0 -0
  103. package/dist/window/jsf.js.br +0 -0
  104. package/dist/window/jsf.js.gz +0 -0
  105. package/webpack.config.js +0 -71
  106. package/webpack.config.js.map +0 -1
@@ -0,0 +1,167 @@
1
+ <!DOCTYPE html>
2
+ <html lang='de'>
3
+ <head>
4
+ <meta charset='UTF-8'>
5
+ <meta name='viewport' content='width=device-width, initial-scale=1.0'>
6
+ <title>Test
7
+ </title>
8
+ <link rel='stylesheet' href='./fixtures/css/tobago.css' type='text/css'>
9
+ <link rel='stylesheet' href='./fixtures/css/bootstrap-icons.css' type='text/css'>
10
+ <script src='./fixtures/jakarta.faces.resource/faces.js.jsf' type='text/javascript'></script>
11
+ <script src='./fixtures/js/tobago.js' type='module'></script>
12
+ </head>
13
+ <body>
14
+ <tobago-page locale='de' class='container-fluid' id='page' focus-on-error='true' wait-overlay-delay-full='1000' wait-overlay-delay-ajax='1000'>
15
+ <form action='/content/010-input/Input.xhtml' id='page::form' method='post' accept-charset='UTF-8' data-tobago-context-path=''>
16
+ <input type='hidden' name='jakarta.faces.source' id='jakarta.faces.source' disabled='disabled'>
17
+ <tobago-focus id='page::lastFocusId'>
18
+ <input type='hidden' name='page::lastFocusId' id='page::lastFocusId::field'>
19
+ </tobago-focus>
20
+ <input type='hidden' name='org.apache.myfaces.tobago.webapp.Secret' id='org.apache.myfaces.tobago.webapp.Secret' value='secretValue'>
21
+ <div class='tobago-page-menuStore'>
22
+ </div>
23
+ <div class='tobago-page-toastStore'>
24
+ </div>
25
+ <span id='page::faces-state-container'><input type='hidden' name='jakarta.faces.ViewState' id='j_id__v_0:jakarta.faces.ViewState:1' value='viewStateValue' autocomplete='off'><input type='hidden' name='jakarta.faces.RenderKitId' value='tobago'><input type='hidden' id='j_id__v_0:jakarta.faces.ClientWindow:1' name='jakarta.faces.ClientWindow' value='clientWindowValue'></span>
26
+ <button type='button' id='page:button' name='page:button' class='tobago-button btn btn-secondary tobago-auto-spacing'><tobago-behavior event='click' client-id='page:button' execute='page:button' render='page'></tobago-behavior><span>page ajax</span></button>
27
+ </form>
28
+ <noscript>
29
+ <div class='tobago-page-noscript'>Diese Seite benötigt JavaScript, allerdings ist JavaScript in Ihrem Browser derzeit deaktiviert. Um JavaScript zu aktivieren, lesen Sie ggf. die Anleitung Ihres Browsers.
30
+ </div>
31
+ </noscript>
32
+ </tobago-page>
33
+ </body>
34
+ </html>
35
+
36
+
37
+
38
+ ---- update ---
39
+
40
+ <?xml version="1.0" encoding="UTF-8"?>
41
+ <partial-response id='j_id__v_0'>
42
+ <changes>
43
+ <update id='page'><![CDATA[
44
+ <html lang='de'>
45
+ <head>
46
+ <meta charset='UTF-8'/>
47
+ <meta name='viewport' content='width=device-width, initial-scale=1.0'/>
48
+ <title>Test
49
+ </title>
50
+ <link rel='stylesheet' href='./fixtures/css/tobago.css' type='text/css'>
51
+ <link rel='stylesheet' href='./fixtures/css/bootstrap-icons.css' type='text/css'>
52
+ <script src='./fixtures/jakarta.faces.resource/faces.js.jsf' type='text/javascript'></script>
53
+ <script src='./fixtures/js/tobago.js' type='module'></script>
54
+ </head>
55
+ <body>
56
+ <tobago-page locale='de' class='container-fluid' id='page' focus-on-error='true' wait-overlay-delay-full='1000' wait-overlay-delay-ajax='1000'>
57
+ <form action='/content/010-input/Input.xhtml' id='page::form' method='post' accept-charset='UTF-8' data-tobago-context-path=''>
58
+ <input type='hidden' name='jakarta.faces.source' id='jakarta.faces.source' disabled='disabled'/>
59
+ <tobago-focus id='page::lastFocusId'>
60
+ <input type='hidden' name='page::lastFocusId' id='page::lastFocusId::field'/>
61
+ </tobago-focus>
62
+ <input type='hidden' name='org.apache.myfaces.tobago.webapp.Secret' id='org.apache.myfaces.tobago.webapp.Secret' value='secretValue'/>
63
+ <div class='tobago-page-menuStore'>
64
+ </div>
65
+ <div class='tobago-page-toastStore'>
66
+ </div>
67
+ <span id='page::faces-state-container'></span>
68
+ <button type='button' id='page:button' name='page:button' class='tobago-button btn btn-secondary tobago-auto-spacing'><tobago-behavior event='click' client-id='page:button' execute='page:button' render='page'></tobago-behavior><span>page ajax</span></button>
69
+ </form>
70
+ <noscript>
71
+ <div class='tobago-page-noscript'>Diese Seite benötigt JavaScript, allerdings ist JavaScript in Ihrem Browser derzeit deaktiviert. Um JavaScript zu aktivieren, lesen Sie ggf. die Anleitung Ihres Browsers.
72
+ </div>
73
+ </noscript>
74
+ </tobago-page>
75
+ </body>
76
+ </html>]]>
77
+ </update>
78
+ <update id='j_id__v_0:jakarta.faces.ViewState:1'><![CDATA[viewStateValue]]>
79
+ </update>
80
+ <update id='j_id__v_0:jakarta.faces.ClientWindow:1'><![CDATA[clientWindowValue]]>
81
+ </update>
82
+ </changes>
83
+ </partial-response>`;
84
+
85
+ static SHADOW_DOM_UPDATE=`
86
+ <partial-response>
87
+ <changes><update id="shadowContent"><![CDATA[<div id="shadowContent">after update</div>]]></update></changes>
88
+ </partial-response>
89
+ `;
90
+
91
+ static UPDATE_INSERT_2 = `
92
+ <partial-response>
93
+ <changes>
94
+ <update id="changesArea"><![CDATA[
95
+ <div id='changesArea'>update succeeded 2</div><script type='text/javascript'>document.getElementById('evalarea2').innerHTML='embedded script at update succeed';</script>
96
+ ]]></update>
97
+ <insert id="inserted1" >
98
+ <before id='changesArea'><![CDATA[insert before succeeded should display before test1<script type='text/javascript'>document.getElementById('evalarea3').innerHTML='embedded script at insert succeed';</script>]]></before>
99
+ </insert>
100
+ <insert id="inserted2">
101
+ <after id='changesArea'><![CDATA[insert after succeeded should display after test1]]></after>
102
+ </insert>
103
+ </changes>
104
+ </partial-response>
105
+
106
+ ---- after ----
107
+
108
+ <head>
109
+ <meta charset="UTF-8">
110
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
111
+ <title>Test
112
+ </title>
113
+ <link rel="stylesheet" href="./fixtures/css/tobago.css" type="text/css">
114
+ <link rel="stylesheet" href="./fixtures/css/bootstrap-icons.css" type="text/css">
115
+ <script src="./fixtures/jakarta.faces.resource/faces.js.jsf" type="text/javascript"></script>
116
+ <script src="./fixtures/js/tobago.js" type="module"></script>
117
+ </head>
118
+ <body>
119
+ <html>
120
+ <head>
121
+ <meta charset="UTF-8">
122
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
123
+ <title>Test
124
+ </title>
125
+
126
+
127
+ <link rel="stylesheet" href="./fixtures/css/tobago.css" type="text/css">
128
+ <link rel="stylesheet" href="./fixtures/css/bootstrap-icons.css" type="text/css">
129
+ <script src="./fixtures/jakarta.faces.resource/faces.js.jsf" type="text/javascript"></script>
130
+ <script src="./fixtures/js/tobago.js" type="module"></script>
131
+ </head>
132
+ <body>
133
+ <tobago-page locale="de" class="container-fluid" id="page" focus-on-error="true" wait-overlay-delay-full="1000"
134
+ wait-overlay-delay-ajax="1000">
135
+ <form action="/content/010-input/Input.xhtml" id="page::form" method="post" accept-charset="UTF-8"
136
+ data-tobago-context-path="">
137
+ <input type="hidden" name="jakarta.faces.source" id="jakarta.faces.source" disabled="disabled">
138
+ <tobago-focus id="page::lastFocusId">
139
+ <input type="hidden" name="page::lastFocusId" id="page::lastFocusId::field">
140
+ </tobago-focus>
141
+ <input type="hidden" name="org.apache.myfaces.tobago.webapp.Secret" id="org.apache.myfaces.tobago.webapp.Secret"
142
+ value="secretValue">
143
+ <div class="tobago-page-menuStore">
144
+ </div>
145
+ <div class="tobago-page-toastStore">
146
+ </div>
147
+ <span id="page::faces-state-container"></span>
148
+ <button type="button" id="page:button" name="page:button"
149
+ class="tobago-button btn btn-secondary tobago-auto-spacing">
150
+ <tobago-behavior event="click" client-id="page:button" execute="page:button"
151
+ render="page"></tobago-behavior>
152
+ <span>page ajax</span></button>
153
+ <input type="hidden" name="jakarta.faces.ViewState" value="viewStateValue"
154
+ id="j_id__v_0:jakarta.faces.ViewState:1"><input type="hidden" '="" name="jakarta.faces.ClientWindow"
155
+ value="clientWindowValue" id="j_id__v_0:jakarta.faces.ClientWindow:1">
156
+ </form>
157
+ <noscript>
158
+ <div class='tobago-page-noscript'>Diese Seite benötigt JavaScript, allerdings ist JavaScript in Ihrem Browser
159
+ derzeit deaktiviert. Um JavaScript zu aktivieren, lesen Sie ggf. die Anleitung Ihres Browsers.
160
+ </div>
161
+ </noscript>
162
+ </tobago-page>
163
+
164
+ </body>
165
+ </html>
166
+
167
+ </body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsf.js_next_gen",
3
- "version": "4.0.2-beta.1",
3
+ "version": "4.0.2-beta.10",
4
4
  "description": "A next generation typescript reimplementation of jsf.js",
5
5
  "main": "dist/window/faces.js",
6
6
  "scripts": {
@@ -21,34 +21,33 @@
21
21
  "license": "Apache-2.0",
22
22
  "devDependencies": {
23
23
  "@istanbuljs/nyc-config-typescript": "^1.0.2",
24
- "@types/chai": "^4.3.4",
24
+ "@types/chai": "^4.3.5",
25
25
  "@types/mocha": "^10.0.1",
26
- "@types/node": "^18.15.11",
27
- "@types/sinon": "^10.0.13",
26
+ "@types/node": "^20.4.2",
27
+ "@types/sinon": "^10.0.15",
28
28
  "babel-plugin-syntax-dynamic-import": "^6.18.0",
29
29
  "chai": "^4.3.7",
30
- "compression-webpack-plugin": "^10.0.0",
31
30
  "cross-env": "^7.0.3",
32
- "html-webpack-plugin": "^5.5.0",
31
+ "html-webpack-plugin": "^5.5.3",
33
32
  "http-server": "^14.1.1",
34
33
  "jsdom": "^21.1.1",
35
34
  "jsdom-global": "^3.0.2",
36
35
  "mocha": "^10.2.0",
37
- "npm-check-updates": "^16.9.0",
36
+ "npm-check-updates": "^16.10.15",
38
37
  "nyc": "^15.1.0",
39
- "replace-in-file": "^6.3.5",
40
- "rxjs": "^7.8.0",
41
- "sinon": "^15.0.3",
42
- "terser-webpack-plugin": "^5.3.7",
43
- "ts-loader": "^9.4.2",
38
+ "replace-in-file": "^7.0.1",
39
+ "rxjs": "^7.8.1",
40
+ "sinon": "^15.2.0",
41
+ "terser-webpack-plugin": "^5.3.9",
42
+ "ts-loader": "^9.4.4",
44
43
  "ts-node": "^10.9.1",
45
- "typedoc": "^0.23.28",
46
- "typescript": "^5.0.3",
47
- "webpack": "^5.77.0",
48
- "webpack-cli": "^5.0.1",
49
- "webpack-dev-server": "^4.13.1"
44
+ "typedoc": "^0.24.8",
45
+ "typescript": "^5.1.6",
46
+ "webpack": "^5.88.1",
47
+ "webpack-cli": "^5.1.4",
48
+ "webpack-dev-server": "^4.15.1"
50
49
  },
51
50
  "dependencies": {
52
- "mona-dish": "0.28.10"
51
+ "mona-dish": "0.28.11"
53
52
  }
54
53
  }
@@ -219,13 +219,14 @@ export module Implementation {
219
219
  // by passing a boolean as return value into the onElem call
220
220
  // we can stop early at the first false, just like the spec requests
221
221
 
222
- let ret;
222
+ let ret = true;
223
223
  funcs.every(func => {
224
224
  let returnVal = resolveAndExecute(source, event, func);
225
- if(returnVal !== false) {
226
- ret = returnVal;
225
+ if(returnVal === false) {
226
+ ret = false;
227
227
  }
228
- return returnVal !== false;
228
+ //we short circuit in case of false and break the every loop
229
+ return ret;
229
230
  });
230
231
  return ret;
231
232
 
@@ -659,13 +660,14 @@ export module Implementation {
659
660
  }
660
661
 
661
662
  /**
662
- * transforms the user values to the expected one
663
- * with the proper none all form and this handling
664
- * (note we also could use a simple string replace, but then
665
- * we would have had double entries under some circumstances)
663
+ * transforms the user values to the expected values
664
+ * handling '@none', '@all', '@form', and '@this' appropriately.
665
+ * (Note: Although we could employ a simple string replacement method,
666
+ * it could result in duplicate entries under certain conditions.)
666
667
  *
667
- * there are several standardized constants which need a special treatment
668
- * like @all, @none, @form, @this
668
+ * Specific standardized constants such as
669
+ * '@all', '@none', '@form', and '@this'
670
+ * require special treatment.
669
671
  *
670
672
  * @param targetConfig the target configuration receiving the final values
671
673
  * @param targetKey the target key
@@ -764,15 +766,14 @@ export module Implementation {
764
766
  }
765
767
 
766
768
  /**
767
- * Filter the options given with a blacklist, so that only
768
- * the values required for params-through are processed in the ajax request
769
+ * Filters the provided options using a blacklist to ensure
770
+ * only pass-through parameters are processed for the Ajax request.
769
771
  *
770
- * Note this is a bug carried over from the old implementation
771
- * the spec conform behavior is to use params for pass - through values
772
- * this will be removed soon, after it is cleared up whether removing
773
- * it breaks any legacy code
772
+ * Note that this issue is leftover from a previous implementation.
773
+ * The specification-conforming behavior is to use parameters for pass-through values.
774
+ * This will be addressed soon, after confirming that removal won't break any legacy code.
774
775
  *
775
- * @param {Context} mappedOpts the options to be filtered
776
+ * @param {Context} mappedOpts - The options to be filtered.
776
777
  */
777
778
  function extractLegacyParams(mappedOpts: Options): {[key: string]: any} {
778
779
  //we now can use the full code reduction given by our stream api
@@ -783,8 +784,9 @@ export module Implementation {
783
784
  }
784
785
 
785
786
  /**
786
- * extracts the myfaces config parameters which provide extra functionality
787
- * on top of JSF
787
+ * Extracts the MyFaces configuration parameters
788
+ * that augment JSF with additional functionality.
789
+ *
788
790
  * @param mappedOpts
789
791
  * @private
790
792
  */
@@ -796,6 +798,7 @@ export module Implementation {
796
798
  .reduce(collectAssoc, {})?.[MYFACES];
797
799
  }
798
800
 
801
+
799
802
  function remapArrayToAssocArr(arrayedParams: [[string, any]] | {[key: string]: any}): {[key: string]: any} {
800
803
  if(Array.isArray(arrayedParams)) {
801
804
  return arrayedParams.reduce(collectAssoc, {} as any);
@@ -153,7 +153,7 @@ export module PushImpl {
153
153
  }
154
154
 
155
155
  onerror(event: any) {
156
- let message = JSON.parse(event.data);
156
+ let message = JSON.parse(event?.data ?? null);
157
157
  //TODO replace this with a more readable Stream code
158
158
  for (let i = clientIdsByTokens[this.channelToken].length - 1; i >= 0; i--) {
159
159
  let socketClientId = clientIdsByTokens[this.channelToken][i];
@@ -41,7 +41,8 @@ export function encodeFormData(formData: Config,
41
41
  */
42
42
  export function decodeEncodedValues(encoded: string): string[][] {
43
43
  const filterBlanks = item => !!(item || '').replace(/\s+/g, '');
44
- const splitKeyValuePair = line => {
44
+ const splitKeyValuePair = _line => {
45
+ let line = decodeURIComponent(_line);
45
46
  let index = line.indexOf("=");
46
47
  if (index == -1) {
47
48
  return [line];
@@ -49,7 +50,7 @@ export function decodeEncodedValues(encoded: string): string[][] {
49
50
  return [line.substring(0, index), line.substring(index + 1)];
50
51
  };
51
52
 
52
- let requestParamEntries = decodeURIComponent(encoded).split(/&/gi);
53
+ let requestParamEntries = encoded.split(/&/gi);
53
54
  return requestParamEntries.filter(filterBlanks).map(splitKeyValuePair);
54
55
  }
55
56
 
@@ -59,7 +59,7 @@ export class HiddenInputBuilder {
59
59
 
60
60
  let existingStates = DQ$(`[name*='${$nsp(this.name)}']`);
61
61
  let cnt = existingStates.asArray.map(state => {
62
- let ident: string = state.id.orElse("-1").value;
62
+ let ident: string = state.id.orElse("0").value;
63
63
  ident = ident.substring(ident.lastIndexOf(SEP)+1);
64
64
  return parseInt(ident);
65
65
  })
@@ -68,7 +68,7 @@ export class HiddenInputBuilder {
68
68
  })
69
69
  .reduce((item1, item2) => {
70
70
  return Math.max(item1, item2);
71
- }, -1);
71
+ }, 0); //we start with 1 (see cnt++)
72
72
  //the maximum new ident is the current max + 1
73
73
  cnt++;
74
74
 
@@ -75,6 +75,10 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
75
75
 
76
76
  private xhrObject = new XMLHttpRequest();
77
77
 
78
+ static readonly TYPE_CHECKBOX = "checkbox";
79
+ static readonly TYPE_RADIO = "radio";
80
+
81
+
78
82
  /**
79
83
  * Required Parameters
80
84
  *
@@ -150,13 +154,7 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
150
154
  requestPassThroughParams.$nspEnabled = true;
151
155
  }
152
156
 
153
- const issuingItemId = this.internalContext.getIf(CTX_PARAM_SRC_CTL_ID).value;
154
- if(issuingItemId) {
155
- const issuingItem = DQ.byId(issuingItemId);
156
- const arr = new ExtConfig({});
157
- arr.assign(issuingItemId).value = issuingItem.val;
158
- formData.shallowMerge(arr, true, true);
159
- }
157
+ this.appendIssuingItem(formData);
160
158
 
161
159
  this.responseContext = requestPassThroughParams.deepCopy;
162
160
 
@@ -385,7 +383,6 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
385
383
  // We need to resolve the local handlers lazily,
386
384
  // because some frameworks might decorate them over the context in the response
387
385
  let eventHandler = resolveHandlerFunc(this.requestContext, this.responseContext, ON_EVENT);
388
-
389
386
  Implementation.sendEvent(eventData, eventHandler);
390
387
  } catch (e) {
391
388
  e.source = e?.source ?? this.requestContext.getIf(SOURCE).value;
@@ -407,4 +404,27 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
407
404
 
408
405
  Implementation.sendError(errorData, eventHandler);
409
406
  }
407
+
408
+ private appendIssuingItem(formData: XhrFormData) {
409
+ const issuingItemId = this.internalContext.getIf(CTX_PARAM_SRC_CTL_ID).value;
410
+ //not encoded
411
+ if(issuingItemId && formData.getIf(issuingItemId).isAbsent()) {
412
+ const issuingItem = DQ.byId(issuingItemId);
413
+ const itemValue = issuingItem.inputValue;
414
+ const arr = new ExtConfig({});
415
+ const type: string = issuingItem.type.orElse("").value.toLowerCase();
416
+
417
+ //Checkbox and radio only value pass if checked is set, otherwise they should not show
418
+ //up at all, and if checked is set, they either can have a value or simply being boolean
419
+ if((type == XhrRequest.TYPE_CHECKBOX || type == XhrRequest.TYPE_RADIO) && !issuingItem.checked) {
420
+ return;
421
+ } else if((type == XhrRequest.TYPE_CHECKBOX || type == XhrRequest.TYPE_RADIO)) {
422
+ arr.assign(issuingItemId).value = itemValue.orElse(true).value;
423
+ } else if (itemValue.isPresent()) {
424
+ arr.assign(issuingItemId).value = itemValue.value;
425
+ }
426
+
427
+ formData.shallowMerge(arr, true, true);
428
+ }
429
+ }
410
430
  }
@@ -273,6 +273,47 @@ export module StandardInits {
273
273
  </html>`;
274
274
 
275
275
 
276
+ const VIRTUAL_ELEMENT = `<!DOCTYPE html>
277
+ <html lang="en">
278
+ <head>
279
+ <meta charset="UTF-8">
280
+ <title>Title</title>
281
+ </head>
282
+ <body>
283
+ <form id="jd_0:blarg">
284
+ <tobago-multi-select id="page:numbers">
285
+ <input type="checkbox" name="page:numbers" id="page:numbers:1" value="1"></input>
286
+ <input type="checkbox" name="page:numbers" id="page:numbers:2" value="2"></input>
287
+ <input type="checkbox" name="page:numbers" id="page:numbers:3" value="3"></input>
288
+ </tobago-multi-select>
289
+ </form>
290
+ </body>
291
+ </html>`;
292
+
293
+
294
+ const CHECKBOX_RADIO_FORM = `
295
+ <!DOCTYPE html>
296
+ <html lang="en">
297
+ <head>
298
+ <meta charset="UTF-8">
299
+ <title>Title</title>
300
+ </head>
301
+ <body>
302
+ <form id="form1">
303
+ <input type="checkbox" checked name="page:numbers:1" id="page:numbers:1" value="1"></input>
304
+ <input type="checkbox" name="page:numbers:2" id="page:numbers:2" value="2"></input>
305
+ <input type="checkbox" name="page:numbers:3" id="page:numbers:3" value="3"></input>
306
+ </form>
307
+
308
+ <form id="form2">
309
+ <input type="radio" checked name="page:numbers:r:1" id="page:numbers:r:1" value="1"></input>
310
+ <input type="radio" name="page:numbers:r:2" id="page:numbers:r:2" value="2"></input>
311
+ <input type="radio" name="page:numbers:r:3" id="page:numbers:r:3" value="3"></input>
312
+ </form>
313
+ </body>
314
+ </html>
315
+ `;
316
+
276
317
 
277
318
  /**
278
319
  * a page simulating basically a simple faces form
@@ -499,6 +540,15 @@ function triggerRequestChain(event) {
499
540
  export function defaultMyFacesNamespaces(withJsf = true): Promise<() => void> {
500
541
  return init(HTML_FORM_NAMESPACED, withJsf);
501
542
  }
543
+
544
+ export function initVirtualElement(withJsf = true): Promise<() => void> {
545
+ return init(VIRTUAL_ELEMENT, withJsf);
546
+ }
547
+
548
+ export function initCheckboxRadioForm(withJsf = true): Promise<() => void> {
549
+ return init(CHECKBOX_RADIO_FORM, withJsf);
550
+ }
551
+
502
552
  export function defaultMyFaces23(withJsf = true): Promise<() => void> {
503
553
  return init(HTML_FORM_DEFAULT.replace(/jakarta/gi, "javax"), withJsf, false);
504
554
  }
@@ -140,6 +140,91 @@ describe('faces.ajax.request test suite', () => {
140
140
  });
141
141
 
142
142
 
143
+ it("chain must handle the true false return values correctly", function () {
144
+ let func1 = () => {
145
+ return true;
146
+ }
147
+ let func2 = () => {
148
+ return false;
149
+ }
150
+
151
+ let func3 = () => {
152
+ return undefined;
153
+ }
154
+
155
+ let func4 = () => {
156
+ return null;
157
+ }
158
+
159
+ let ret = faces.util.chain(this, {}, func1);
160
+ expect(ret).to.be.true;
161
+
162
+ ret = faces.util.chain(this, {}, func2);
163
+ expect(ret).to.be.false;
164
+
165
+ ret = faces.util.chain(this, {}, func3);
166
+ expect(ret).to.be.true;
167
+
168
+ ret = faces.util.chain(this, {}, func4);
169
+ expect(ret).to.be.true;
170
+
171
+ })
172
+
173
+ it("sidebehavior chain on undefined must not break the chain only a dedicated false does", function() {
174
+ let called = {};
175
+ window.called = called;
176
+
177
+ let func1 = () => {
178
+ called["func1"] = true;
179
+ return true;
180
+ }
181
+
182
+ let func2 = `function func2(called) {
183
+ called["func2"] = true;
184
+ return true;
185
+ }`;
186
+
187
+ let func3 = () => {
188
+ called["func3"] = true;
189
+ return null;
190
+ }
191
+
192
+ let func4 = `return (function func4(called) {
193
+ called["func4"] = true;
194
+ return undefined;
195
+ })(event)`;
196
+
197
+ let func5 = `return (function func4(called) {
198
+ called["func5"] = true;
199
+ return false;
200
+ })(event)`;
201
+
202
+
203
+
204
+ let func6 = () => {
205
+ called["func6"] = true;
206
+ return false;
207
+ };
208
+ delete Array.prototype["flatMap"];
209
+ faces.util.chain(this, called, func1, func2, func3, func4, func5, func6);
210
+
211
+ expect(called["func1"]).to.be.true;
212
+ expect(called["func2"]).to.be.true;
213
+ expect(!!called["func3"]).to.be.true;
214
+ expect(!!called["func4"]).to.be.true;
215
+ expect(!!called["func5"]).to.be.true;
216
+ expect(!!called["func6"]).to.be.false;
217
+
218
+ /*called = {};
219
+ faces.util.chain(this, called, func1, func2, func4, func5, func6);
220
+ expect(called["func1"]).to.be.true;
221
+ expect(called["func2"]).to.be.true;
222
+ expect(!!called["func4"]).to.be.true;
223
+ expect(!!called["func5"]).to.be.false;*/
224
+ });
225
+
226
+
227
+
143
228
 
144
229
 
145
230
  });