Skip to content

FORMS-18927 Added support for custom extensions using the edit dialogue #1541

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
1ffbe62
added support for custom extensions using the edit dialogue
rajatkhurana-adobe Mar 6, 2025
dab954d
feat(FileExtensionSupport): add support for custom file extensions te…
rajatkhurana-adobe Mar 10, 2025
74ac42b
Updated help description to support file extensions as well
rajatkhurana-adobe Mar 13, 2025
b26fe17
added support for new extesnions in the file input with test cases
rajatkhurana-adobe Mar 19, 2025
dc78624
feat(FileExtensionSupport): add support for custom file extensions te…
rajatkhurana-adobe Mar 10, 2025
832ed88
Updated help description to support file extensions as well
rajatkhurana-adobe Mar 13, 2025
16a6a6a
added support for new extesnions removed extra changes from other ver…
rajatkhurana-adobe Mar 19, 2025
69dfe31
feat(newExtensionsSupport): test cases fixed
rajatkhurana-adobe Mar 26, 2025
81b75c7
added new support for extensions
rajatkhurana-adobe Apr 1, 2025
9d5a826
hiding info icon as per extensions support
rajatkhurana-adobe Apr 25, 2025
7e93f33
file extensions masking removed
rajatkhurana-adobe Apr 25, 2025
db44ec5
Test cases for model added
rajatkhurana-adobe Apr 25, 2025
4e1285d
test cases fixed
rajatkhurana-adobe Apr 25, 2025
3618248
test cases fixed I
rajatkhurana-adobe Apr 25, 2025
55ad1a9
test cases fixed for extensions support in file input
rajatkhurana-adobe Apr 25, 2025
5951ad8
test cases fixed for extensions support in file input
rajatkhurana-adobe Apr 25, 2025
793ac61
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 @@ default Boolean isMultiple() {
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();
}

/**
* 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