Skip to content

Forms 18927 allow extensions support in file input #1586

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
6090023
added support for custom extensions using the edit dialogue
rajatkhurana-adobe Mar 6, 2025
f318496
feat(FileExtensionSupport): add support for custom file extensions te…
rajatkhurana-adobe Mar 10, 2025
1e4b082
Updated help description to support file extensions as well
rajatkhurana-adobe Mar 13, 2025
f67107d
added support for new extesnions in the file input with test cases
rajatkhurana-adobe Mar 19, 2025
8df457a
feat(FileExtensionSupport): add support for custom file extensions te…
rajatkhurana-adobe Mar 10, 2025
3263fc7
Updated help description to support file extensions as well
rajatkhurana-adobe Mar 13, 2025
38f946d
added support for new extesnions removed extra changes from other ver…
rajatkhurana-adobe Mar 19, 2025
b0dfd43
feat(newExtensionsSupport): test cases fixed
rajatkhurana-adobe Mar 26, 2025
7e2935a
added new support for extensions
rajatkhurana-adobe Apr 1, 2025
225daa2
hiding info icon as per extensions support
rajatkhurana-adobe Apr 25, 2025
691b641
file extensions masking removed
rajatkhurana-adobe Apr 25, 2025
396b6cb
Test cases for model added
rajatkhurana-adobe Apr 25, 2025
58e07d3
test cases fixed
rajatkhurana-adobe Apr 25, 2025
e525b83
test cases fixed I
rajatkhurana-adobe Apr 25, 2025
49cd2ed
test cases fixed for extensions support in file input
rajatkhurana-adobe Apr 25, 2025
cd411cd
test cases fixed for extensions support in file input
rajatkhurana-adobe Apr 25, 2025
c10b1e9
File Type and file extensions descriptions added
rajatkhurana-adobe May 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ private ReservedProperties() {
public static final String PN_UNCHECKED_VALUE = "uncheckedValue";
public static final String PN_MAX_FILE_SIZE = "maxFileSize";
public static final String PN_FILE_ACCEPT = "accept";
public static final String PN_FILE_ACCEPT_EXTENSIONS = "acceptExtensions";
public static final String PN_BUTTON_TEXT = "buttonText";
public static final String PN_WRAP_DATA = "wrapData";
public static final String PN_FRAGMENT_PATH = "fragmentPath";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@

package com.adobe.cq.forms.core.components.internal.models.v3.form;

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;
Expand Down Expand Up @@ -48,6 +52,9 @@ public class FileInputImplV3 extends FileInputImplV2 {
@Default(values = FileInput.DEFAULT_DRAGDROP_TEXT)
protected String dragDropTextV3;

@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_FILE_ACCEPT_EXTENSIONS)
protected String[] acceptExtensions;

@Override
public String getDragDropText() {
return dragDropTextV3;
Expand All @@ -60,4 +67,17 @@ public String getDragDropText() {
customProperties.put(ReservedProperties.PN_DRAG_DROP_TEXT_V3, getDragDropText());
return customProperties;
}

@Override
public List<String> getAcceptExtensions() {
// adding . in front of the accept extensions
if (acceptExtensions != null) {
for (int i = 0; i < acceptExtensions.length; i++) {
acceptExtensions[i] = "." + acceptExtensions[i];
}
}
return Optional.ofNullable(acceptExtensions)
.map(Arrays::asList)
.orElse(Collections.emptyList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ default List<String> getAccept() {
return DEFAULT_ACCEPT;
}

/**
* Returns the list of file extensions which field can accept. The constraint is
* applicable for file attachment field
*
* @return the list of extensions supported by the field
* @since com.adobe.cq.forms.core.components.models.form 0.0.1
*/
default List<String> getAcceptExtensions() {
return Collections.emptyList();
}

/**
* The constraint is
* applicable for file attachment field. If the type is {@code String}, the format will always be {@code data-url}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package com.adobe.cq.forms.core.components.models.form;

import java.util.Collections;
import java.util.List;

import org.osgi.annotation.versioning.ConsumerType;

import com.fasterxml.jackson.annotation.JsonIgnore;
Expand All @@ -40,6 +43,17 @@
return false;
}

/**
* Returns the list of file extensions which field can accept. The constraint is
* applicable for file attachment field
*
* @return the list of extensions supported by the field
*/
@JsonIgnore
default List<String> getAcceptExtensions() {
return Collections.emptyList();

Check warning on line 54 in bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/FileInput.java

View check run for this annotation

Codecov / codecov/patch

bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/FileInput.java#L54

Added line #L54 was not covered by tests
}

/**
* Returns the text to be displayed on the file input button
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package com.adobe.cq.forms.core.components.internal.models.v1.form;

import java.util.Collections;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
Expand Down Expand Up @@ -42,4 +44,11 @@ void testGetAccept() {
Mockito.when(fileConstraintMock.getAccept()).thenCallRealMethod();
assertThat(FileConstraint.DEFAULT_ACCEPT, is(fileConstraintMock.getAccept()));
}

@Test
void testGetAcceptExtensions() {
FileConstraint fileConstraintMock = Mockito.mock(FileConstraint.class);
Mockito.when(fileConstraintMock.getAcceptExtensions()).thenCallRealMethod();
assertEquals(Collections.emptyList(), fileConstraintMock.getAcceptExtensions());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.reflect.FieldUtils;
Expand All @@ -41,7 +42,7 @@
import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;

import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
Expand Down Expand Up @@ -400,4 +401,21 @@ void testJSONExportDataLayer() throws Exception {
FieldUtils.writeField(fileInput, "dataLayerEnabled", true, true);
Utils.testJSONExport(fileInput, Utils.getTestExporterJSONPath(BASE, PATH_FILEINPUT_DATALAYER));
}

@Test
void testGetAcceptExtensions() {
FileInput fileInput = Utils.getComponentUnderTest(PATH_FILEINPUT_DATALAYER, FileInput.class, context);
// assert fileInput.getAcceptExtensions() to return empty list
assertEquals(Collections.emptyList(), fileInput.getAcceptExtensions());
FileInput fileInputMock = Mockito.mock(FileInput.class);
Mockito.when(fileInputMock.getAcceptExtensions()).thenCallRealMethod();
assertEquals(Collections.emptyList(), fileInput.getAcceptExtensions());
}

@Test
void testGetAcceptExtensionsWithExtensions() {
FileInput fileInput = Utils.getComponentUnderTest(PATH_FILEINPUT_CUSTOMIZED, FileInput.class, context);
List<String> extensions = fileInput.getAcceptExtensions();
assertThat(Arrays.asList(".jpg", ".png"), is(extensions));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@
"custom" : "Custom screen reader text",
"tooltip": "test-short-description",
"maxFileSize" : "4",
"accept" : ["audio/*", "video/*", "image/*"]
"accept" : ["audio/*", "video/*", "image/*"],
"acceptExtensions": [
"jpg",
"png"
]
},
"multiselect-fileinput" : {
"jcr:primaryType": "nt:unstructured",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@
maxFileSize="2"
type="file[]"
visible="{Boolean}true"/>
<fileinput7
jcr:primaryType="nt:unstructured"
jcr:title="File Input - 7"
sling:resourceType="core/fd/components/form/fileinput/v3/fileinput"
accept="[audio/*, video/*, image/*, text/*, application/pdf,.ifc]"
fieldType="file-input"
readOnly="{Boolean}false"
name="fileinput7"
type="file"/>
<submit
jcr:lastModified="{Date}2023-01-17T16:28:58.844+05:30"
jcr:lastModifiedBy="admin"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
jcr:primaryType="nt:unstructured"
jcr:title="Adaptive Form File Attachment"
sling:resourceType="cq/gui/components/authoring/dialog"
extraClientlibs="[core.forms.components.fileinput.v1.editor]"
extraClientlibs="[core.forms.components.fileinput.v3.editor]"
helpPath="https://www.adobe.com/go/aem_af_cmp_fileinput_v2"
trackingFeature="core-components:adaptiveform-fileinput:v2">
<content
Expand Down Expand Up @@ -87,7 +87,54 @@
</basic>
<validation
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container"/>
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<columns
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
margin="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<mimeType
wrapperClass="cmp-adaptiveform-fileinput__mimeType"
jcr:primaryType="nt:unstructured"
sling:resourceType="fd/af/authoring/components/granite/form/formsmultifield"
fieldLabel="Allowed file types"
fieldDescription="Specify allowed MIME types (for example, image/jpeg) to filter uploads. You can use this option or 'Allowed file extensions'. However, this setting is disabled if any 'Allowed file extensions' are specified."
defaultValue="">
<field
name="./accept"
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"/>
</mimeType>
<extensions
wrapperClass="cmp-adaptiveform-fileinput__extensions"
jcr:primaryType="nt:unstructured"
sling:resourceType="fd/af/authoring/components/granite/form/formsmultifield"
fieldLabel="Allowed file extensions"
fieldDescription="Specify allowed file extensions (for example, jpg, pdf) to filter uploads. Using this option will disable and override the 'Allowed file types' setting."
defaultValue="">
<field
name="./acceptExtensions"
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"/>
<granite:rendercondition
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/renderconditions/featuretoggle"
toggleName="FT_FORMS-18927"/>
</extensions>
<acceptMessage
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"/>
</items>
</column>
</items>
</columns>
</items>
</validation>
<help
jcr:primaryType="nt:unstructured"
jcr:title="Help Content"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:Folder"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:ClientLibraryFolder"
categories="[core.forms.components.fileinput.v3.editor]"
jsProcessor="[default:none,min:gcc;languageIn=ECMASCRIPT_2021;languageOut=ECMASCRIPT_2021]"
dependencies="[core.forms.components.base.v1.editor, core.forms.components.commons.v1.editor.utils]"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
###############################################################################
# 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
editDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*******************************************************************************
* 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.
******************************************************************************/
(function($) {
"use strict";
let EDIT_DIALOG = ".cmp-adaptiveform-fileinput__editdialog",
FILEINPUT_MIMETYPE = EDIT_DIALOG + " .cmp-adaptiveform-fileinput__mimeType",
FILEINPUT_EXTENSIONS = EDIT_DIALOG + " .cmp-adaptiveform-fileinput__extensions",
Utils = window.CQ.FormsCoreComponents.Utils.v1;

function handleMimeType(dialog) {
let mimeTypeWrapper = dialog.find(FILEINPUT_MIMETYPE);
let mimeTypeField = mimeTypeWrapper.find("coral-multifield");
let extensionsField = dialog.find(FILEINPUT_EXTENSIONS + " coral-multifield");
let mimeTypeFieldInfoIcon = mimeTypeWrapper.find('coral-icon.coral-Form-fieldinfo');

function updateMimeTypeState() {
let hasExtensions = extensionsField.find('coral-multifield-item').length > 0;

// Disable the entire multifield and its contents
mimeTypeField.css({
'pointer-events': hasExtensions ? 'none' : 'auto',
'opacity': hasExtensions ? '0.5' : '1'
});
mimeTypeField.prop('disabled', hasExtensions);

// Disable delete icons and their SVGs
mimeTypeField.find('coral-icon[icon="delete"], ._coral-Icon--svg').css({
'pointer-events': hasExtensions ? 'none' : 'auto'
});

// Handle MIME type items if extensions exist
if (hasExtensions) {
// Keep first item, remove others
let firstItem = mimeTypeField.find('coral-multifield-item').first();

// If no first item exists, create one
if (firstItem.length === 0) {
// Click the add button to create a new item
mimeTypeField.find('button[coral-multifield-add]').click();
firstItem = mimeTypeField.find('coral-multifield-item').first();
}

mimeTypeField.find('coral-multifield-item:not(:first)').remove();

// Set value of first item to */*
firstItem.find('input').val('*/*');
}

if(mimeTypeFieldInfoIcon.length > 0) {
// show the info icon
mimeTypeFieldInfoIcon.css({
'display': hasExtensions ? '' : 'none'
});
}
}

// Watch for changes in both fields
extensionsField.on('change', updateMimeTypeState);
mimeTypeField.on('change', updateMimeTypeState);

// Check initial state without triggering events
let hasExtensions = extensionsField.find('coral-multifield-item').length > 0;
if (hasExtensions) {
mimeTypeField.css({
'pointer-events': 'none',
'opacity': '0.5'
});
mimeTypeField.prop('disabled', true);
mimeTypeField.find('coral-icon[icon="delete"], ._coral-Icon--svg').css({
'pointer-events': 'none'
});
}
}

$(document).on('dialog-loaded', EDIT_DIALOG, function(e) {
handleMimeType($(this));
});

Utils.initializeEditDialog(EDIT_DIALOG)(handleMimeType);

})(jQuery);
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
/>
Expand Down
Loading
Loading