diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all-xfa/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all-xfa/.content.xml
index 3bf1de3a89..89969144f0 100644
--- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all-xfa/.content.xml
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all-xfa/.content.xml
@@ -5,4 +5,4 @@
cssProcessor="[default:none,min:none]"
jsProcessor="[default:none,min:none]"
categories="[core.forms.components.runtime.all.xfa]"
- embed="[core.forms.components.runtime.base.xfa,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v1.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v3.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v1.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime, core.forms.components.hcaptcha.v1.runtime,core.forms.components.review.v1.runtime, core.forms.components.turnstile.v1.runtime]"/>
+ embed="[core.forms.components.runtime.base.xfa,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v1.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v3.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v1.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime, core.forms.components.hcaptcha.v1.runtime,core.forms.components.review.v1.runtime, core.forms.components.turnstile.v1.runtime, core.forms.components.customfileupload.v1.runtime]"/>
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml
index 0ef50cf14f..d0d8c106f2 100644
--- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml
@@ -5,4 +5,4 @@
cssProcessor="[default:none,min:none]"
jsProcessor="[default:none,min:none]"
categories="[core.forms.components.runtime.all]"
- embed="[core.forms.components.runtime.base,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v1.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v3.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v1.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime, core.forms.components.hcaptcha.v1.runtime,core.forms.components.review.v1.runtime, core.forms.components.turnstile.v1.runtime]"/>
+ embed="[core.forms.components.runtime.base,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v1.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v3.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v1.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime, core.forms.components.hcaptcha.v1.runtime,core.forms.components.review.v1.runtime, core.forms.components.turnstile.v1.runtime, core.forms.components.customfileupload.v1.runtime]"/>
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/.content.xml
new file mode 100644
index 0000000000..3d0c31ab4d
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/.content.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/.content.xml
new file mode 100644
index 0000000000..1437899b31
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/.content.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/.content.xml
new file mode 100644
index 0000000000..2a99c0ebaa
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/.content.xml
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/.content.xml
new file mode 100644
index 0000000000..9ccf799a9f
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/.content.xml
@@ -0,0 +1,6 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/js.txt b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/js.txt
new file mode 100644
index 0000000000..22ed485080
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/js.txt
@@ -0,0 +1,19 @@
+###############################################################################
+# Copyright 2025 Adobe
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###############################################################################
+
+#base=js
+fileinputwidget.js
+fileinputview.js
\ No newline at end of file
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/js/fileinputview.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/js/fileinputview.js
new file mode 100644
index 0000000000..3afe972702
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/js/fileinputview.js
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright 2023 Adobe
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+(function() {
+
+ "use strict";
+ class FileInputV3 extends FormView.FormFieldBase {
+
+ static NS = FormView.Constants.NS;
+ /**
+ * Each FormField has a data attribute class that is prefixed along with the global namespace to
+ * distinguish between them. If a component wants to put a data-attribute X, the attribute in HTML would be
+ * data-{NS}-{IS}-x=""
+ * @type {string}
+ */
+ static IS = "adaptiveFormCustomFileInput";
+ static bemBlock = 'cmp-adaptiveform-fileinput'
+ static selectors = {
+ self: "[data-" + this.NS + '-is="' + this.IS + '"]',
+ widget: `.${FileInputV3.bemBlock}__widget`,
+ label: `.${FileInputV3.bemBlock}__label`,
+ description: `.${FileInputV3.bemBlock}__longdescription`,
+ qm: `.${FileInputV3.bemBlock}__questionmark`,
+ errorDiv: `.${FileInputV3.bemBlock}__errormessage`,
+ tooltipDiv: `.${FileInputV3.bemBlock}__shortdescription`,
+ fileListDiv : `.${FileInputV3.bemBlock}__filelist`,
+ attachButtonLabel : `.${FileInputV3.bemBlock}__widgetlabel`,
+ dragArea: `.${FileInputV3.bemBlock}__dragarea`
+ };
+
+ constructor(params) {
+ super(params);
+ }
+ widgetFields = {
+ widget: this.getWidget(),
+ fileListDiv: this.getFileListDiv(),
+ model: () => this._model,
+ dragArea: this.getDragArea()
+ };
+
+ getWidget() {
+ return this.element.querySelector(FileInputV3.selectors.widget);
+ }
+
+ getDragArea() {
+ return this.element.querySelector(FileInputV3.selectors.dragArea);
+ }
+
+ getDescription() {
+ return this.element.querySelector(FileInputV3.selectors.description);
+ }
+
+ getLabel() {
+ return this.element.querySelector(FileInputV3.selectors.label);
+ }
+
+ getErrorDiv() {
+ return this.element.querySelector(FileInputV3.selectors.errorDiv);
+ }
+
+ getTooltipDiv() {
+ return this.element.querySelector(FileInputV3.selectors.tooltipDiv);
+ }
+
+ getQuestionMarkDiv() {
+ return this.element.querySelector(FileInputV3.selectors.qm);
+ }
+
+ getFileListDiv() {
+ return this.element.querySelector(FileInputV3.selectors.fileListDiv);
+ }
+
+ getAttachButtonLabel() {
+ return this.element.querySelector(FileInputV3.selectors.attachButtonLabel);
+ }
+
+ updateEnabled(enabled, state) {
+ if (this.widget) {
+ this.element.setAttribute(FormView.Constants.DATA_ATTRIBUTE_ENABLED, enabled);
+ const isDisabled = !enabled || state.readOnly;
+ if (isDisabled) {
+ this.widget.setAttribute("disabled", "disabled");
+ } else {
+ this.widget.removeAttribute("disabled");
+ }
+ }
+ }
+
+ updateValue(value) {
+ if (this.widgetObject == null) {
+ this.widgetObject = new CustomFileInputWidget(this.widgetFields);
+ }
+ this.widgetObject.setValue(value);
+ super.updateEmptyStatus();
+ }
+
+ setModel(model) {
+ super.setModel(model);
+ if (this.widgetObject == null) {
+ this.widgetObject = new CustomFileInputWidget(this.widgetFields);
+ }
+ this.getAttachButtonLabel().addEventListener('focus', () => {
+ this.setActive();
+ })
+ this.getAttachButtonLabel().addEventListener('blur', () => {
+ this.setInactive();
+ })
+ }
+
+ syncWidget() {
+ let widgetElement = this.getWidget ? this.getWidget() : null;
+ if (widgetElement) {
+ widgetElement.id = this.getId() + "__widget";
+ const closestElement = widgetElement?.previousElementSibling;
+ if (closestElement && closestElement.tagName.toLowerCase() === 'label') {
+ closestElement.setAttribute('for', this.getId() + "__widget");
+ } else {
+ this.getAttachButtonLabel().removeAttribute('for');
+ }
+ }
+ }
+
+ syncLabel() {
+ let labelElement = typeof this.getLabel === 'function' ? this.getLabel() : null;
+ if (labelElement) {
+ labelElement.setAttribute('for', this.getId());
+ }
+ }
+
+ syncMarkupWithModel() {
+ super.syncMarkupWithModel();
+ this.syncWidget();
+ this.syncLabel();
+ }
+ }
+
+ FormView.Utils.setupField(({element, formContainer}) => {
+ return new FileInputV3({element, formContainer})
+ }, FileInputV3.selectors.self);
+
+})();
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/js/fileinputwidget.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/js/fileinputwidget.js
new file mode 100644
index 0000000000..d97bd08707
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/clientlibs/site/js/fileinputwidget.js
@@ -0,0 +1,274 @@
+/*******************************************************************************
+ * Copyright 2025 Adobe
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+/**
+ * This class is responsible for interacting with the file input widget. It implements the file preview,
+ * file list, handling invalid file size, file name, file mime type functionality
+ */
+
+if (typeof window.CustomFileInputWidget === 'undefined') {
+ window.CustomFileInputWidget = class extends FormView.FormFileInputWidget {
+
+ constructor(params) {
+ super(params);
+ }
+
+ attachEventHandlers(widget, dragArea, model) {
+ super.attachEventHandlers(widget, dragArea, model)
+ const customBtn = dragArea?.querySelector(".cmp-adaptiveform-fileinput__widgetlabel")
+ customBtn?.addEventListener("click", () => {
+ widget.click();
+ });
+ customBtn?.addEventListener('keydown', function(event) {
+ // Check if the Enter key is pressed
+ if (event.key === 'Enter' || event.keyCode === 13) {
+ // Trigger the click event of the file input
+ widget.click();
+ }
+ });
+ }
+
+ fileItem(fileName, fileSize, comment, fileUrl) {
+ let self = this;
+ let id = `${Date.now() + '_' + Math.floor(Math.random() * 10000)}_file_size`
+ let fileItem = document.createElement('li');
+ fileItem.setAttribute("class", "cmp-adaptiveform-fileinput__fileitem");
+ let fileNameDom = document.createElement('a');
+ let fileSizeDom = document.createElement('span');
+
+ fileSizeDom.setAttribute('class', "cmp-adaptiveform-fileinput__filesize");
+ fileSizeDom.setAttribute('id', id);
+ fileSizeDom.setAttribute('hidden', true);
+ fileSizeDom.textContent = this.formatBytes(fileSize);
+
+ fileNameDom.setAttribute('tabindex', '0');
+ fileNameDom.setAttribute('class', "cmp-adaptiveform-fileinput__filename");
+ fileNameDom.setAttribute('aria-describedBY', id);
+ fileNameDom.textContent = fileName;
+ fileNameDom.addEventListener('keypress', function(e) {
+ if (e.keyCode === 13 || e.charCode === 32) {
+ e.target.click();
+ }
+ });
+ fileNameDom.addEventListener('click', function(e) {
+ self.handleFilePreview(e);
+ });
+ fileItem.appendChild(fileNameDom);
+ if(fileUrl != null){
+ fileNameDom.dataset.key = fileUrl;
+ }
+ let fileEndContainer = document.createElement('span');
+ let fileClose = document.createElement('button');
+ fileEndContainer.setAttribute('class', "cmp-adaptiveform-fileinput__fileendcontainer");
+ fileClose.setAttribute('tabindex', '0');
+ fileClose.setAttribute('class', "cmp-adaptiveform-fileinput__filedelete");
+ fileClose.setAttribute('aria-label', FormView.LanguageUtils.getTranslatedString(this.lang, "FileCloseAccessText") + fileName);
+ fileClose.textContent = "x";
+ fileClose.addEventListener('keypress', function(e) {
+ if (e.keyCode === 13 || e.charCode === 32) {
+ e.target.click();
+ }
+ });
+ fileClose.addEventListener('click', function(e) {
+ self.handleClick(e);
+ });
+ fileEndContainer.appendChild(fileSizeDom);
+ fileEndContainer.appendChild(fileClose);
+ fileItem.appendChild(fileEndContainer);
+ return fileItem;
+ }
+
+ handleChange(filesUploaded) {
+ if (!this.isFileUpdate) {
+ let currFileName = '',
+ inValidSizefileNames = '',
+ inValidNamefileNames = '',
+ inValidMimeTypefileNames = '',
+ self = this,
+ uris = [],
+ files = filesUploaded;
+ // Initially set the invalid flag to false
+ let isInvalidSize = false,
+ isInvalidFileName = false,
+ isInvalidMimeType = false;
+ //this.resetIfNotMultiSelect();
+ if (typeof files !== "undefined") {
+ let invalidFilesIndexes = [];
+ let validFiles = [];
+ Array.from(files).forEach(function (file, fileIndex) {
+ let isCurrentInvalidFileSize = false,
+ isCurrentInvalidFileName = false,
+ isCurrentInvalidMimeType = false;
+ currFileName = file.name.split("\\").pop();
+ // Now size is in MB
+ let size = file.size / 1024 / 1024;
+ // check if file size limit is within limits
+ if ((size > parseFloat(this.options.maxFileSize))) {
+ isInvalidSize = isCurrentInvalidFileSize = true;
+ inValidSizefileNames = currFileName + "," + inValidSizefileNames;
+ } else if (!FileInputWidget.isValid(currFileName)) {
+ // check if file names are valid (ie) there are no control characters in file names
+ isInvalidFileName = isCurrentInvalidFileName = true;
+ inValidNamefileNames = currFileName + "," + inValidNamefileNames;
+ } else {
+ let isMatch = false;
+ let extension = currFileName.split('.').pop();
+ let mimeType = (file.type) ? file.type : self.extensionToMimeTypeMap[extension];
+ if (mimeType != undefined && mimeType.trim().length > 0) {
+ isMatch = this.regexMimeTypeList.some(function (rx) {
+ return rx.test(mimeType);
+ });
+ }
+ if (!isMatch) {
+ isInvalidMimeType = isCurrentInvalidMimeType = true;
+ inValidMimeTypefileNames = currFileName + "," + inValidMimeTypefileNames;
+ }
+ }
+
+ // if the file is not invalid, show it and push it to internal array
+ if (!isCurrentInvalidFileSize && !isCurrentInvalidFileName && !isCurrentInvalidMimeType) {
+ // We'll update this.values with the complete URL later
+ validFiles.push(file);
+ } else {
+ invalidFilesIndexes.push(fileIndex);
+ }
+ }, this);
+
+ // Handle file upload for valid files
+ if (validFiles.length > 0) {
+ // Upload file and get URL
+ let fileUrl = this.uploadFile(validFiles);
+ if (this.isMultiSelect()) {
+ Array.from(validFiles).forEach(function (file, fileIndex) {
+ let completeUrl = fileUrl + "/" + file.name;
+ uris.push(completeUrl);
+ this.fileArr.push(completeUrl);
+ this.values.push(completeUrl);
+ }, this);
+ } else {
+ let completeUrl = fileUrl + "/" + validFiles[0].name;
+ this.values = [completeUrl];
+ this.fileArr = [completeUrl];
+ uris.push(completeUrl);
+ }
+ }
+
+ if (invalidFilesIndexes.length > 0 && this.widget !== null) {
+ this.deleteFilesFromInputDom(invalidFilesIndexes);
+ }
+ }
+
+ // set the new model value.
+ this.model.value = this.fileArr;
+
+ Array.from(uris).forEach(function (uri, fileIndex) {
+ this.fileList.querySelectorAll('.cmp-adaptiveform-fileinput__filename')[fileIndex].dataset.key = uri;
+ this.fileList.querySelectorAll('.cmp-adaptiveform-fileinput__filesize')[fileIndex].hidden = true;
+ }, this);
+
+ if (isInvalidSize) {
+ this.showInvalidMessage(inValidSizefileNames.substring(0, inValidSizefileNames.lastIndexOf(',')), this.invalidFeature.SIZE);
+ } else if (isInvalidFileName) {
+ this.showInvalidMessage(inValidNamefileNames.substring(0, inValidNamefileNames.lastIndexOf(',')), this.invalidFeature.NAME);
+ } else if (isInvalidMimeType) {
+ this.showInvalidMessage(inValidMimeTypefileNames.substring(0, inValidMimeTypefileNames.lastIndexOf(',')), this.invalidFeature.MIMETYPE);
+ }
+ }
+ this.widget.value = null;
+ }
+
+ uploadFile (filesObject) {
+ let s3UploadUrl = "/services/s3/presign", // URL for getting S3 presigned URL
+ multiple = this.isMultiSelect(); // Check if multiple files can be uploaded;
+
+ let self = this;
+ if (multiple) {
+ let uploadPromises = [];
+ Array.from(filesObject).forEach(function (file, fileIndex) {
+ uploadPromises.push(self.uploadFileToS3(file, s3UploadUrl, file.name));
+ }, this);
+
+ // Wait for all files to upload
+ Promise.all(uploadPromises).then(function(results) {
+ console.log("fileuploaded successfully");
+ //self.handleMultipleFileUpload(results);
+ }).catch(function(error) {
+ console.error("Error uploading files:", error);
+ //self.$element.trigger("adobeFileUploader.fileUploadFailed");
+ });
+ } else {
+ this.uploadFileToS3(filesObject[0], s3UploadUrl, filesObject[0].name).then(function(result) {
+ console.log("fileuploaded successfully");
+ }).catch(function(error) {
+ console.error("Error uploading file:", error);
+ // self.$element.trigger("adobeFileUploader.fileUploadFailed");
+ });
+ }
+ return s3UploadUrl;
+ }
+
+ // Helper method to handle file upload to S3
+ uploadFileToS3(file, presignEndpoint, fileName) {
+ // Return a resolved promise with a sample URL
+ // This is just for testing - replace with actual implementation
+ return new Promise((resolve) => {
+ // Simulate network delay
+ setTimeout(() => {
+ // For testing: construct a sample URL using the fileName
+ const sampleUrl = presignEndpoint + "/" + fileName;
+
+ // Return an object with url and other metadata
+ resolve({
+ success: true,
+ url: sampleUrl,
+ fileName: fileName,
+ fileSize: file.size,
+ fileType: file.type,
+ lastModified: file.lastModified
+ });
+ }, 500); // 500ms delay to simulate network request
+ });
+
+ /* Real implementation would look like this:
+ return fetch(presignEndpoint, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ fileName: fileName,
+ contentType: file.type
+ })
+ })
+ .then(response => response.json())
+ .then(presignedData => {
+ return fetch(presignedData.url, {
+ method: 'PUT',
+ body: file,
+ headers: presignedData.headers || {}
+ });
+ })
+ .then(() => {
+ return {
+ success: true,
+ url: this.fileUrl,
+ fileName: fileName
+ };
+ });
+ */
+ }
+ }
+}
\ No newline at end of file
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/customfileupload.html b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/customfileupload.html
new file mode 100644
index 0000000000..b7c77dfca6
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/customfileupload/v1/customfileupload/customfileupload.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+