diff --git a/application/forms/Config/Authentication/ExternalBackendForm.php b/application/forms/Config/Authentication/ExternalBackendForm.php
index e25661596..86087eb66 100644
--- a/application/forms/Config/Authentication/ExternalBackendForm.php
+++ b/application/forms/Config/Authentication/ExternalBackendForm.php
@@ -53,7 +53,7 @@ class ExternalBackendForm extends Form
return @preg_match($value, '') !== false;
});
$callbackValidator->setMessage(
- $this->translate('"%value%" is not a valid regular expression'),
+ $this->translate('"%value%" is not a valid regular expression.'),
Zend_Validate_Callback::INVALID_VALUE
);
$this->addElement(
@@ -62,9 +62,10 @@ class ExternalBackendForm extends Form
array(
'label' => $this->translate('Filter Pattern'),
'description' => $this->translate(
- 'The regular expression to use to strip specific parts off from usernames.'
- . ' Leave empty if you do not want to strip off anything'
+ 'The filter to use to strip specific parts off from usernames.'
+ . ' Leave empty if you do not want to strip off anything.'
),
+ 'requirement' => $this->translate('The filter pattern must be a valid regular expression.'),
'validators' => array($callbackValidator)
)
);
diff --git a/application/forms/Config/General/LoggingConfigForm.php b/application/forms/Config/General/LoggingConfigForm.php
index 1c4e090c4..bd62f4490 100644
--- a/application/forms/Config/General/LoggingConfigForm.php
+++ b/application/forms/Config/General/LoggingConfigForm.php
@@ -66,6 +66,7 @@ class LoggingConfigForm extends Form
'description' => $this->translate(
'The name of the application by which to prefix syslog messages.'
),
+ 'requirement' => $this->translate('The application prefix must not contain whitespace.'),
'value' => 'icingaweb2',
'validators' => array(
array(
diff --git a/application/forms/Config/Resource/FileResourceForm.php b/application/forms/Config/Resource/FileResourceForm.php
index b1bb0c6ae..184a5c18a 100644
--- a/application/forms/Config/Resource/FileResourceForm.php
+++ b/application/forms/Config/Resource/FileResourceForm.php
@@ -3,6 +3,7 @@
namespace Icinga\Forms\Config\Resource;
+use Zend_Validate_Callback;
use Icinga\Web\Form;
/**
@@ -42,13 +43,22 @@ class FileResourceForm extends Form
'validators' => array('ReadablePathValidator')
)
);
+ $callbackValidator = new Zend_Validate_Callback(function ($value) {
+ return @preg_match($value, '') !== false;
+ });
+ $callbackValidator->setMessage(
+ $this->translate('"%value%" is not a valid regular expression.'),
+ Zend_Validate_Callback::INVALID_VALUE
+ );
$this->addElement(
'text',
'fields',
array(
'required' => true,
'label' => $this->translate('Pattern'),
- 'description' => $this->translate('The regular expression by which to identify columns')
+ 'description' => $this->translate('The pattern by which to identify columns.'),
+ 'requirement' => $this->translate('The column pattern must be a valid regular expression.'),
+ 'validators' => array($callbackValidator)
)
);
diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php
index 3ebfdaf04..265da8420 100644
--- a/library/Icinga/Web/Form.php
+++ b/library/Icinga/Web/Form.php
@@ -157,7 +157,7 @@ class Form extends Zend_Form
public static $defaultElementDecorators = array(
array('ViewHelper', array('separator' => '')),
array('Errors', array('separator' => '')),
- array('Help'),
+ array('Help', array('placement' => 'PREPEND')),
array('Label', array('separator' => '')),
array('HtmlTag', array('tag' => 'div', 'class' => 'element'))
);
@@ -622,7 +622,7 @@ class Form extends Zend_Form
public function addSubForm(Zend_Form $form, $name = null, $order = null)
{
if ($form instanceof self) {
- $form->removeDecorator('Form');
+ $form->setDecorators(array('FormElements')); // TODO: Makes it difficult to customise subform decorators..
$form->setSubmitLabel('');
$form->setTokenDisabled();
$form->setUidDisabled();
@@ -743,7 +743,7 @@ class Form extends Zend_Form
if (($cue = $this->getRequiredCue()) !== null && ($label = $element->getDecorator('label')) !== false) {
$element->setLabel($this->getView()->escape($element->getLabel()));
$label->setOption('escape', false);
- $label->setOption('requiredSuffix', sprintf(' %s', $cue));
+ $label->setRequiredSuffix(sprintf(' %s', $cue));
}
}
diff --git a/library/Icinga/Web/Form/Decorator/FormDescriptions.php b/library/Icinga/Web/Form/Decorator/FormDescriptions.php
index 012c934a1..c8ba16ead 100644
--- a/library/Icinga/Web/Form/Decorator/FormDescriptions.php
+++ b/library/Icinga/Web/Form/Decorator/FormDescriptions.php
@@ -13,6 +13,29 @@ use Icinga\Web\Form;
*/
class FormDescriptions extends Zend_Form_Decorator_Abstract
{
+ /**
+ * A list of element class names to be ignored when detecting which message to use to describe required elements
+ *
+ * @var array
+ */
+ protected $blacklist;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct($options = null)
+ {
+ parent::__construct($options);
+ $this->blacklist = array(
+ 'Zend_Form_Element_Hidden',
+ 'Zend_Form_Element_Submit',
+ 'Zend_Form_Element_Button',
+ 'Icinga\Web\Form\Element\Note',
+ 'Icinga\Web\Form\Element\Button',
+ 'Icinga\Web\Form\Element\CsrfCounterMeasure'
+ );
+ }
+
/**
* Render form descriptions
*
@@ -32,9 +55,16 @@ class FormDescriptions extends Zend_Form_Decorator_Abstract
return $content;
}
- $descriptions = $form->getDescriptions();
- if (($requiredDesc = $this->getRequiredDescription($form)) !== null) {
- $descriptions[] = $requiredDesc;
+ $descriptions = $this->recurseForm($form, $entirelyRequired);
+ if ($entirelyRequired) {
+ $descriptions[] = $form->getView()->translate(
+ 'All fields are required and must be filled in to complete the form.'
+ );
+ } elseif ($entirelyRequired === false) {
+ $descriptions[] = $form->getView()->translate(sprintf(
+ 'Required fields are marked with %s and must be filled in to complete the form.',
+ $form->getRequiredCue()
+ ));
}
if (empty($descriptions)) {
@@ -60,53 +90,57 @@ class FormDescriptions extends Zend_Form_Decorator_Abstract
}
/**
- * Return the description for the given form's required elements
+ * Recurse the given form and return the descriptions for it and all of its subforms
*
- * @param Form $form
+ * @param Form $form The form to recurse
+ * @param mixed $entirelyRequired Set by reference, true means all elements in the hierarchy are
+ * required, false only a partial subset and null none at all
+ * @param bool $elementsPassed Whether there were any elements passed during the recursion until now
*
- * @return string|null
+ * @return array
*/
- protected function getRequiredDescription(Form $form)
+ protected function recurseForm(Form $form, & $entirelyRequired = null, $elementsPassed = false)
{
- if (($cue = $form->getRequiredCue()) === null) {
- return;
- }
-
$requiredLabels = array();
- $entirelyRequired = true;
- $partiallyRequired = false;
- $blacklist = array(
- 'Zend_Form_Element_Hidden',
- 'Zend_Form_Element_Submit',
- 'Zend_Form_Element_Button',
- 'Icinga\Web\Form\Element\Note',
- 'Icinga\Web\Form\Element\Button',
- 'Icinga\Web\Form\Element\CsrfCounterMeasure'
- );
- foreach ($form->getElements() as $element) {
- if (! in_array($element->getType(), $blacklist)) {
- if (! $element->isRequired()) {
- $entirelyRequired = false;
- } else {
- $partiallyRequired = true;
- if (($label = $element->getDecorator('label')) !== false) {
- $requiredLabels[] = $label;
+ if ($form->getRequiredCue() !== null) {
+ $partiallyRequired = $partiallyOptional = false;
+ foreach ($form->getElements() as $element) {
+ if (! in_array($element->getType(), $this->blacklist)) {
+ if (! $element->isRequired()) {
+ $partiallyOptional = true;
+ if ($entirelyRequired) {
+ $entirelyRequired = false;
+ }
+ } else {
+ $partiallyRequired = true;
+ if (($label = $element->getDecorator('label')) !== false) {
+ $requiredLabels[] = $label;
+ }
}
}
}
+
+ if (! $elementsPassed) {
+ $elementsPassed = $partiallyRequired || $partiallyOptional;
+ if ($entirelyRequired === null && $partiallyRequired) {
+ $entirelyRequired = ! $partiallyOptional;
+ }
+ } elseif ($entirelyRequired === null && $partiallyRequired) {
+ $entirelyRequired = false;
+ }
}
- if ($entirelyRequired && $partiallyRequired) {
+ $descriptions = array($form->getDescriptions());
+ foreach ($form->getSubForms() as $subForm) {
+ $descriptions[] = $this->recurseForm($subForm, $entirelyRequired, $elementsPassed);
+ }
+
+ if ($entirelyRequired) {
foreach ($requiredLabels as $label) {
$label->setRequiredSuffix('');
}
-
- return $form->getView()->translate('All fields are required and must be filled in to complete the form.');
- } elseif ($partiallyRequired) {
- return $form->getView()->translate(sprintf(
- 'Required fields are marked with %s and must be filled in to complete the form.',
- $cue
- ));
}
+
+ return call_user_func_array('array_merge', $descriptions);
}
}
diff --git a/library/Icinga/Web/Form/Decorator/Help.php b/library/Icinga/Web/Form/Decorator/Help.php
index a02443994..152d548af 100644
--- a/library/Icinga/Web/Form/Decorator/Help.php
+++ b/library/Icinga/Web/Form/Decorator/Help.php
@@ -76,18 +76,35 @@ class Help extends Zend_Form_Decorator_Abstract
*/
public function render($content = '')
{
- if ($content && ($description = $this->getElement()->getDescription()) !== null) {
+ $element = $this->getElement();
+ $description = $element->getDescription();
+ $requirement = $element->getAttrib('requirement');
+ unset($element->requirement);
+
+ $helpContent = '';
+ if ($description || $requirement) {
if ($this->accessible) {
- $content = 'getDescriptionId()
. '" class="sr-only">'
. $description
- . '' . $content;
+ . ($description && $requirement ? ' ' : '')
+ . $requirement
+ . '';
}
- $content = $this->getView()->icon('help', $description, array('aria-hidden' => 'true')) . $content;
+ $helpContent = $this->getView()->icon(
+ 'help',
+ $description . ($description && $requirement ? ' ' : '') . $requirement,
+ array('aria-hidden' => $this->accessible ? 'true' : 'false')
+ ) . $helpContent;
}
- return $content;
+ switch ($this->getPlacement()) {
+ case self::APPEND:
+ return $content . $helpContent;
+ case self::PREPEND:
+ return $helpContent . $content;
+ }
}
}