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 @@ + + + + + +
+
+
+
+
+
+
+
+
+
${file.dragDropText @context='html'}
+ + +
+
    +
    +
    +
    +
    +
    +
    + + + +