You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2024/10/28 14:14:34 UTC
(myfaces-tobago) branch main updated: fix: Better validation for upload (#5634)
This is an automated email from the ASF dual-hosted git repository.
lofwyr pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
The following commit(s) were added to refs/heads/main by this push:
new 57e09ed8f5 fix: Better validation for upload (#5634)
57e09ed8f5 is described below
commit 57e09ed8f54f0d6117f81a8b791733df6f4a85ed
Author: Udo Schnurpfeil <lo...@apache.org>
AuthorDate: Mon Oct 28 15:14:29 2024 +0100
fix: Better validation for upload (#5634)
Better client validation before uploading
large files. Uploading too large files
should fail eary.
issue: TOBAGO-2361
issue: TOBAGO-2353
---
.../webapp/content/100-upload/File_Upload.xhtml | 1 +
.../tobago-theme-standard/src/main/js/tobago.js | 8 +--
.../src/main/js/tobago.js.map | 2 +-
.../src/main/ts/tobago-behavior.ts | 82 +++++++++++++++++++++-
.../src/main/ts/tobago-file.ts | 9 ++-
.../src/main/ts/tobago-init.ts | 8 ++-
6 files changed, 101 insertions(+), 9 deletions(-)
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/100-upload/File_Upload.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/100-upload/File_Upload.xhtml
index 785c02a304..4dc9cf49f7 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/100-upload/File_Upload.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/100-upload/File_Upload.xhtml
@@ -82,6 +82,7 @@
<p>Ajax can be activated by adding <code class="language-markup"><f:ajax/></code>
to the <code class="language-markup"><tc:file/></code> tag.</p>
<tc:file label="Ajax" value="#{uploadController.fileAjax}" id="fileAjax">
+ <tc:validateFileItem maxSize="1048576"/>
<f:ajax listener="#{uploadController.uploadAjax}" render="s3 list :page:messages"/>
</tc:file>
</tc:section>
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
index 7a6e2ee8cf..4d1f05a991 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
@@ -1,19 +1,19 @@
-!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";var e,t;!function(e){e.ACTIVE="active",e.AUTOCOMPLETE="autocomplete",e.AUTOCOMPLETE_INPUT="autocomplete-input",e.BOTTOM_0="bottom-0",e.COLLAPSE="collapse",e.COLLAPSING="collapsing",e.D_NONE="d-none",e.DISABLED="disabled",e.DROPDOWN="dropdown",e.DROPDOWN_ITEM="dropdown-item",e.DROPDOWN_MENU="dropdown-menu",e.DROPDOWN_MENU_END="dropdown-menu-end",e.END_0="end-0",e.FADE="fade",e.FIXED_BOTTOM="fixed-bo [...]
+!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";var e,t;!function(e){e.ACTIVE="active",e.AUTOCOMPLETE="autocomplete",e.AUTOCOMPLETE_INPUT="autocomplete-input",e.BOTTOM_0="bottom-0",e.COLLAPSE="collapse",e.COLLAPSING="collapsing",e.D_NONE="d-none",e.DISABLED="disabled",e.DROPDOWN="dropdown",e.DROPDOWN_ITEM="dropdown-item",e.DROPDOWN_MENU="dropdown-menu",e.DROPDOWN_MENU_END="dropdown-menu-end",e.END_0="end-0",e.FADE="fade",e.FIXED_BOTTOM="fixed-bo [...]
/*!
* Bootstrap v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
-const $e=new Map,Pe={set(e,t,s){$e.has(e)||$e.set(e,new Map);const i=$e.get(e);i.has(t)||0===i.size?i.set(t,s):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(i.keys())[0]}.`)},get:(e,t)=>$e.has(e)&&$e.get(e).get(t)||null,remove(e,t){if(!$e.has(e))return;const s=$e.get(e);s.delete(t),0===s.size&&$e.delete(e)}},Be="transitionend",He=e=>(e&&window.CSS&&window.CSS.escape&&(e=e.replace(/#([^\s"#']+)/g,((e,t)=>`#${CSS.escape(t)}`))),e),q [...]
+const pt=new Map,gt={set(e,t,s){pt.has(e)||pt.set(e,new Map);const i=pt.get(e);i.has(t)||0===i.size?i.set(t,s):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(i.keys())[0]}.`)},get:(e,t)=>pt.has(e)&&pt.get(e).get(t)||null,remove(e,t){if(!pt.has(e))return;const s=pt.get(e);s.delete(t),0===s.size&&pt.delete(e)}},ft="transitionend",mt=e=>(e&&window.CSS&&window.CSS.escape&&(e=e.replace(/#([^\s"#']+)/g,((e,t)=>`#${CSS.escape(t)}`))),e),b [...]
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
- */const lr=globalThis,cr=lr.trustedTypes,dr=cr?cr.createPolicy("lit-html",{createHTML:e=>e}):void 0,ur="$lit$",hr=`lit$${Math.random().toFixed(9).slice(2)}$`,pr="?"+hr,gr=`<${pr}>`,fr=document,mr=()=>fr.createComment(""),br=e=>null===e||"object"!=typeof e&&"function"!=typeof e,vr=Array.isArray,_r="[ \t\n\f\r]",yr=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,wr=/-->/g,Er=/>/g,Ar=RegExp(`>|${_r}(?:([^\\s"'>=/]+)(${_r}*=${_r}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),Sr=/'/g,Lr [...]
+ */const ar=globalThis,lr=ar.trustedTypes,cr=lr?lr.createPolicy("lit-html",{createHTML:e=>e}):void 0,dr="$lit$",ur=`lit$${Math.random().toFixed(9).slice(2)}$`,hr="?"+ur,pr=`<${hr}>`,gr=document,fr=()=>gr.createComment(""),mr=e=>null===e||"object"!=typeof e&&"function"!=typeof e,br=Array.isArray,vr="[ \t\n\f\r]",_r=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,yr=/-->/g,wr=/>/g,Er=RegExp(`>|${vr}(?:([^\\s"'>=/]+)(${vr}*=${vr}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),Ar=/'/g,Sr [...]
<button type='button'
class='tobago-button btn btn-secondary badge' aria-label='deselect ${e}'
${s>0?" tabindex='"+String(s)+"'":""}
@click="${this.removeBadge.bind(this)}"
@focus="${this.focusEvent.bind(this)}"
- @blur="${this.blurEvent.bind(this)}"><i class='bi-x-lg'></i></button>`}removeBadge(e){var t;const s=e.target.closest(".btn-group").dataset.tobagoValue,i=this.hiddenSelect.querySelector(`[value="${s}"]`);i.selected=!1;const n=this.badges.querySelector(`[data-tobago-value="${s}"]`),o=n.previousElementSibling,r="SPAN"===(null===(t=n.nextElementSibling)||void 0===t?void 0:t.tagName)?n.nextElementSibling:null;o?o.querySelector("button.btn.badge").focus():r?r.querySelector("button.btn.ba [...]
+ @blur="${this.blurEvent.bind(this)}"><i class='bi-x-lg'></i></button>`}removeBadge(e){var t;const s=e.target.closest(".btn-group").dataset.tobagoValue,i=this.hiddenSelect.querySelector(`[value="${s}"]`);i.selected=!1;const n=this.badges.querySelector(`[data-tobago-value="${s}"]`),o=n.previousElementSibling,r="SPAN"===(null===(t=n.nextElementSibling)||void 0===t?void 0:t.tagName)?n.nextElementSibling:null;o?o.querySelector("button.btn.badge").focus():r?r.querySelector("button.btn.ba [...]
//# sourceMappingURL=tobago.js.map
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
index 5947bad160..3c83d89642 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago.js","sources":["../ts/tobago-css.ts","../ts/tobago-collapse-operation.ts","../ts/tobago-bar.ts","../../../../node_modules/@popperjs/core/lib/enums.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js","../../../../node_modules/@poppe [...]
\ No newline at end of file
+{"version":3,"file":"tobago.js","sources":["../ts/tobago-css.ts","../ts/tobago-key.ts","../ts/tobago-bar.ts","../ts/tobago-date.ts","../ts/tobago-menu-store.ts","../../../../node_modules/@popperjs/core/lib/enums.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../../../node_modules/@popperjs/core/lib/modifiers/applyStyles [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-behavior.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-behavior.ts
index 6c23fcf4e2..ad8d310a09 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-behavior.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-behavior.ts
@@ -74,6 +74,24 @@ class Behavior extends HTMLElement {
}
}
+ switch (this.mode) {
+ case BehaviorMode.ajax:
+ if (!this.validate(this.execute)) {
+ console.warn("Validation failed! No request will be sent.");
+ return;
+ }
+ break;
+ case BehaviorMode.full:
+ // todo: not implemented/activated yet, because this implementation doesn't support sub-forms
+ // if (!this.validate(Page.page(this).id)) {
+ // console.warn("Validation failed! No request will be sent.");
+ // return;
+ // }
+ break;
+ default:
+ // nothing to do
+ }
+
if (this.collapseOperation && this.collapseTarget) {
const rootNode = this.getRootNode() as ShadowRoot | Document;
Collapse.execute(this.collapseOperation, rootNode.getElementById(this.collapseTarget), this.mode);
@@ -89,7 +107,7 @@ class Behavior extends HTMLElement {
if (partialElement) {
let id: string;
if (partialElement.tagName === "TOBAGO-POPUP") {
- // popup needs no overlay, is has no area to show
+ // popup needs no overlay, it has no area to show
id = partialElement.querySelector(".modal-dialog").id;
} else {
id = partialElement.id;
@@ -101,6 +119,43 @@ class Behavior extends HTMLElement {
}
}
}
+ /*
+ // TODO: Sketch for Progressbar
+ // register callback for the AJAX-event
+ faces.ajax.addOnEvent(function (data) {
+ if (data.status === "success") {
+ // Access the XmlHttpRequest-Object after successful AJAX-request
+ const xhr: XMLHttpRequest = data.source;
+ // Event listener to monitor the upload progress
+ console.log("xhr", xhr);
+ if (xhr) {
+ console.log("xhr.upload", xhr.upload);
+ if (xhr.upload) {
+ xhr.upload.onprogress = function (event) {
+ if (event.lengthComputable) {
+ // Calculate the percentage of upload completed
+ const percentComplete = (event.loaded / event.total) * 100;
+ console.info(`Progress: ${Math.round(percentComplete)}%`);
+ }
+ };
+ } else {
+ console.error("xhr.upload null");
+ }
+ } else {
+ console.error("xhr null");
+ }
+ console.log("AJAX-request success.");
+ } else if (data.status === "begin") {
+ console.log("AJAX-request begin.");
+ } else if (data.status === "complete") {
+ console.log("AJAX-request complete.");
+ }
+ });
+ // register error handling
+ faces.ajax.addOnError(function (data) {
+ console.error("Error AJAX-request:", data);
+ });
+ */
faces.ajax.request(
this.actionElement,
event,
@@ -168,6 +223,31 @@ class Behavior extends HTMLElement {
}
}
+ validate(ids: string): boolean {
+ let allValid = true;
+ if (ids) {
+ console.debug("Is all valid? ids=", ids);
+ for (const id of ids.split(/\s+/)) {
+ const element = document.getElementById(id);
+ if (element) {
+ const formElements = element.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(
+ "input, textarea, select"
+ );
+ for (const formElement of formElements) {
+ if (!formElement.checkValidity()) {
+ console.debug("invalid", formElement.id);
+ allValid = false;
+ } else {
+ console.debug("valid", formElement.id);
+ }
+ }
+ }
+ }
+ console.debug("Is all valid?", allValid);
+ return allValid;
+ }
+ }
+
get mode(): BehaviorMode {
if (this.render || this.execute) {
return BehaviorMode.ajax;
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-file.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-file.ts
index 11f6cbd618..484f723992 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-file.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-file.ts
@@ -121,16 +121,21 @@ export class File extends HTMLElement {
const input = event.currentTarget as HTMLInputElement;
const files = input.files;
if (files) {
+ input.setCustomValidity("");
let error = false;
for (const file of files) {
if (file.size > this.maxSize) {
- window.alert(this.maxSizeMessage);
input.value = "";
+ input.setCustomValidity(this.maxSizeMessage);
+ input.reportValidity();
error = true;
+ break;
}
}
if (error) {
- event.preventDefault;
+ // only when error to prevent green checks, because we can't be sure, this is really valid (TBD)
+ this.classList.add("was-validated");
+ event.preventDefault();
event.stopPropagation();
}
}
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-init.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-init.ts
index 201265ce41..baa58f2673 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-init.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-init.ts
@@ -15,9 +15,13 @@
* limitations under the License.
*/
+/*
+formal ordering rules:
+- "tobago-file" must be before "tobago-behavior"
+*/
+
// custom elements
import "./tobago-bar";
-import "./tobago-behavior";
import "./tobago-date";
import "./tobago-dropdown";
import "./tobago-file";
@@ -53,6 +57,8 @@ import "./tobago-tree";
import "./tobago-tree-listbox";
import "./tobago-tree-node";
import "./tobago-tree-select";
+// the behavior must be registered after the custom elements, because of validation
+import "./tobago-behavior";
//polyfill
import "./tobago-polyfill";