Skip to content
Open
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 @@ -44,6 +44,9 @@ private FormConstants() {
/** The resource type for email input v1 */
public static final String RT_FD_FORM_EMAIL_V1 = RT_FD_FORM_PREFIX + "emailinput/v1/emailinput";

/** The resource type for password input v1 */
public static final String RT_FD_FORM_PASSWORD_V1 = RT_FD_FORM_PREFIX + "passwordinput/v1/passwordinput";

/** The resource type for button v1 */
public static final String RT_FD_FORM_BUTTON_V1 = RT_FD_FORM_PREFIX + "button/v1/button";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ private ReservedProperties() {
public static final String PN_SHOW_AS_POPUP = "showAsPopup";
public static final String PN_TEXT_IS_RICH = "textIsRich";
public static final String PN_MULTILINE = "multiLine";
public static final String PN_SHOW_HIDE_PASSWORD = "showHidePassword";
public static final String PN_DESIGN_DEFAULT_TYPE = Title.PN_DESIGN_DEFAULT_TYPE;
public static final String PN_TITLE_LINK_DISABLED = Title.PN_TITLE_LINK_DISABLED;
public static final String PN_DRAG_DROP_TEXT = "dragDropText";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
@Model(
adaptables = { SlingHttpServletRequest.class, Resource.class },
adapters = { TextInput.class, ComponentExporter.class },
resourceType = { FormConstants.RT_FD_FORM_TEXT_V1, FormConstants.RT_FD_FORM_EMAIL_V1, FormConstants.RT_FD_FORM_TELEPHONE_V1 })
resourceType = { FormConstants.RT_FD_FORM_TEXT_V1, FormConstants.RT_FD_FORM_EMAIL_V1, FormConstants.RT_FD_FORM_TELEPHONE_V1,
FormConstants.RT_FD_FORM_PASSWORD_V1 })
@Exporter(
name = ExporterConstants.SLING_MODEL_EXPORTER_NAME,
extensions = ExporterConstants.SLING_MODEL_EXTENSION)
Expand All @@ -65,6 +66,10 @@ public class TextInputImpl extends AbstractFieldImpl implements TextInput {
@Nullable
protected String autocomplete;

@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_SHOW_HIDE_PASSWORD)
@Default(booleanValues = true)
protected boolean showHidePassword;

/** Type number specific constraints **/
private Object exclusiveMinimumVaue;
private Object exclusiveMaximumValue;
Expand All @@ -83,6 +88,17 @@ public String getFieldType() {
return super.getFieldType(FieldType.TEXT_INPUT);
}

@Override
@Nullable
public Object[] getDefault() {
// password values must never be exposed in rendered markup or the exported JSON model,
// regardless of how the underlying property was set (authoring dialog, direct content write, etc.)
if (FieldType.PASSWORD.getValue().equals(getFieldType())) {
return null;
}
return super.getDefault();
}

@Override
@Nullable
public Integer getMinLength() {
Expand All @@ -106,6 +122,11 @@ public String getAutoComplete() {
return autocomplete;
}

@Override
public boolean isShowHidePasswordEnabled() {
return showHidePassword;
}

@Override
@Nullable
public Long getMinimum() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ default boolean isMultiLine() {
return false;
}

/**
* Returns {@code true} if the password show/hide visibility toggle should be rendered, otherwise {@code false}.
* Only relevant when the field's {@code fieldType} is {@code password}.
*
* @return {@code true} if the visibility toggle should be rendered, otherwise {@code false}
* @since com.adobe.cq.forms.core.components.models.form 2.0.0
*/
@JsonIgnore
default boolean isShowHidePasswordEnabled() {
return true;
}

/**
* Returns {@code "off"} if autocomplete if disabled, otherwise {@code "on"} or values listed @see
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete">here</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ public class TextInputImplTest {
private static final String PATH_TEXTINPUT_EMPTYVALUE_EMPTY_STRING = CONTENT_ROOT + "/textinput-emptyvalue-empty-string";
private static final String PATH_TEXTINPUT_EMPTYVALUE_INVALID = CONTENT_ROOT + "/textinput-emptyvalue-invalid";
private static final String PATH_TEXTINPUT_EMPTYVALUE_NOT_SET = CONTENT_ROOT + "/textinput-emptyvalue-not-set";
private static final String PATH_PASSWORD_TEXTINPUT = CONTENT_ROOT + "/password-textinput";
private static final String PATH_PASSWORD_TEXTINPUT_TOGGLE_DISABLED = CONTENT_ROOT + "/password-textinput-toggle-disabled";

private final AemContext context = FormsCoreComponentTestContext.newAemContext();

Expand Down Expand Up @@ -594,6 +596,34 @@ void testEmptyValueEnumGetValue() {
assertEquals("", AbstractFieldImpl.EmptyValue.EMPTY_STRING.getValue());
}

@Test
void testFieldTypeForPassword() {
TextInput textInput = Utils.getComponentUnderTest(PATH_PASSWORD_TEXTINPUT, TextInput.class, context);
assertEquals(FieldType.PASSWORD.getValue(), textInput.getFieldType());
assertEquals(FormConstants.RT_FD_FORM_PASSWORD_V1, textInput.getExportedType());
}

@Test
void testShowHidePasswordEnabledByDefault() {
TextInput textInput = Utils.getComponentUnderTest(PATH_PASSWORD_TEXTINPUT, TextInput.class, context);
assertTrue(textInput.isShowHidePasswordEnabled());
TextInput textInputMock = Mockito.mock(TextInput.class);
Mockito.when(textInputMock.isShowHidePasswordEnabled()).thenCallRealMethod();
assertTrue(textInputMock.isShowHidePasswordEnabled());
}

@Test
void testShowHidePasswordCanBeDisabled() {
TextInput textInput = Utils.getComponentUnderTest(PATH_PASSWORD_TEXTINPUT_TOGGLE_DISABLED, TextInput.class, context);
assertFalse(textInput.isShowHidePasswordEnabled());
}

@Test
void testJSONExportForPassword() throws Exception {
TextInput textInput = Utils.getComponentUnderTest(PATH_PASSWORD_TEXTINPUT, TextInput.class, context);
Utils.testJSONExport(textInput, Utils.getTestExporterJSONPath(BASE, PATH_PASSWORD_TEXTINPUT));
}

@AfterEach
void tearDown() {
System.clearProperty(FeatureToggleConstants.FT_SKIP_DEFAULT_SET_PROPERTY_EVENT);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"id": "passwordinput-5c6da9d601",
"fieldType": "password",
"name": "abc",
"type": "string",
"minLength": 8,
"maxLength": 20,
"label": {
"value": "def"
},
"properties": {
"fd:path": "/content/password-textinput"
},
"events": {
"custom:setProperty": [
"$event.payload"
]
},
":type": "core/fd/components/form/passwordinput/v1/passwordinput"
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,5 +234,22 @@
"sling:resourceType" : "core/fd/components/form/textinput/v1/textinput",
"name" : "abc",
"jcr:title" : "def"
},
"password-textinput" : {
"jcr:primaryType": "nt:unstructured",
"sling:resourceType" : "core/fd/components/form/passwordinput/v1/passwordinput",
"name" : "abc",
"jcr:title" : "def",
"fieldType": "password",
"minLength": 8,
"maxLength": 20
},
"password-textinput-toggle-disabled" : {
"jcr:primaryType": "nt:unstructured",
"sling:resourceType" : "core/fd/components/form/passwordinput/v1/passwordinput",
"name" : "abc",
"jcr:title" : "def",
"fieldType": "password",
"showHidePassword": false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:Component"
jcr:title="Adaptive Form Password Input"
jcr:description="Add a field to capture passwords, with an optional show/hide toggle."
sling:resourceSuperType="core/fd/components/form/passwordinput/v1/passwordinput"
componentGroup="Core Components Examples - Adaptive Form"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="Password Input"
autocomplete="new-password"
fieldType="password"/>
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<imagechoice/>
<numberinput/>
<panelcontainer/>
<passwordinput/>
<radiobutton/>
<resetbutton/>
<submitbutton/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:fd="http://www.adobe.com/aemfd/fd/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="cq:Page">
<jcr:content
cq:lastModified="{Date}2026-07-29T00:00:00.000+00:00"
cq:lastModifiedBy="admin"
cq:tags="[]"
cq:template="/conf/core-components-examples/settings/wcm/templates/content-page"
jcr:description="Password Input"
jcr:primaryType="cq:PageContent"
jcr:title="Password Input"
sling:resourceType="forms-components-examples/components/page">
<root
jcr:primaryType="nt:unstructured"
sling:resourceType="wcm/foundation/components/responsivegrid">
<responsivegrid
jcr:primaryType="nt:unstructured"
sling:resourceType="wcm/foundation/components/responsivegrid">
<text_1740702242
jcr:primaryType="nt:unstructured"
sling:resourceType="core/wcm/components/text/v2/text"
text="&lt;h1>Password Input&lt;sub>v1&lt;/sub>&lt;/h1>"
textIsRich="true"/>
<text
jcr:primaryType="nt:unstructured"
sling:resourceType="core/wcm/components/text/v2/text"
text="&lt;p>The Adaptive Form Password Input Core Component is used to collect passwords from users. It renders a masked text box with an optional show/hide visibility toggle button, and supports the same length and pattern validations as the Text Input component.&lt;/p>"
textIsRich="true"/>
<teaser
jcr:primaryType="nt:unstructured"
jcr:description="&lt;p>GitHub&lt;/p>&#xd;&#xa;"
jcr:title="Technical Documentation"
sling:resourceType="core-components-examples/components/teaser"
actionsEnabled="false"
descriptionFromPage="false"
fileReference="/content/dam/core-components-examples/library/github-logo.svg"
linkURL="https://github.com/adobe/aem-core-forms-components/tree/master/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/passwordinput/v1/passwordinput"
textIsRich="true"
titleFromPage="false"/>
<title_865328581
jcr:primaryType="nt:unstructured"
jcr:title="Examples"
sling:resourceType="core/wcm/components/title/v2/title"
type="h2"/>
<title_290384409
jcr:primaryType="nt:unstructured"
jcr:title="Standard"
sling:resourceType="core/wcm/components/title/v2/title"
type="h3"/>
<text_1337506762
jcr:primaryType="nt:unstructured"
sling:resourceType="core/wcm/components/text/v2/text"
text="&lt;p>A simple Password Input with the show/hide toggle enabled.&lt;/p>"
textIsRich="true"/>
<demo
jcr:primaryType="nt:unstructured"
sling:resourceType="forms-components-examples/components/demo">
<component
jcr:primaryType="nt:unstructured"
sling:resourceType="forms-components-examples/components/demo/component">
<guideContainer
fd:version="2.1"
fieldType="form"
jcr:primaryType="nt:unstructured"
sling:resourceType="forms-components-examples/components/form/container">
<container
jcr:primaryType="nt:unstructured"
sling:resourceType="forms-components-examples/components/demo/component">
<passwordinput_demo
jcr:title="Password"
fieldType="password"
jcr:primaryType="nt:unstructured"
description="&lt;p>This is a long description.&lt;/p>"
tooltip="&lt;p>This is a short description.&lt;/p>"
tooltipVisible="true"
minLength="{Long}8"
showHidePassword="{Boolean}true"
sling:resourceType="forms-components-examples/components/form/passwordinput"/>
</container>
</guideContainer>
</component>
<info
jcr:primaryType="nt:unstructured"
sling:resourceType="core-components-examples/components/tabs">
<properties
cq:panelTitle="Properties"
jcr:primaryType="nt:unstructured"
sling:resourceType="core-components-examples/components/demo/properties"
reference="../../component/guideContainer/container"/>
<markup
cq:panelTitle="Markup"
jcr:primaryType="nt:unstructured"
sling:resourceType="core-components-examples/components/demo/markup"
reference="../../component/guideContainer/container"/>
<json
cq:panelTitle="JSON"
jcr:primaryType="nt:unstructured"
sling:resourceType="core-components-examples/components/demo/json"
reference="../../component/guideContainer/container"/>
</info>
</demo>
</responsivegrid>
</root>
</jcr:content>
</jcr:root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?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" xmlns:rep="internal"
jcr:mixinTypes="[rep:AccessControllable]"
jcr:primaryType="sling:Folder"
lcFolder="{Long}0"
type="lcFolder"
/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:fd="http://www.adobe.com/aemfd/fd/1.0" xmlns:dam="http://www.day.com/dam/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="dam:Asset">
<jcr:content
jcr:primaryType="dam:AssetContent"
sling:resourceType="fd/fm/af/render"
guide="1"
type="guide">
<metadata
fd:version="2.1"
jcr:primaryType="nt:unstructured"
allowedRenderFormat="HTML"
author="admin"
availableInMobileApp="{Boolean}false"
dorType="none"
formmodel="none"
hasCustomThumbnail="{Boolean}false"
title="Adaptive Form V2 (IT)"/>
</jcr:content>
</jcr:root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?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" xmlns:rep="internal"
jcr:mixinTypes="[rep:AccessControllable]"
jcr:primaryType="sling:Folder"
hidden="true"/>
Loading
Loading