--- /dev/null
+<input type="password" {*
+ *}id="{@$field->getPrefixedId()}" {*
+ *}name="{@$field->getPrefixedId()}" {*
+ *}value="{$field->getValue()}"{*
+ *}{if !$field->getFieldClasses()|empty} class="{implode from=$field->getFieldClasses() item='class' glue=' '}{$class}{/implode}"{/if}{*
+ *}{if $field->getInputMode() !== null} inputmode="{$field->getInputMode()}"{/if}{*
+ *}{if $field->getAutoComplete() !== null} autocomplete="{$field->getAutoComplete()}"{/if}{*
+ *}{if $field->getPattern() !== null} pattern="{$field->getPattern()}"{/if}{*
+ *}{if $field->isAutofocused()} autofocus{/if}{*
+ *}{if $field->isRequired()} required{/if}{*
+ *}{if $field->isImmutable()} disabled{/if}{*
+ *}{if $field->getMinimumLength() !== null} minlength="{$field->getMinimumLength()}"{/if}{*
+ *}{if $field->getMaximumLength() !== null} maxlength="{$field->getMaximumLength()}"{/if}{*
+ *}{if $field->getPlaceholder() !== null} placeholder="{$field->getPlaceholder()}"{/if}{*
+ *}{if $field->getDocument()->isAjax()} data-dialog-submit-on-enter="true"{/if}{*
+ *}{foreach from=$field->getFieldAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach}{*
+*}>
"__multipleSelectionFormField",
"__nonEmptyFormFieldDependency",
"__numericFormField",
+ "__passwordFormField",
"__pollOptionsFormField",
"__radioButtonFormField",
"__ratingFormField",
--- /dev/null
+<input type="password" {*
+ *}id="{@$field->getPrefixedId()}" {*
+ *}name="{@$field->getPrefixedId()}" {*
+ *}value="{$field->getValue()}"{*
+ *}{if !$field->getFieldClasses()|empty} class="{implode from=$field->getFieldClasses() item='class' glue=' '}{$class}{/implode}"{/if}{*
+ *}{if $field->getInputMode() !== null} inputmode="{$field->getInputMode()}"{/if}{*
+ *}{if $field->getAutoComplete() !== null} autocomplete="{$field->getAutoComplete()}"{/if}{*
+ *}{if $field->getPattern() !== null} pattern="{$field->getPattern()}"{/if}{*
+ *}{if $field->isAutofocused()} autofocus{/if}{*
+ *}{if $field->isRequired()} required{/if}{*
+ *}{if $field->isImmutable()} disabled{/if}{*
+ *}{if $field->getMinimumLength() !== null} minlength="{$field->getMinimumLength()}"{/if}{*
+ *}{if $field->getMaximumLength() !== null} maxlength="{$field->getMaximumLength()}"{/if}{*
+ *}{if $field->getPlaceholder() !== null} placeholder="{$field->getPlaceholder()}"{/if}{*
+ *}{if $field->getDocument()->isAjax()} data-dialog-submit-on-enter="true"{/if}{*
+ *}{foreach from=$field->getFieldAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach}{*
+*}>
--- /dev/null
+<?php
+
+namespace wcf\system\form\builder\field;
+
+use wcf\system\form\builder\field\validation\FormFieldValidationError;
+
+/**
+ * Implementation of a form field for a password.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Form\Builder\Field
+ * @since 5.4
+ */
+class PasswordFormField extends AbstractFormField implements
+ IAttributeFormField,
+ IAutoCompleteFormField,
+ IAutoFocusFormField,
+ ICssClassFormField,
+ IImmutableFormField,
+ IInputModeFormField,
+ IMaximumLengthFormField,
+ IMinimumLengthFormField,
+ IPatternFormField,
+ IPlaceholderFormField
+{
+ use TInputAttributeFormField;
+ use TTextAutoCompleteFormField;
+ use TAutoFocusFormField;
+ use TCssClassFormField;
+ use TDefaultIdFormField;
+ use TImmutableFormField;
+ use TInputModeFormField;
+ use TMaximumLengthFormField;
+ use TMinimumLengthFormField;
+ use TPatternFormField;
+ use TPlaceholderFormField;
+
+ /**
+ * @inheritDoc
+ */
+ protected $javaScriptDataHandlerModule = 'WoltLabSuite/Core/Form/Builder/Field/Value';
+
+ /**
+ * @inheritDoc
+ */
+ protected $templateName = '__passwordFormField';
+
+ /**
+ * Creates a new instance of `PasswordFormField`.
+ */
+ public function __construct()
+ {
+ $this->label('wcf.user.password');
+ $this->addFieldClass('long');
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getValidInputModes(): array
+ {
+ return [
+ 'text',
+ ];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function readValue()
+ {
+ if ($this->getDocument()->hasRequestData($this->getPrefixedId())) {
+ $this->value = $this->getDocument()->getRequestData($this->getPrefixedId());
+ }
+
+ return $this;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function validate()
+ {
+ $value = $this->getValue();
+ $hasValue = $this->getValue() !== null && $this->getValue() !== '';
+
+ if ($this->isRequired() && !$hasValue) {
+ $this->addValidationError(new FormFieldValidationError('empty'));
+ } elseif ($hasValue) {
+ $this->validateMinimumLength($value);
+ $this->validateMaximumLength($value);
+ }
+
+ parent::validate();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected static function getDefaultId()
+ {
+ return 'password';
+ }
+}