Skip to content

Commit

Permalink
Merge branch 'feature/exhaustive-form-descriptions-7947'
Browse files Browse the repository at this point in the history
resolves #7947
  • Loading branch information
Johannes Meyer committed Mar 6, 2015
2 parents 2df7c60 + 9ca0d6a commit ff66583
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 49 deletions.
Expand Up @@ -53,7 +53,7 @@ public function createElements(array $formData)
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(
Expand All @@ -62,9 +62,10 @@ public function createElements(array $formData)
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)
)
);
Expand Down
1 change: 1 addition & 0 deletions application/forms/Config/General/LoggingConfigForm.php
Expand Up @@ -66,6 +66,7 @@ public function createElements(array $formData)
'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(
Expand Down
12 changes: 11 additions & 1 deletion application/forms/Config/Resource/FileResourceForm.php
Expand Up @@ -3,6 +3,7 @@

namespace Icinga\Forms\Config\Resource;

use Zend_Validate_Callback;
use Icinga\Web\Form;

/**
Expand Down Expand Up @@ -42,13 +43,22 @@ public function createElements(array $formData)
'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)
)
);

Expand Down
6 changes: 3 additions & 3 deletions library/Icinga/Web/Form.php
Expand Up @@ -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'))
);
Expand Down Expand Up @@ -622,7 +622,7 @@ public function addSubmitButton()
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();
Expand Down Expand Up @@ -743,7 +743,7 @@ public function ensureElementAccessibility(Zend_Form_Element $element)
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(' <span aria-hidden="true">%s</span>', $cue));
$label->setRequiredSuffix(sprintf(' <span aria-hidden="true">%s</span>', $cue));
}
}

Expand Down
108 changes: 71 additions & 37 deletions library/Icinga/Web/Form/Decorator/FormDescriptions.php
Expand Up @@ -13,6 +13,29 @@
*/
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
*
Expand All @@ -32,9 +55,16 @@ public function render($content = '')
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)) {
Expand All @@ -60,53 +90,57 @@ public function render($content = '')
}

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

$descriptions = array($form->getDescriptions());
foreach ($form->getSubForms() as $subForm) {
$descriptions[] = $this->recurseForm($subForm, $entirelyRequired, $elementsPassed);
}

if ($entirelyRequired && $partiallyRequired) {
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);
}
}
27 changes: 22 additions & 5 deletions library/Icinga/Web/Form/Decorator/Help.php
Expand Up @@ -76,18 +76,35 @@ protected function getView()
*/
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 = '<span id="'
$helpContent = '<span id="'
. $this->getDescriptionId()
. '" class="sr-only">'
. $description
. '</span>' . $content;
. ($description && $requirement ? ' ' : '')
. $requirement
. '</span>';
}

$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;
}
}
}

0 comments on commit ff66583

Please sign in to comment.