Skip to content
Closed

dummy #1808

Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -56,6 +56,7 @@ public class PanelImpl extends AbstractContainerImpl implements Panel {
private static String OVERFLOW_TEXT = "overflowText";
private static String DOR_NUM_COLS = "dorNumCols";
private static String DOR_LAYOUT_TYPE = "dorLayoutType";
private static final String FD_USE_FIELDSET = "fd:useFieldset";

@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_DOR_EXCLUDE_TITLE)
@Nullable
Expand Down Expand Up @@ -93,6 +94,10 @@ public class PanelImpl extends AbstractContainerImpl implements Panel {
@Nullable
protected Boolean readOnly;

@ValueMapValue(name = FD_USE_FIELDSET, injectionStrategy = InjectionStrategy.OPTIONAL)
@Nullable
protected Boolean useFieldset;

@JsonIgnore
@Override
public Boolean isRequired() {
Expand Down Expand Up @@ -120,6 +125,21 @@ public Boolean isReadOnly() {
return readOnly;
}

@Override
@Nullable
public Boolean useFieldset() {
return useFieldset;
}

@Override
public @NotNull Map<String, Object> getProperties() {
Map<String, Object> properties = super.getProperties();
if (useFieldset != null) {
properties.put(FD_USE_FIELDSET, useFieldset);
}
return properties;
}

@Override
@JsonIgnore
@NotNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,15 @@ public interface Panel extends Container, ContainerConstraint {
default Boolean isReadOnly() {
return null;
}

/**
* Checks if the panel should use fieldset HTML element instead of div.
*
* @return {@code true} if the panel should render as fieldset, {@code false} or null otherwise
* @since com.adobe.cq.forms.core.components.models.form 5.12.4
*/
@Nullable
default Boolean useFieldset() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
* </p>
*/

@Version("5.12.3")
@Version("5.12.4")
package com.adobe.cq.forms.core.components.models.form;

import org.osgi.annotation.versioning.Version;
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@
import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.*;
import static org.junit.jupiter.api.Assertions.assertTrue;

@ExtendWith(AemContextExtension.class)
Expand All @@ -52,6 +51,7 @@ public class PanelImplTest {
private static final String PATH_RULES_PANEL = CONTENT_ROOT + "/rules-panel";
private static final String PATH_BOUND_PANEL = CONTENT_ROOT + "/bound-panel";
private static final String PATH_PANEL_WITHOUT_FIELDTYPE = CONTENT_ROOT + "/panel-without-fieldtype";
private static final String PATH_PANEL_WITH_FIELDSET = CONTENT_ROOT + "/panel-with-fieldset";
private final AemContext context = FormsCoreComponentTestContext.newAemContext();

@BeforeEach
Expand Down Expand Up @@ -148,4 +148,30 @@ void testDorContainer() {
Map<String, Object> dorProperties = mockPanel.getDorProperties();
assertTrue(dorProperties.containsKey(PanelImpl.CUSTOM_DOR_CONTAINER_WRAPPER));
}

@Test
void testUseFieldsetDefaultMethod() {
Panel panelMock = Mockito.mock(Panel.class);
Mockito.when(panelMock.useFieldset()).thenCallRealMethod();
assertNull(panelMock.useFieldset());
}

@Test
void testUseFieldsetMethod() throws Exception {
Panel panel = Utils.getComponentUnderTest(PATH_PANEL_WITH_FIELDSET, Panel.class, context);
assertEquals(true, panel.useFieldset());
}

@Test
void testUseFieldsetInProperties() throws Exception {
Panel panel = Utils.getComponentUnderTest(PATH_PANEL_WITH_FIELDSET, Panel.class, context);
Map<String, Object> properties = panel.getProperties();
assertEquals(true, properties.get("fd:useFieldset"));
}

@Test
void testPanelWithFieldsetJSONExport() throws Exception {
Panel panel = Utils.getComponentUnderTest(PATH_PANEL_WITH_FIELDSET, Panel.class, context);
Utils.testJSONExport(panel, Utils.getTestExporterJSONPath(BASE, PATH_PANEL_WITH_FIELDSET));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"id": "panel-848a57fc7b",
"fieldType": "panel",
"name": "fieldsetPanel",
"properties": {
"fd:dor": {
"dorExclusion": false,
"dorExcludeTitle": false,
"dorExcludeDescription": false
},
"fd:path": "/content/panel-with-fieldset",
"fd:useFieldset": true
},
"label": {
"value": "Panel with Fieldset"
},
"events": {
"custom:setProperty": [
"$event.payload"
]
},
":itemsOrder": [
"textinput"
],
":type": "core/fd/components/form/panel/v1/panel",
":items": {
"textinput": {
"id": "textinput-2c19ef8518",
"fieldType": "text-input",
"name": "field1",
"type": "string",
"label": {
"value": "Field 1"
},
"properties": {
"fd:dor": {
"dorExclusion": false
},
"fd:path": "/content/panel-with-fieldset/textinput"
},
"events": {
"custom:setProperty": [
"$event.payload"
]
},
":type": "core/fd/components/form/textinput/v1/textinput"
}
}
}
15 changes: 15 additions & 0 deletions bundles/af-core/src/test/resources/form/panel/test-content.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,20 @@
"description" : "dummy",
"visible" : false
}
},
"panel-with-fieldset": {
"name" : "fieldsetPanel",
"jcr:primaryType": "nt:unstructured",
"sling:resourceType" : "core/fd/components/form/panel/v1/panel",
"jcr:title": "Panel with Fieldset",
"fieldType" : "panel",
"fd:useFieldset": true,
"textinput" : {
"jcr:primaryType": "nt:unstructured",
"sling:resourceType" : "core/fd/components/form/textinput/v1/textinput",
"name" : "field1",
"jcr:title" : "Field 1",
"fieldType" : "text-input"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,22 @@
fieldType="number-input"
name="numberinput1674624783704"/>
</panelcontainer1>
<panelcontainerFieldset
jcr:primaryType="nt:unstructured"
jcr:title="Fieldset Panel"
sling:resourceType="forms-components-examples/components/form/panelcontainer"
enabled="{Boolean}true"
fieldType="panel"
name="panelcontainerFieldset"
fd:useFieldset="{Boolean}true"
visible="{Boolean}true">
<textinputFieldset
jcr:primaryType="nt:unstructured"
jcr:title="Text Input in Fieldset"
sling:resourceType="forms-components-examples/components/form/textinput"
fieldType="text-input"
name="textinputFieldset"/>
</panelcontainerFieldset>
</guideContainer>
</jcr:content>
</jcr:root>
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ The following properties are written to JCR for this Panel Container component a
6. `./enabled` - defines initial state of panel if its enabled or not
7. `./tooltip` - defines tooltip on panel title
8. `./description` - defines a help message that can be rendered in the field as a hint for the user
9. `./fd:useFieldset` - if set to `true`, the panel will be rendered as a `<fieldset>` element with the label as a `<legend>` for improved semantics and accessibility. When enabled, the title becomes mandatory and the "Hide Title" option is disabled. If title is not provided, the component will fallback to the panel name.

#### Style Properties
1. `./backgroundImageReference` - defines the Panel Container background image.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,25 @@
sling:resourceType="granite/ui/components/coral/foundation/form/hidden"
name="./wrapData@TypeHint"
value="Boolean"/>
<useFieldset
granite:class="cmp-adaptiveform-panel__useFieldset"
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
fieldLabel="Use Fieldset/Legend"
fieldDescription="Render panel as a fieldset with legend for better semantics and accessibility. When enabled, title becomes mandatory."
name="./fd:useFieldset"
text="Enable Fieldset/Legend"
uncheckedValue="false"
value="true">
<granite:data
jcr:primaryType="nt:unstructured"
cmp-adaptiveform-panel-useFieldset="true"/>
</useFieldset>
<useFieldset-typehint
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/hidden"
name="./fd:useFieldset@TypeHint"
value="Boolean"/>
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/select"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
(function($) {
"use strict";

var selectors = {
const selectors = {
dialogContent: ".cmp-adaptiveform-panelcontainer__editdialog",
edit: {
backgroundColorSwatchesOnly: "[data-cmp-container-v1-dialog-edit-hook='backgroundColorSwatchesOnly']"
Expand All @@ -27,26 +27,33 @@
backgroundColorSwatchesOnly: "[data-cmp-container-v1-dialog-policy-hook='backgroundColorSwatchesOnly']",
backgroundColorAllowedSwatches: "[data-cmp-container-v1-dialog-policy-hook='backgroundColorAllowedSwatches']"
}
};
},
Utils = window.CQ.FormsCoreComponents.Utils.v1;

$(document).on("dialog-loaded", function(e) {
var $dialog = e.dialog;
var $dialogContent = $dialog.find(selectors.dialogContent);
var dialogContent = $dialogContent.length > 0 ? $dialogContent[0] : undefined;
/**
* Main handler that delegates to edit/policy dialog handlers and always handles common behaviors
* @param {jQuery} dialog The jQuery dialog object
*/
function handlePanelDialog(dialog) {
const $dialogContent = dialog.find(selectors.dialogContent);
const dialogContent = $dialogContent.length > 0 ? $dialogContent[0] : undefined;

if (dialogContent) {
if (dialogContent.querySelector("[data-cmp-container-v1-dialog-edit-hook]")) {
handleEditDialog(dialogContent);
} else if (dialogContent.querySelector("[data-cmp-container-v1-dialog-policy-hook]")) {
handlePolicyDialog(dialogContent);
}

// Always handle useFieldset behavior for panel dialogs
handleUseFieldsetBehavior(dialogContent);
}

if($dialog[0]) {
if (dialog[0]) {
// repeatability, For handling the case when tabs,accordion and wizard inherit panel edit-dialog
handleRepeat($dialog[0]);
handleRepeat(dialog[0]);
}
});
}

/**
* Binds edit dialog handling
Expand All @@ -67,6 +74,71 @@
}
}

/**
* Handles the interaction between useFieldset checkbox and hideTitle checkbox.
* When useFieldset is enabled:
* - hideTitle should be disabled and unchecked (legend must be visible)
* - Title is recommended for accessibility, but code falls back to name if not provided
*
* @param {HTMLElement} containerEditor The dialog wrapper
*/
const handleUseFieldsetBehavior = (containerEditor) => {
const useFieldsetCheckbox = containerEditor.querySelector('[data-cmp-adaptiveform-panel-usefieldset]');
const hideTitleCheckbox = containerEditor.querySelector('coral-checkbox[name="./hideTitle"]');
const titleField = containerEditor.querySelector('input[name="./jcr:title"]');

if (!useFieldsetCheckbox) {
return;
}

// Function to update hideTitle state based on useFieldset
const updateHideTitleState = () => {
const isFieldsetEnabled = useFieldsetCheckbox.checked;

if (isFieldsetEnabled) {
// Disable and uncheck hideTitle when fieldset is enabled
if (hideTitleCheckbox) {
hideTitleCheckbox.disabled = true;
hideTitleCheckbox.checked = false;
}

// Add visual indicator that title is recommended (but not strictly required since we fall back to name in the HTL template)
if (titleField) {
const titleFieldWrapper = titleField.closest('.coral-Form-fieldwrapper');
if (titleFieldWrapper) {
const labelElement = titleFieldWrapper.querySelector('label.coral-Form-fieldlabel');
if (labelElement && !labelElement.dataset.originalText) {
// Store original text and append asterisk (indicating that title is recommended)
labelElement.dataset.originalText = labelElement.textContent;
labelElement.textContent = `${labelElement.textContent} *`;
}
}
}
} else {
// Re-enable hideTitle when fieldset is disabled
if (hideTitleCheckbox) {
hideTitleCheckbox.disabled = false;
}

// Remove title recommendation indicator (restore original text)
if (titleField) {
const titleFieldWrapper = titleField.closest('.coral-Form-fieldwrapper');
if (titleFieldWrapper) {
const labelElement = titleFieldWrapper.querySelector('label.coral-Form-fieldlabel');
if (labelElement && labelElement.dataset.originalText) {
labelElement.textContent = labelElement.dataset.originalText;
delete labelElement.dataset.originalText;
}
}
}
}
};

// Initialize state on dialog load
updateHideTitleState();
useFieldsetCheckbox.addEventListener('change', updateHideTitleState);
};

/**
* Binds policy dialog handling
*
Expand Down Expand Up @@ -154,4 +226,7 @@
}
}

})(jQuery);
// Initialize dialog handlers using the common utility
Utils.initializeEditDialog(selectors.dialogContent)(handlePanelDialog);

})(jQuery);
Loading