jsf.js_next_gen 4.0.2-beta.8 → 4.0.3-beta.1

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 (42) hide show
  1. package/dist/window/faces-development.js +86 -56
  2. package/dist/window/faces-development.js.map +1 -1
  3. package/dist/window/faces.js +1 -1
  4. package/dist/window/faces.js.map +1 -1
  5. package/dist/window/jsf-development.js +86 -56
  6. package/dist/window/jsf-development.js.map +1 -1
  7. package/dist/window/jsf.js +1 -1
  8. package/dist/window/jsf.js.map +1 -1
  9. package/faulty_response.html +167 -0
  10. package/package.json +1 -1
  11. package/src/main/typescript/impl/AjaxImpl.ts +22 -19
  12. package/src/main/typescript/impl/PushImpl.ts +1 -1
  13. package/src/main/typescript/impl/core/Const.ts +1 -1
  14. package/src/main/typescript/impl/xhrCore/ErrorData.ts +20 -15
  15. package/src/main/typescript/impl/xhrCore/XhrRequest.ts +78 -27
  16. package/src/main/typescript/test/impl/ImplTest.spec.ts +85 -0
  17. package/src/main/typescript/test/xhrCore/EventTests.spec.ts +1 -1
  18. package/src/main/typescript/test/xhrCore/RequestTest.spec.ts +3 -3
  19. package/src/main/typescript/test/xhrCore/RequestTest_23.spec.ts +3 -3
  20. package/src/main/typescript/test/xhrCore/ResponseTest.spec.ts +2 -2
  21. package/target/impl/AjaxImpl.js +21 -19
  22. package/target/impl/AjaxImpl.js.map +1 -1
  23. package/target/impl/PushImpl.js +3 -3
  24. package/target/impl/PushImpl.js.map +1 -1
  25. package/target/impl/core/Const.js +2 -2
  26. package/target/impl/core/Const.js.map +1 -1
  27. package/target/impl/xhrCore/ErrorData.js +11 -10
  28. package/target/impl/xhrCore/ErrorData.js.map +1 -1
  29. package/target/impl/xhrCore/XhrRequest.js +49 -22
  30. package/target/impl/xhrCore/XhrRequest.js.map +1 -1
  31. package/target/test/impl/ImplTest.spec.js +64 -0
  32. package/target/test/impl/ImplTest.spec.js.map +1 -1
  33. package/target/test/xhrCore/EventTests.spec.js +1 -1
  34. package/target/test/xhrCore/EventTests.spec.js.map +1 -1
  35. package/target/test/xhrCore/RequestTest.spec.js +3 -4
  36. package/target/test/xhrCore/RequestTest.spec.js.map +1 -1
  37. package/target/test/xhrCore/RequestTest_23.spec.js +3 -3
  38. package/target/test/xhrCore/RequestTest_23.spec.js.map +1 -1
  39. package/target/test/xhrCore/ResponseTest.spec.js +2 -2
  40. package/target/test/xhrCore/ResponseTest.spec.js.map +1 -1
  41. package/webpack.config.js +54 -0
  42. package/webpack.config.js.map +1 -0
@@ -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.8",
3
+ "version": "4.0.3-beta.1",
4
4
  "description": "A next generation typescript reimplementation of jsf.js",
5
5
  "main": "dist/window/faces.js",
6
6
  "scripts": {
@@ -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];
@@ -90,7 +90,7 @@ export const RESPONSE_TEXT = "responseText";
90
90
  export const RESPONSE_XML = "responseXML";
91
91
 
92
92
  /*ajax errors spec 14.4.2*/
93
- export const HTTPERROR = "httpError";
93
+ export const HTTP_ERROR = "httpError";
94
94
  export const EMPTY_RESPONSE = "emptyResponse";
95
95
  export const MALFORMEDXML = "malformedXML";
96
96
  export const SERVER_ERROR = "serverError";
@@ -16,14 +16,14 @@
16
16
  import {
17
17
  EMPTY_STR, ERROR,
18
18
  ERROR_MESSAGE,
19
- ERROR_NAME,
19
+ ERROR_NAME, HTTP_ERROR,
20
20
  RESPONSE_TEXT,
21
21
  RESPONSE_XML, SERVER_ERROR,
22
22
  SOURCE,
23
23
  STATUS,
24
24
  UNKNOWN
25
25
  } from "../core/Const";
26
- import {Config} from "mona-dish";
26
+ import {Config, Optional, XMLQuery} from "mona-dish";
27
27
 
28
28
  import {EventData} from "./EventData";
29
29
  import {ExtLang} from "../util/Lang";
@@ -49,8 +49,8 @@ export enum ErrorType {
49
49
  export class ErrorData extends EventData implements IErrorData {
50
50
 
51
51
  type: string = "error";
52
- source: HTMLElement;
53
- sourceId: string;
52
+ source: string;
53
+
54
54
  errorName: string;
55
55
  errorMessage: string;
56
56
 
@@ -62,19 +62,24 @@ export class ErrorData extends EventData implements IErrorData {
62
62
 
63
63
  serverErrorName: string;
64
64
  serverErrorMessage: string;
65
- message: string;
65
+ description: string;
66
66
 
67
- constructor(source: string, errorName: string, errorMessage: string, responseText: string = null, responseXML: any = null, responseCode: string = "200", status: string = "", type = ErrorType.CLIENT_ERROR) {
67
+ constructor(source: string, errorName: string, errorMessage: string, responseText: string = null, responseXML: Document = null, responseCode: number = -1, statusOverride: string = null, type = ErrorType.CLIENT_ERROR) {
68
68
  super();
69
- this.source = document.getElementById(source);
70
- this.sourceId = source;
69
+ this.source = source;
71
70
  this.type = ERROR;
72
71
  this.errorName = errorName;
72
+
73
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;
75
- this.responseCode = responseCode;
74
+ this.errorMessage = errorMessage;
75
+ this.responseCode = `${responseCode}`;
76
76
  this.responseText = responseText;
77
- this.status = status;
77
+ this.responseXML = responseXML;
78
+
79
+ this.status = statusOverride;
80
+
81
+ this.description = `Status: ${this.status}\nResponse Code: ${this.responseCode}\nError Message: ${this.errorMessage}`;
82
+
78
83
  this.typeDetails = type;
79
84
 
80
85
  if (type == ErrorType.SERVER_ERROR) {
@@ -87,8 +92,8 @@ export class ErrorData extends EventData implements IErrorData {
87
92
  return new ErrorData((e as any)?.source ?? "client", e?.name ?? EMPTY_STR, e?.message ?? EMPTY_STR, e?.stack ?? EMPTY_STR);
88
93
  }
89
94
 
90
- static fromHttpConnection(source: any, name: string, message: string, responseText, responseCode: number, status: string = EMPTY_STR): ErrorData {
91
- return new ErrorData(source, name, message, responseText, responseCode, `${responseCode}`, status, ErrorType.HTTP_ERROR);
95
+ static fromHttpConnection(source: any, name: string, message: string, responseText: string, responseXML: Document, responseCode: number, status: string = EMPTY_STR): ErrorData {
96
+ return new ErrorData(source, name, message, responseText, responseXML, responseCode, status, ErrorType.HTTP_ERROR);
92
97
  }
93
98
 
94
99
  static fromGeneric(context: Config, errorCode: number, errorType: ErrorType = ErrorType.SERVER_ERROR): ErrorData {
@@ -100,10 +105,10 @@ export class ErrorData extends EventData implements IErrorData {
100
105
  let errorMessage = getMsg(context, ERROR_MESSAGE);
101
106
  let status = getMsg(context, STATUS);
102
107
  let responseText = getMsg(context, RESPONSE_TEXT);
103
- let responseXML = getMsg(context, RESPONSE_XML);
108
+ let responseXML: Document = context.getIf(RESPONSE_XML).value;
104
109
 
105
110
 
106
- return new ErrorData(source, errorName, errorMessage, responseText, responseXML, errorCode + EMPTY_STR, status, errorType);
111
+ return new ErrorData(source, errorName, errorMessage, responseText, responseXML, errorCode, status, errorType);
107
112
  }
108
113
 
109
114
  private static getMsg(context, param) {
@@ -15,7 +15,7 @@
15
15
  */
16
16
 
17
17
  import {AsyncRunnable, IAsyncRunnable} from "../util/AsyncRunnable";
18
- import {Config, DQ} from "mona-dish";
18
+ import {Config, DQ, XMLQuery} from "mona-dish";
19
19
  import {Implementation} from "../AjaxImpl";
20
20
 
21
21
  import {XhrFormData} from "./XhrFormData";
@@ -34,14 +34,23 @@ import {
34
34
  MALFORMEDXML,
35
35
  NO_TIMEOUT,
36
36
  ON_ERROR,
37
- ON_EVENT, P_EXECUTE,
37
+ ON_EVENT,
38
+ P_EXECUTE,
38
39
  REQ_ACCEPT,
39
40
  REQ_TYPE_GET,
40
- REQ_TYPE_POST, SOURCE,
41
+ REQ_TYPE_POST,
42
+ SOURCE,
41
43
  STATE_EVT_TIMEOUT,
42
44
  STD_ACCEPT,
43
45
  URL_ENCODED,
44
- VAL_AJAX, IDENT_NONE, CTX_PARAM_SRC_FRM_ID, CTX_PARAM_SRC_CTL_ID, CTX_PARAM_PPS
46
+ VAL_AJAX,
47
+ IDENT_NONE,
48
+ CTX_PARAM_SRC_FRM_ID,
49
+ CTX_PARAM_SRC_CTL_ID,
50
+ CTX_PARAM_PPS,
51
+ P_AJAX_SOURCE,
52
+ RESPONSE_TEXT,
53
+ RESPONSE_XML, STATUS, EMPTY_RESPONSE, HTTP_ERROR, UNKNOWN, SERVER_ERROR, EMPTY_STR
45
54
  } from "../core/Const";
46
55
  import {
47
56
  resolveFinalUrl,
@@ -75,6 +84,10 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
75
84
 
76
85
  private xhrObject = new XMLHttpRequest();
77
86
 
87
+ static readonly TYPE_CHECKBOX = "checkbox";
88
+ static readonly TYPE_RADIO = "radio";
89
+
90
+
78
91
  /**
79
92
  * Required Parameters
80
93
  *
@@ -126,7 +139,6 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
126
139
  executes, partialIdsArray
127
140
  );
128
141
 
129
-
130
142
  this.contentType = formData.isMultipartRequest ? "undefined" : this.contentType;
131
143
 
132
144
  // next step the pass through parameters are merged in for post params
@@ -279,7 +291,7 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
279
291
  // reject means clear queue, in this case we abort entirely the processing
280
292
  // does not happen yet, we have to probably rethink this strategy in the future
281
293
  // when we introduce cancel functionality
282
- this.handleGenericError(reject);
294
+ this.handleHttpError(reject);
283
295
  }
284
296
 
285
297
  /**
@@ -293,7 +305,7 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
293
305
  // timeout also means we we probably should clear the queue,
294
306
  // the state is unsafe for the next requests
295
307
  this.sendEvent(STATE_EVT_TIMEOUT);
296
- this.handleGenericError(resolve);
308
+ this.handleHttpError(resolve);
297
309
  }
298
310
 
299
311
  /**
@@ -307,27 +319,66 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
307
319
  private onResponseReceived(resolve: Consumer<any>) {
308
320
 
309
321
  this.sendEvent(COMPLETE);
310
- /*
311
- * second on error path
312
- */
313
- if ((this.xhrObject?.status ?? 0) >= 300 || !this?.xhrObject?.responseXML) {
314
- // all errors from the server are resolved without interfering in the queue
315
- this.handleGenericError(resolve);
316
- return;
322
+
323
+ //request error resolution as per spec:
324
+ if(!this.processRequestErrors(resolve)) {
325
+ $faces().ajax.response(this.xhrObject, this.responseContext.value ?? {});
317
326
  }
327
+ }
318
328
 
319
- $faces().ajax.response(this.xhrObject, this.responseContext.value ?? {});
329
+ private processRequestErrors(resolve: Consumer<any>): boolean {
330
+ const responseXML = new XMLQuery(this.xhrObject?.responseXML);
331
+ const responseCode = this.xhrObject?.status ?? -1;
332
+ if(responseXML.isXMLParserError()) {
333
+ // invalid response
334
+ const errorName = "Invalid Response";
335
+ const errorMessage = "The response xml is invalid";
336
+
337
+ this.handleGenericResponseError(errorName, errorMessage, MALFORMEDXML, resolve);
338
+ return true;
339
+ } else if(responseXML.isAbsent()) {
340
+ // empty response
341
+ const errorName = "Empty Response";
342
+ const errorMessage = "The response has provided no data";
343
+
344
+ this.handleGenericResponseError(errorName, errorMessage, EMPTY_RESPONSE, resolve);
345
+ return true;
346
+ } else if (responseCode >= 300 || responseCode < 200) {
347
+ // other server errors
348
+ // all errors from the server are resolved without interfering in the queue
349
+ this.handleHttpError(resolve);
350
+ return true;
351
+ }
352
+ //additional errors are application errors and must be handled within the response
353
+ return false;
354
+ }
355
+ private handleGenericResponseError(errorName: string, errorMessage: string, responseStatus: string, resolve: (s?: any) => void) {
356
+ const errorData: ErrorData = new ErrorData(
357
+ this.internalContext.getIf(CTX_PARAM_SRC_CTL_ID).value,
358
+ errorName, errorMessage,
359
+ this.xhrObject?.responseText ?? "",
360
+ this.xhrObject?.responseXML ?? null,
361
+ this.xhrObject.status,
362
+ responseStatus
363
+ );
364
+ this.finalizeError(errorData, resolve);
320
365
  }
321
366
 
322
- private handleGenericError(resolveOrReject: Function) {
367
+ private handleHttpError(resolveOrReject: Function, errorMessage: string = "Generic HTTP Serror") {
323
368
  this.stopProgress = true;
324
- const errorData = {
325
- type: ERROR,
326
- status: MALFORMEDXML,
327
- responseCode: this.xhrObject?.status ?? 400,
328
- responseText: this.xhrObject?.responseText ?? "Error",
329
- source: this.internalContext.getIf(CTX_PARAM_SRC_CTL_ID).value
330
- };
369
+
370
+ const errorData = new ErrorData(
371
+ this.internalContext.getIf(CTX_PARAM_SRC_CTL_ID).value,
372
+ HTTP_ERROR, errorMessage,
373
+ this.xhrObject?.responseText ?? "",
374
+ this.xhrObject?.responseXML ?? null,
375
+ this.xhrObject?.status ?? -1,
376
+ HTTP_ERROR
377
+ )
378
+ this.finalizeError(errorData, resolveOrReject);
379
+ }
380
+
381
+ private finalizeError(errorData: ErrorData, resolveOrReject: Function) {
331
382
  try {
332
383
  this.handleError(errorData, true);
333
384
  } finally {
@@ -335,8 +386,8 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
335
386
  // reject would clean up the queue
336
387
  // resolve would trigger the next element in the queue to be processed
337
388
  resolveOrReject(errorData);
389
+ this.stopProgress = true;
338
390
  }
339
- // non blocking non clearing
340
391
  }
341
392
 
342
393
  /**
@@ -395,7 +446,7 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
395
446
  }
396
447
 
397
448
  private handleError(exception, responseFormatError: boolean = false) {
398
- const errorData = (responseFormatError) ? ErrorData.fromHttpConnection(exception.source, exception.type, exception.status, exception.responseText, exception.responseCode, exception.status) : ErrorData.fromClient(exception);
449
+ const errorData = (responseFormatError) ? ErrorData.fromHttpConnection(exception.source, exception.type, exception.message ?? EMPTY_STR, exception.responseText, exception.responseXML, exception.responseCode, exception.status) : ErrorData.fromClient(exception);
399
450
  const eventHandler = resolveHandlerFunc(this.requestContext, this.responseContext, ON_ERROR);
400
451
 
401
452
  Implementation.sendError(errorData, eventHandler);
@@ -412,9 +463,9 @@ export class XhrRequest extends AsyncRunnable<XMLHttpRequest> {
412
463
 
413
464
  //Checkbox and radio only value pass if checked is set, otherwise they should not show
414
465
  //up at all, and if checked is set, they either can have a value or simply being boolean
415
- if((type == "checkbox" || type == "radio") && !issuingItem.checked) {
466
+ if((type == XhrRequest.TYPE_CHECKBOX || type == XhrRequest.TYPE_RADIO) && !issuingItem.checked) {
416
467
  return;
417
- } else if((type == "checkbox" || type == "radio")) {
468
+ } else if((type == XhrRequest.TYPE_CHECKBOX || type == XhrRequest.TYPE_RADIO)) {
418
469
  arr.assign(issuingItemId).value = itemValue.orElse(true).value;
419
470
  } else if (itemValue.isPresent()) {
420
471
  arr.assign(issuingItemId).value = itemValue.value;
@@ -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
  });
@@ -111,7 +111,7 @@ describe('tests the addOnEvent and addOnError handling', function () {
111
111
  expect(onErrorCalled1).to.eq(1);
112
112
  expect(onErrorCalled2).to.eq(1);
113
113
  expect(errorTitle).to.eq('Erro21');
114
- expect(errorMessage).to.eq('serverError: Error2 Text');
114
+ expect(errorMessage).to.eq('Error2 Text');
115
115
  } finally {
116
116
  console.error = oldErr;
117
117
  }