diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index 24f0e2657..326730ac3 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -160,6 +160,13 @@ class Form extends Zend_Form */ protected $notifications; + /** + * The hints of this form + * + * @var array + */ + protected $hints; + /** * Whether the Autosubmit decorator should be applied to this form * @@ -566,6 +573,49 @@ class Form extends Zend_Form return $this->notifications; } + /** + * Set the hints for this form + * + * @param array $hints + * + * @return $this + */ + public function setHints(array $hints) + { + $this->hints = $hints; + return $this; + } + + /** + * Add a hint for this form + * + * If $hint is an array the second value should be an + * array as well containing additional HTML properties. + * + * @param string|array $hint + * + * @return $this + */ + public function addHint($hint) + { + $this->hints[] = $hint; + return $this; + } + + /** + * Return the hints of this form + * + * @return array + */ + public function getHints() + { + if ($this->hints === null) { + return array(); + } + + return $this->hints; + } + /** * Set whether the Autosubmit decorator should be applied to this form * @@ -1091,6 +1141,7 @@ class Form extends Zend_Form ->addDecorator('FormNotifications') ->addDecorator('FormErrors', array('onlyCustomFormErrors' => true)) ->addDecorator('FormElements') + ->addDecorator('FormHints') //->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form')) ->addDecorator('Form'); } diff --git a/library/Icinga/Web/Form/Decorator/FormHints.php b/library/Icinga/Web/Form/Decorator/FormHints.php new file mode 100644 index 000000000..91e906684 --- /dev/null +++ b/library/Icinga/Web/Form/Decorator/FormHints.php @@ -0,0 +1,142 @@ +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 hints + * + * @param string $content The html rendered so far + * + * @return string The updated html + */ + public function render($content = '') + { + $form = $this->getElement(); + if (! $form instanceof Form) { + return $content; + } + + $view = $form->getView(); + if ($view === null) { + return $content; + } + + $hints = $this->recurseForm($form, $entirelyRequired); + if ($entirelyRequired !== null) { + $hints[] = $form->getView()->translate(sprintf( + 'Required fields are marked with %s and must be filled in to complete the form.', + $form->getRequiredCue() + )); + } + + if (empty($hints)) { + return $content; + } + + $html = ''; + case self::PREPEND: + return $html . '' . $content; + } + } + + /** + * Recurse the given form and return the hints for it and all of its subforms + * + * @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 array + */ + protected function recurseForm(Form $form, & $entirelyRequired = null, $elementsPassed = false) + { + $requiredLabels = array(); + 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; + } + } + + $hints = array($form->getHints()); + foreach ($form->getSubForms() as $subForm) { + $hints[] = $this->recurseForm($subForm, $entirelyRequired, $elementsPassed); + } + + if ($entirelyRequired) { + foreach ($requiredLabels as $label) { + $label->setRequiredSuffix(''); + } + } + + return call_user_func_array('array_merge', $hints); + } +} diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index 42f04d7f3..3323520db 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -259,3 +259,13 @@ form ul.descriptions { } } } + +form ul.hints { + .non-list-like-list; + padding: 0.5em 0.5em 0 0.5em; + + li { + font-size: 0.8em; + padding-bottom: 0.5em; + } +} \ No newline at end of file