diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index 37aa44e23..0dc607412 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -13,7 +13,7 @@ use Icinga\Authentication\Manager; use Icinga\Security\SecurityException; use Icinga\Util\Translator; use Icinga\Web\Form\ErrorLabeller; -use Icinga\Web\Form\Decorator\NoScriptApply; +use Icinga\Web\Form\Decorator\Autosubmit; use Icinga\Web\Form\Element\CsrfCounterMeasure; /** @@ -592,16 +592,27 @@ class Form extends Zend_Form ) )); + if ($this->protectIds) { + $el->setAttrib('id', $this->getRequest()->protectId($this->getId(false) . '_' . $el->getId())); + } + if ($el->getAttrib('autosubmit')) { - $noScript = new NoScriptApply(); // Non-JS environments + $autosubmitDecorator = new Autosubmit(); + $autosubmitDecorator->setAccessible(); $decorators = $el->getDecorators(); $pos = array_search('Zend_Form_Decorator_ViewHelper', array_keys($decorators)) + 1; $el->setDecorators( array_slice($decorators, 0, $pos, true) - + array(get_class($noScript) => $noScript) + + array(get_class($autosubmitDecorator) => $autosubmitDecorator) + array_slice($decorators, $pos, count($decorators) - $pos, true) ); + if (($describedBy = $el->getAttrib('aria-describedby')) !== null) { + $el->setAttrib('aria-describedby', $describedBy . ' ' . $autosubmitDecorator->getWarningId($el)); + } else { + $el->setAttrib('aria-describedby', $autosubmitDecorator->getWarningId($el)); + } + $class = $el->getAttrib('class'); if (is_array($class)) { $class[] = 'autosubmit'; @@ -610,15 +621,11 @@ class Form extends Zend_Form } else { $class .= ' autosubmit'; } - $el->setAttrib('class', $class); // JS environments + $el->setAttrib('class', $class); unset($el->autosubmit); } - if ($this->protectIds) { - $el->setAttrib('id', $this->getRequest()->protectId($this->getId(false) . '_' . $el->getId())); - } - return $this->ensureElementAccessibility($el); } @@ -642,7 +649,17 @@ class Form extends Zend_Form } if ($element->getDescription() !== null && ($help = $element->getDecorator('help')) !== false) { - $element->setAttrib('aria-describedby', $help->setAccessible()->getDescriptionId($element)); + if (($describedBy = $element->getAttrib('aria-describedby')) !== null) { + // Assume that it's because of the element being of type autosubmit or + // that one who did set the property manually removes the help decorator + // in case it has already an aria-requiredby property set + $element->setAttrib( + 'aria-describedby', + $help->setAccessible()->getDescriptionId($element) . ' ' . $describedBy + ); + } else { + $element->setAttrib('aria-describedby', $help->setAccessible()->getDescriptionId($element)); + } } return $element; diff --git a/library/Icinga/Web/Form/Decorator/Autosubmit.php b/library/Icinga/Web/Form/Decorator/Autosubmit.php new file mode 100644 index 000000000..928325919 --- /dev/null +++ b/library/Icinga/Web/Form/Decorator/Autosubmit.php @@ -0,0 +1,108 @@ + should be created with the same warning as in the icon label + * + * @var bool + */ + protected $accessible = false; + + /** + * The id used to identify the auto-submit warning associated with the decorated form element + * + * @var string + */ + protected $warningId; + + /** + * Set whether a hidden should be created with the same warning as in the icon label + * + * @param bool $state + * + * @return Autosubmit + */ + public function setAccessible($state = true) + { + $this->accessible = (bool) $state; + return $this; + } + + /** + * Return the id used to identify the auto-submit warning associated with the decorated element + * + * @param Zend_Form_Element $element The element for which to generate a id + * + * @return string + */ + public function getWarningId(Zend_Form_Element $element = null) + { + if ($this->warningId === null) { + $element = $element ?: $this->getElement(); + $this->warningId = 'autosubmit_warning_' . $element->getId(); + } + + return $this->warningId; + } + + /** + * Return the current view + * + * @return View + */ + protected function getView() + { + return Icinga::app()->getViewRenderer()->view; + } + + /** + * Add a auto-submit icon and submit button encapsulated in noscript-tags to the element + * + * @param string $content The html rendered so far + * + * @return string The updated html + */ + public function render($content = '') + { + if ($content) { + $warning = t('Upon its value has changed, this control issues an automatic update of this page.'); + $content .= $this->getView()->icon('cw', $warning, array( + 'aria-hidden' => 'true', + 'class' => 'autosubmit-warning' + )); + if ($this->accessible) { + $content = '' . $warning . '' . $content; + } + + $content .= sprintf( + '', + t('Push this button to update the form to reflect the change that was made in the control on the left'), + $this->getView()->icon('cw') . t('Apply') + ); + } + + return $content; + } +} diff --git a/library/Icinga/Web/Form/Decorator/NoScriptApply.php b/library/Icinga/Web/Form/Decorator/NoScriptApply.php deleted file mode 100644 index fbc96756b..000000000 --- a/library/Icinga/Web/Form/Decorator/NoScriptApply.php +++ /dev/null @@ -1,34 +0,0 @@ -'; - } - - return $content; - } -} diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index d455bf654..ae7ebf720 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -195,6 +195,18 @@ select.grant-permissions { width: auto; } -label + input, label + select, label + input + input { +label ~ input, label ~ select { margin-left: 1.6em; +} + +label + i ~ input, label + i ~ select { + margin-left: 0; +} + +button.noscript-apply { + margin-left: 0.5em; +} + +html.no-js i.autosubmit-warning { + .sr-only; } \ No newline at end of file