diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v3/form/FileInputImplV3.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v3/form/FileInputImplV3.java index 5438940599..20ed3556c7 100644 --- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v3/form/FileInputImplV3.java +++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v3/form/FileInputImplV3.java @@ -18,11 +18,11 @@ package com.adobe.cq.forms.core.components.internal.models.v3.form; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Optional; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.Resource; @@ -70,14 +70,18 @@ public String getDragDropText() { @Override public List getAcceptExtensions() { - // adding . in front of the accept extensions - if (acceptExtensions != null) { - for (int i = 0; i < acceptExtensions.length; i++) { - acceptExtensions[i] = "." + acceptExtensions[i]; - } + if (acceptExtensions == null) { + return Collections.emptyList(); } - return Optional.ofNullable(acceptExtensions) - .map(Arrays::asList) - .orElse(Collections.emptyList()); + return Arrays.stream(acceptExtensions) + .map(ext -> "." + ext) + .collect(java.util.stream.Collectors.toList()); + } + + @Override + public List getAccept() { + List combined = new ArrayList<>(super.getAccept()); + combined.addAll(getAcceptExtensions()); // adds .pdf, .docx etc. + return combined; } } diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v3/form/FileInputImplV3Test.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v3/form/FileInputImplV3Test.java index 30aff48d5c..b0a4478c95 100644 --- a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v3/form/FileInputImplV3Test.java +++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v3/form/FileInputImplV3Test.java @@ -262,7 +262,7 @@ void testGetMaxFileSize() { @Test void testGetAccept() { FileInput fileInput = Utils.getComponentUnderTest(PATH_FILEINPUT_CUSTOMIZED, FileInput.class, context); - assertThat(Arrays.asList("audio/*", "video/*", "image/*"), is(fileInput.getAccept())); + assertThat(Arrays.asList("audio/*", "video/*", "image/*", ".jpg", ".png"), is(fileInput.getAccept())); FileInput fileInputMock = Mockito.mock(FileInput.class); Mockito.when(fileInputMock.getAccept()).thenCallRealMethod(); assertThat(FileInput.DEFAULT_ACCEPT, is(fileInputMock.getAccept())); diff --git a/bundles/af-core/src/test/resources/form/fileinputv3/exporter-fileinput-customized.json b/bundles/af-core/src/test/resources/form/fileinputv3/exporter-fileinput-customized.json index 07f0d3be50..9ccef68b84 100644 --- a/bundles/af-core/src/test/resources/form/fileinputv3/exporter-fileinput-customized.json +++ b/bundles/af-core/src/test/resources/form/fileinputv3/exporter-fileinput-customized.json @@ -21,7 +21,9 @@ "accept": [ "audio/*", "video/*", - "image/*" + "image/*", + ".jpg", + ".png" ], "dataRef": "a.b", "events": { diff --git a/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/fileinput/fileinputv4/basic/.content.xml b/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/fileinput/fileinputv4/basic/.content.xml index cbac1049d2..fd4851bff2 100644 --- a/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/fileinput/fileinputv4/basic/.content.xml +++ b/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/fileinput/fileinputv4/basic/.content.xml @@ -103,6 +103,15 @@ maxFileSize="2" type="file[]" visible="{Boolean}true"/> + \ No newline at end of file diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fileinput/v4/fileinput/clientlibs/site/js/fileinputwidget.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fileinput/v4/fileinput/clientlibs/site/js/fileinputwidget.js index 3b2c271576..91708f50f0 100644 --- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fileinput/v4/fileinput/clientlibs/site/js/fileinputwidget.js +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fileinput/v4/fileinput/clientlibs/site/js/fileinputwidget.js @@ -93,32 +93,6 @@ if (typeof window.FileInputWidget === 'undefined') { fileItem.appendChild(fileEndContainer); return fileItem; } - validateFile(file, invalidFilesByType) { - let currFileName = file.name.split("\\").pop(); - let size = file.size / 1024 / 1024; - if (file.size === 0) { - invalidFilesByType.SIZE_ZERO.push(currFileName); - return false; - } else if (size > parseFloat(this.options.maxFileSize)) { - invalidFilesByType.SIZE.push(currFileName); - return false; - } else if (!FileInputWidget.isValid(currFileName)) { - invalidFilesByType.NAME.push(currFileName); - return false; - } else { - let isMatch = false; - let extension = currFileName.split('.').pop(); - let mimeType = (file.type) ? file.type : this.extensionToMimeTypeMap[extension]; - if (mimeType && mimeType.trim().length > 0) { - isMatch = this.regexMimeTypeList.some(rx => rx.test(mimeType)); - } - if (!isMatch) { - invalidFilesByType.MIMETYPE.push(currFileName); - return false; - } - } - return true; - } handleChange(filesUploaded) { if (!this.isFileUpdate) { let self = this, @@ -128,12 +102,46 @@ if (typeof window.FileInputWidget === 'undefined') { if (typeof files !== "undefined") { let invalidFilesIndexes = []; Array.from(files).forEach(function (file, fileIndex) { - if (self.validateFile(file, invalidFilesByType)) { + let currFileName = file.name.split("\\").pop(); + let size = file.size / 1024 / 1024; + let isCurrentInvalid = false; + if (file.size === 0) { + invalidFilesByType.SIZE_ZERO.push(currFileName); + isCurrentInvalid = true; + } else if (size > parseFloat(this.options.maxFileSize)) { + invalidFilesByType.SIZE.push(currFileName); + isCurrentInvalid = true; + } else if (!FileInputWidget.isValid(currFileName)) { + invalidFilesByType.NAME.push(currFileName); + isCurrentInvalid = true; + } else { + let isMatch = false; + let extension = currFileName.split('.').pop().toLowerCase(); + let mimeType = file.type || this.extensionToMimeTypeMap[extension]; + // If no MIME type is detected, check if the file extension is in the accept list + if (!mimeType && this.options.acceptExtensions) { + isMatch = this.options.acceptExtensions.some(function(acceptPattern) { + if (!acceptPattern) { + return false; + } + // Remove leading dot if present and convert to lowercase + let cleanPattern = acceptPattern.replace(/^\./, '').toLowerCase(); + return cleanPattern === extension; + }); + } else { + isMatch = this.regexMimeTypeList.some(rx => rx.test(mimeType)); + } + if (!isMatch) { + invalidFilesByType.MIMETYPE.push(currFileName); + isCurrentInvalid = true; + } + } + if (!isCurrentInvalid) { if (self.isMultiSelect()) { - self.values.push(file.name.split("\\").pop()); + self.values.push(currFileName); self.fileArr.push(file); } else { - self.values = [file.name.split("\\").pop()]; + self.values = [currFileName]; self.fileArr = [file]; } } else { diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fileinput/v4/fileinput/fileinput.html b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fileinput/v4/fileinput/fileinput.html index 72ed4886a9..272c37e753 100644 --- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fileinput/v4/fileinput/fileinput.html +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fileinput/v4/fileinput/fileinput.html @@ -50,7 +50,7 @@ name="${file.name}" disabled="${!file.enabled}" required="${file.required}" - accept="${file.accept}" + accept="${[file.accept, file.acceptExtensions] @ join=','}" type="file" data-cmp-data-layer="${file.data.json}" /> diff --git a/ui.frontend/src/view/FormFileInputWidget.js b/ui.frontend/src/view/FormFileInputWidget.js index 0c94e1df7d..cf56f43166 100644 --- a/ui.frontend/src/view/FormFileInputWidget.js +++ b/ui.frontend/src/view/FormFileInputWidget.js @@ -134,6 +134,10 @@ import FormFileInputWidgetBase from "./FormFileInputWidgetBase"; return fileName; }); this.fileArr = [...value]; + } else { + this.values = []; + this.fileArr = []; + this.widget.value = ''; } } } diff --git a/ui.tests/test-module/libs/fixtures/sample.ifc b/ui.tests/test-module/libs/fixtures/sample.ifc index e69de29bb2..f865c07137 100644 --- a/ui.tests/test-module/libs/fixtures/sample.ifc +++ b/ui.tests/test-module/libs/fixtures/sample.ifc @@ -0,0 +1 @@ +sample ifc content diff --git a/ui.tests/test-module/specs/fileinput/fileinputv4.runtime.cy.js b/ui.tests/test-module/specs/fileinput/fileinputv4.runtime.cy.js index 999b5b9147..11f3290c36 100644 --- a/ui.tests/test-module/specs/fileinput/fileinputv4.runtime.cy.js +++ b/ui.tests/test-module/specs/fileinput/fileinputv4.runtime.cy.js @@ -278,6 +278,23 @@ describe('Click on button tag (V-4)', () => { cy.attachFile(fileInput, [sampleFileNames[0]]); cy.get('.cmp-adaptiveform-fileinput__filesize').should('contain.text', '508 bytes'); cy.attachFile(fileInput, [sampleFileNames[0]]); - cy.get('.cmp-adaptiveform-fileinput__filesize').should('contain.text', '508 bytes'); + cy.get('.cmp-adaptiveform-fileinput__filesize').should('contain.text', '508 bytes'); + }); + + it(`file input should not support extension which are not in accept property`, () => { + const fileInput7 = "input[name='fileinput7']"; + cy.attachFile(fileInput7, ['sample.afe']); + cy.get('.cmp-adaptiveform-fileinput__filelist') + .children() + .should('have.length', 0); + }); + + it(`fileinput should support custom file extensions`, () => { + const fileInput7 = "input[name='fileinput7']"; + cy.attachFile(fileInput7, ['sample.ifc']); + cy.get('.cmp-adaptiveform-fileinput__filelist') + .children() + .should('have.length', 1) + .and('contain.text', 'sample.ifc'); }); -}); \ No newline at end of file +}); \ No newline at end of file