From 690d60672c485243c9c8f9256055ed24d3a7364e Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 14:34:43 +0200 Subject: [PATCH 01/30] Introduce form element decorator Spinner refs #8369 --- library/Icinga/Web/Form.php | 8 ++++ library/Icinga/Web/Form/Decorator/Spinner.php | 45 +++++++++++++++++++ public/css/icinga/forms.less | 19 ++++++++ 3 files changed, 72 insertions(+) create mode 100644 library/Icinga/Web/Form/Decorator/Spinner.php diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index 2730f6998..40d6bb409 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -801,9 +801,17 @@ class Form extends Zend_Form && ! array_key_exists('disabledLoadDefaultDecorators', $options) ) { $options['decorators'] = static::$defaultElementDecorators; + if (! isset($options['data-progress-label']) && ($type === 'submit' + || ($type === 'button' && isset($options['type']) && $options['type'] === 'submit')) + ) { + array_splice($options['decorators'], 1, 0, array(array('Spinner', array('separator' => '')))); + } } } else { $options = array('decorators' => static::$defaultElementDecorators); + if ($type === 'submit') { + array_splice($options['decorators'], 1, 0, array(array('Spinner', array('separator' => '')))); + } } $el = parent::createElement($type, $name, $options); diff --git a/library/Icinga/Web/Form/Decorator/Spinner.php b/library/Icinga/Web/Form/Decorator/Spinner.php new file mode 100644 index 000000000..802e001d9 --- /dev/null +++ b/library/Icinga/Web/Form/Decorator/Spinner.php @@ -0,0 +1,45 @@ +getViewRenderer()->view; + } + + /** + * Add a spinner icon to a form element + * + * @param string $content The html rendered so far + * + * @return string The updated html + */ + public function render($content = '') + { + $spinner = '
' + . $this->getView()->icon('spin6') + . '
'; + + switch ($this->getPlacement()) { + case self::APPEND: + return $content . $spinner; + case self::PREPEND: + return $spinner . $content; + } + } +} \ No newline at end of file diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index 82a5f5184..f49c485a6 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -107,6 +107,25 @@ form.inline { display: inline; } +div.spinner { + display: inline-block; + margin-top: 0.2em; + margin-left: 0.25em; + + i { + visibility: hidden; + + &.active { + visibility: visible; + } + + &:before { + margin: 0; // Disables wobbling + .animate(spin 2s infinite linear); + } + } +} + button, .button-like { font-size: 0.9em; font-weight: bold; From 291c712b4422318e91e2c8a01cd6b271d411dd7f Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 14:35:40 +0200 Subject: [PATCH 02/30] Fix form element label style --- public/css/icinga/forms.less | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index f49c485a6..b761f478d 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -271,12 +271,13 @@ form div.element { form label { display: inline-block; + margin-top: 0.3em; margin-right: 1em; font-size: 0.9em; width: 10em; } -form div.element > * { +label ~ * { vertical-align: top; } @@ -314,8 +315,8 @@ select.grant-permissions { width: auto; } -label ~ input, label ~ select { - margin-left: 1.35em; +label ~ input, label ~ select, label ~ textarea { + margin-left: 1.3em; } label + i ~ input, label + i ~ select { From 2fe3c6e5cf8c5b35f913bd140c56c4db0e3f336d Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 14:36:55 +0200 Subject: [PATCH 03/30] events.js: Properly handle the default for param `autosubmit' refs #8369 --- public/js/icinga/events.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index 71408d712..109eea255 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -246,6 +246,10 @@ encoding = 'application/x-www-form-urlencoded'; } + if (typeof autosubmit === 'undefined') { + autosubmit = false; + } + if ($button.length === 0) { $button = $('input[type=submit]', $form).add('button[type=submit]', $form).first(); } @@ -271,7 +275,7 @@ if (method === 'GET') { var dataObj = $form.serializeObject(); - if (typeof autosubmit === 'undefined' || ! autosubmit) { + if (! autosubmit) { if ($button.length && $button.attr('name') !== 'undefined') { dataObj[$button.attr('name')] = $button.attr('value'); } @@ -289,7 +293,7 @@ $form.find(':input:not(:disabled)').prop('disabled', true); }, 0); - if (! typeof autosubmit === 'undefined' && autosubmit) { + if (autosubmit) { if ($button.length) { // We're autosubmitting the form so the button has not been clicked, however, // to be really safe, we're disabling the button explicitly, just in case.. @@ -310,7 +314,7 @@ data = $form.serializeArray(); } - if (typeof autosubmit === 'undefined' || ! autosubmit) { + if (! autosubmit) { if ($button.length && $button.attr('name') !== 'undefined') { if (encoding === 'multipart/form-data') { data.append($button.attr('name'), $button.attr('value')); From e3d99cb00d5da67154683ef5897263458c104ad7 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 14:38:03 +0200 Subject: [PATCH 04/30] loader.js: Add support for ajax progress timer refs #8369 refs #8848 --- public/js/icinga/loader.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js index ff63f808a..6a296d03c 100644 --- a/public/js/icinga/loader.js +++ b/public/js/icinga/loader.js @@ -42,13 +42,15 @@ /** * Load the given URL to the given target * - * @param {string} url URL to be loaded - * @param {object} target Target jQuery element - * @param {object} data Optional parameters, usually for POST requests - * @param {string} method HTTP method, default is 'GET' - * @param {string} action How to handle the response ('replace' or 'append'), default is 'replace' + * @param {string} url URL to be loaded + * @param {object} target Target jQuery element + * @param {object} data Optional parameters, usually for POST requests + * @param {string} method HTTP method, default is 'GET' + * @param {string} action How to handle the response ('replace' or 'append'), default is 'replace' + * @param {boolean} autorefresh Whether the cause is a autorefresh or not + * @param {object} progressTimer A timer to be stopped when the request is done */ - loadUrl: function (url, $target, data, method, action, autorefresh) { + loadUrl: function (url, $target, data, method, action, autorefresh, progressTimer) { var id = null; // Default method is GET @@ -131,6 +133,7 @@ req.autorefresh = autorefresh; req.action = action; req.addToHistory = true; + req.progressTimer = progressTimer; if (id) { this.requests[id] = req; @@ -537,6 +540,10 @@ return; } + if (typeof req.progressTimer !== 'undefined') { + this.icinga.timer.unregister(req.progressTimer); + } + // .html() removes outer div we added above this.renderContentToContainer($resp.html(), req.$target, req.action, req.autorefresh); if (oldNotifications) { @@ -638,6 +645,10 @@ req.$target.data('icingaUrl', url); } + if (typeof req.progressTimer !== 'undefined') { + this.icinga.timer.unregister(req.progressTimer); + } + if (req.status > 0) { this.icinga.logger.error( req.status, From fedda16bd4cb2a5f6d4ea6de34c9679bcdfad384 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 14:40:05 +0200 Subject: [PATCH 05/30] js: Use the last button instead of the first one for form submits refs #8369 fixes #9245 --- public/js/icinga/events.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index 109eea255..5b5a5ae84 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -227,11 +227,11 @@ icinga.logger.debug('events/submitForm: Button is event.currentTarget'); } - if ($el && ($el.is('input[type=submit]') || $el.is('button[type=submit]'))) { + if ($el && ($el.is('input[type=submit]') || $el.is('button[type=submit]')) && $el.is(':focus')) { $button = $el; } else { icinga.logger.debug( - 'events/submitForm: Can not determine submit button, using the first one in form' + 'events/submitForm: Can not determine submit button, using the last one in form' ); } } @@ -251,7 +251,7 @@ } if ($button.length === 0) { - $button = $('input[type=submit]', $form).add('button[type=submit]', $form).first(); + $button = $('button[type=submit]', $form).add('input[type=submit]', $form).last(); } if ($button.length) { From 7da8ad4e44895a2f442f3c990e1627a9a5656667 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 14:44:49 +0200 Subject: [PATCH 06/30] js: Show activity indicators for form submits refs #8369 --- public/css/icinga/forms.less | 16 ++++++++++++++++ public/js/icinga/events.js | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index b761f478d..510a970a9 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -327,6 +327,22 @@ button.noscript-apply { margin-left: 0.5em; } +i.autosubmit-warning { + display: inline-block; + margin-left: 0.2em; + margin-top: 0.25em; + + &.spinning { + .animate(spin 2s infinite linear); + + &:before { + margin: 0; // Disables wobbling + font-size: 90%; // icon-spin6 seems to be bigger than icon-cw + content: '\e874'; // icon-spin6 + } + } +} + html.no-js i.autosubmit-warning { .sr-only; } diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index 5b5a5ae84..ce6d62e5d 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -212,6 +212,7 @@ var method = $form.attr('method'); var encoding = $form.attr('enctype'); var $button = $('input[type=submit]:focus', $form).add('button[type=submit]:focus', $form); + var progressTimer; var $target; var data; @@ -332,7 +333,39 @@ // Note that disabled form inputs will not be enabled via JavaScript again $form.find(':input:not(#search):not(:disabled)').prop('disabled', true); - icinga.loader.loadUrl(url, $target, data, method); + // Show a spinner depending on how the form is being submitted + if (autosubmit && typeof $el !== 'undefined' && $el.next().hasClass('autosubmit-warning')) { + $el.next().addClass('spinning'); + } else if ($button.length) { + if ($button.attr('data-progress-label')) { + var isInput = $button.is('input'); + if (isInput) { + $button.prop('value', $button.attr('data-progress-label')); + } else { + $button.html($button.attr('data-progress-label')); + } + + progressTimer = icinga.timer.register(function () { + var label = isInput ? $button.prop('value') : $button.html(); + + if (label.substr(-3) === '...') { + label = label.slice(0, -2); + } else { + label += '.'; + } + + if (isInput) { + $button.prop('value', label); + } else { + $button.html(label); + } + }, null, 100); + } else if ($button.next().hasClass('spinner')) { + $('i', $button.next()).addClass('active'); + } + } + + icinga.loader.loadUrl(url, $target, data, method).progressTimer = progressTimer; event.stopPropagation(); event.preventDefault(); From 275b57cb6927445416b14d7813f8ae42db890329 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 15:04:15 +0200 Subject: [PATCH 07/30] Form: Allow to set a progress label refs #8369 --- library/Icinga/Web/Form.php | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index 40d6bb409..c5eb413d8 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -81,6 +81,13 @@ class Form extends Zend_Form */ protected $submitLabel; + /** + * Label to use for showing the user an activity indicator when submitting the form + * + * @var string + */ + protected $progressLabel; + /** * The url to redirect to upon success * @@ -263,6 +270,29 @@ class Form extends Zend_Form return $this->submitLabel; } + /** + * Set the label to use for showing the user an activity indicator when submitting the form + * + * @param string $label + * + * @return $this + */ + public function setProgressLabel($label) + { + $this->progressLabel = $label; + return $this; + } + + /** + * Return the label to use for showing the user an activity indicator when submitting the form + * + * @return string + */ + public function getProgressLabel() + { + return $this->progressLabel; + } + /** * Set the url to redirect to upon success * @@ -738,9 +768,10 @@ class Form extends Zend_Form 'submit', 'btn_submit', array( - 'ignore' => true, - 'label' => $submitLabel, - 'decorators' => array( + 'ignore' => true, + 'label' => $submitLabel, + 'data-progress-label' => $this->getProgressLabel(), + 'decorators' => array( 'ViewHelper', array('HtmlTag', array('tag' => 'div')) ) From a77dc3665c68c6504c757df187cffae1566f68a0 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 15:05:02 +0200 Subject: [PATCH 08/30] Form: Show a spinner for ongoing form submits This will only be shown if there's no progress label set. refs #8369 --- library/Icinga/Web/Form.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index c5eb413d8..cd262375a 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -773,7 +773,8 @@ class Form extends Zend_Form 'data-progress-label' => $this->getProgressLabel(), 'decorators' => array( 'ViewHelper', - array('HtmlTag', array('tag' => 'div')) + array('Spinner', array('separator' => '')), + array('HtmlTag', array('tag' => 'div', 'class' => 'buttons')) ) ) ); From 3f4221b2490ca9e2158e613864f74e7db9143285 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 15:32:31 +0200 Subject: [PATCH 09/30] js: Use a fixed with for form buttons once a form submit is ongoing ...and a progress label is set. refs #8369 --- public/js/icinga/events.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index ce6d62e5d..6a0a5c26b 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -340,18 +340,25 @@ if ($button.attr('data-progress-label')) { var isInput = $button.is('input'); if (isInput) { - $button.prop('value', $button.attr('data-progress-label')); + $button.prop('value', $button.attr('data-progress-label') + '...'); } else { - $button.html($button.attr('data-progress-label')); + $button.html($button.attr('data-progress-label') + '...'); } + // Use a fixed width to prevent the button from wobbling + $button.css('width', $button.css('width')); + progressTimer = icinga.timer.register(function () { var label = isInput ? $button.prop('value') : $button.html(); + var dots = label.substr(-3); - if (label.substr(-3) === '...') { - label = label.slice(0, -2); - } else { - label += '.'; + // Using empty spaces here to prevent centered labels from wobbling + if (dots === '...') { + label = label.slice(0, -2) + ' '; + } else if (dots === '.. ') { + label = label.slice(0, -1) + '.'; + } else if (dots === '. ') { + label = label.slice(0, -2) + '. '; } if (isInput) { From bf1e17702355326452082a67097465bdec993fd3 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 15:32:53 +0200 Subject: [PATCH 10/30] LoginForm: Provide a progress label refs #8369 --- application/forms/Authentication/LoginForm.php | 1 + 1 file changed, 1 insertion(+) diff --git a/application/forms/Authentication/LoginForm.php b/application/forms/Authentication/LoginForm.php index f7bae3d1b..9646046f6 100644 --- a/application/forms/Authentication/LoginForm.php +++ b/application/forms/Authentication/LoginForm.php @@ -27,6 +27,7 @@ class LoginForm extends Form $this->setRequiredCue(null); $this->setName('form_login'); $this->setSubmitLabel($this->translate('Login')); + $this->setProgressLabel($this->translate('Logging in')); } /** From 5602d57d0b7c730ff6e8e3ccb62797b92f9cd39e Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 15:48:41 +0200 Subject: [PATCH 11/30] Indicate that the configuration is being validated refs #8369 --- application/forms/Config/ResourceConfigForm.php | 7 ++++--- application/forms/Config/UserBackendConfigForm.php | 7 ++++--- modules/monitoring/library/Monitoring/MonitoringWizard.php | 7 ++++--- modules/setup/library/Setup/WebWizard.php | 7 ++++--- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/application/forms/Config/ResourceConfigForm.php b/application/forms/Config/ResourceConfigForm.php index 51e1b1bff..db951e67a 100644 --- a/application/forms/Config/ResourceConfigForm.php +++ b/application/forms/Config/ResourceConfigForm.php @@ -344,9 +344,10 @@ class ResourceConfigForm extends ConfigForm 'submit', 'resource_validation', array( - 'ignore' => true, - 'label' => $this->translate('Validate Configuration'), - 'decorators' => array('ViewHelper') + 'ignore' => true, + 'label' => $this->translate('Validate Configuration'), + 'data-progress-label' => $this->translate('Validation In Progress'), + 'decorators' => array('ViewHelper') ) ); $this->addDisplayGroup( diff --git a/application/forms/Config/UserBackendConfigForm.php b/application/forms/Config/UserBackendConfigForm.php index 5ee4674bb..1183ae724 100644 --- a/application/forms/Config/UserBackendConfigForm.php +++ b/application/forms/Config/UserBackendConfigForm.php @@ -464,9 +464,10 @@ class UserBackendConfigForm extends ConfigForm 'submit', 'backend_validation', array( - 'ignore' => true, - 'label' => $this->translate('Validate Configuration'), - 'decorators' => array('ViewHelper') + 'ignore' => true, + 'label' => $this->translate('Validate Configuration'), + 'data-progress-label' => $this->translate('Validation In Progress'), + 'decorators' => array('ViewHelper') ) ); $this->addDisplayGroup( diff --git a/modules/monitoring/library/Monitoring/MonitoringWizard.php b/modules/monitoring/library/Monitoring/MonitoringWizard.php index 0a224610c..4b495c36e 100644 --- a/modules/monitoring/library/Monitoring/MonitoringWizard.php +++ b/modules/monitoring/library/Monitoring/MonitoringWizard.php @@ -120,9 +120,10 @@ class MonitoringWizard extends Wizard implements SetupWizard 'submit', 'backend_validation', array( - 'ignore' => true, - 'label' => t('Validate Configuration'), - 'decorators' => array('ViewHelper') + 'ignore' => true, + 'label' => t('Validate Configuration'), + 'data-progress-label' => t('Validation In Progress'), + 'decorators' => array('ViewHelper') ) ); $page->getDisplayGroup('buttons')->addElement($page->getElement('backend_validation')); diff --git a/modules/setup/library/Setup/WebWizard.php b/modules/setup/library/Setup/WebWizard.php index e3831e673..7b67a2c2f 100644 --- a/modules/setup/library/Setup/WebWizard.php +++ b/modules/setup/library/Setup/WebWizard.php @@ -369,9 +369,10 @@ class WebWizard extends Wizard implements SetupWizard 'submit', 'backend_validation', array( - 'ignore' => true, - 'label' => t('Validate Configuration'), - 'decorators' => array('ViewHelper') + 'ignore' => true, + 'label' => t('Validate Configuration'), + 'data-progress-label' => t('Validation In Progress'), + 'decorators' => array('ViewHelper') ) ); $page->getDisplayGroup('buttons')->addElement($page->getElement('backend_validation')); From 4edf1223646517b36999fd3ee1d8c2667d91581d Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 15:49:25 +0200 Subject: [PATCH 12/30] Show a spinner when deleting comments or downtimes refs #8369 --- .../forms/Command/Object/DeleteCommentCommandForm.php | 2 +- .../forms/Command/Object/DeleteDowntimeCommandForm.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php b/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php index 691b7dbed..442b9b2ce 100644 --- a/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php @@ -68,7 +68,7 @@ class DeleteCommentCommandForm extends CommandForm 'ignore' => true, 'escape' => false, 'type' => 'submit', - 'class' => 'link-like', + 'class' => 'link-like spinner', 'label' => $this->getView()->icon('trash'), 'title' => $this->translate('Delete this comment'), 'decorators' => array('ViewHelper') diff --git a/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php b/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php index c58179fe6..27fbae67a 100644 --- a/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php @@ -68,7 +68,7 @@ class DeleteDowntimeCommandForm extends CommandForm 'ignore' => true, 'escape' => false, 'type' => 'submit', - 'class' => 'link-like', + 'class' => 'link-like spinner', 'label' => $this->getView()->icon('trash'), 'title' => $this->translate('Delete this downtime'), 'decorators' => array('ViewHelper') From 736d715d8c2f81480ada9b35df6525601b5667c5 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 16:13:12 +0200 Subject: [PATCH 13/30] js: Allow to provide a fallback spinner for forms refs #8369 --- public/js/icinga/events.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index 6a0a5c26b..c05acf047 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -369,6 +369,11 @@ }, null, 100); } else if ($button.next().hasClass('spinner')) { $('i', $button.next()).addClass('active'); + } else if ($form.attr('data-progress-element')) { + var $progressElement = $('#' + $form.attr('data-progress-element')); + if ($progressElement.length) { + $('i', $progressElement).addClass('active'); + } } } From 20f144bd4ba2d3ed185fdd35ee4e12a6318c1dba Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 16:13:30 +0200 Subject: [PATCH 14/30] Spinner: Accept option `id' refs #8369 --- library/Icinga/Web/Form/Decorator/Spinner.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/Icinga/Web/Form/Decorator/Spinner.php b/library/Icinga/Web/Form/Decorator/Spinner.php index 802e001d9..b47798d26 100644 --- a/library/Icinga/Web/Form/Decorator/Spinner.php +++ b/library/Icinga/Web/Form/Decorator/Spinner.php @@ -31,7 +31,10 @@ class Spinner extends Zend_Form_Decorator_Abstract */ public function render($content = '') { - $spinner = '
' + $spinner = '
getOption('id') !== null ? ' id="' . $this->getOption('id') . '"' : '') + . 'class="spinner ' . ($this->getOption('class') ?: '') . '"' + . '>' . $this->getView()->icon('spin6') . '
'; From 32f8c0770c91878d128442593a77748f24828b2e Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 16:13:56 +0200 Subject: [PATCH 15/30] Wizard: Use a single spinner for all submit buttons refs #8369 --- library/Icinga/Web/Wizard.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/library/Icinga/Web/Wizard.php b/library/Icinga/Web/Wizard.php index 1af211017..f70452d3b 100644 --- a/library/Icinga/Web/Wizard.php +++ b/library/Icinga/Web/Wizard.php @@ -655,8 +655,21 @@ class Wizard ); } + $page->setAttrib('data-progress-element', 'wizard-progress'); + $page->addElement( + 'note', + 'progress', + array( + 'order' => 99, + 'decorators' => array( + 'ViewHelper', + array('Spinner', array('id' => 'wizard-progress')) + ) + ) + ); + $page->addDisplayGroup( - array(static::BTN_PREV, static::BTN_NEXT), + array(static::BTN_PREV, static::BTN_NEXT, 'progress'), 'buttons', array( 'decorators' => array( From ebd34422cb9625b4137f27697a130f451d1da7dc Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 16:53:26 +0200 Subject: [PATCH 16/30] forms: Fix textarea layout with help icons --- public/css/icinga/forms.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index 510a970a9..1563b8c0d 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -319,7 +319,7 @@ label ~ input, label ~ select, label ~ textarea { margin-left: 1.3em; } -label + i ~ input, label + i ~ select { +label + i ~ input, label + i ~ select, label + i ~ textarea { margin-left: 0; } From 46cd47b73cc7ef657e8c80b998184e5bca0de622 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 16:54:20 +0200 Subject: [PATCH 17/30] Form: Automatically set data-progress-element... ..for forms with form based autosubmit warnings. refs #8369 --- library/Icinga/Web/Form.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index cd262375a..40ddf4ee0 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -668,6 +668,12 @@ class Form extends Zend_Form public function setUseFormAutosubmit($state = true) { $this->useFormAutosubmit = (bool) $state; + if ($this->useFormAutosubmit) { + $this->setAttrib('data-progress-element', 'form-header'); + } else { + $this->removeAttrib('data-progress-element'); + } + return $this; } @@ -1203,7 +1209,7 @@ class Form extends Zend_Form $this->addDecorator('Description', array('tag' => 'h1')); if ($this->getUseFormAutosubmit()) { $this->addDecorator('Autosubmit', array('accessible' => true)) - ->addDecorator('HtmlTag', array('tag' => 'div', 'class' => 'header')); + ->addDecorator('HtmlTag', array('tag' => 'div', 'class' => 'header', 'id' => 'form-header')); } $this->addDecorator('FormDescriptions') From d9855d82736a64bbf836e947aa176182add33329 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 20 Aug 2015 16:55:03 +0200 Subject: [PATCH 18/30] js: Fix that the fallback spinner is not utilized for auto submits refs #8369 --- public/js/icinga/events.js | 70 ++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index c05acf047..470486285 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -336,43 +336,45 @@ // Show a spinner depending on how the form is being submitted if (autosubmit && typeof $el !== 'undefined' && $el.next().hasClass('autosubmit-warning')) { $el.next().addClass('spinning'); - } else if ($button.length) { - if ($button.attr('data-progress-label')) { - var isInput = $button.is('input'); - if (isInput) { - $button.prop('value', $button.attr('data-progress-label') + '...'); - } else { - $button.html($button.attr('data-progress-label') + '...'); + } else if ($button.length && $button.attr('data-progress-label')) { + var isInput = $button.is('input'); + if (isInput) { + $button.prop('value', $button.attr('data-progress-label') + '...'); + } else { + $button.html($button.attr('data-progress-label') + '...'); + } + + // Use a fixed width to prevent the button from wobbling + $button.css('width', $button.css('width')); + + progressTimer = icinga.timer.register(function () { + var label = isInput ? $button.prop('value') : $button.html(); + var dots = label.substr(-3); + + // Using empty spaces here to prevent centered labels from wobbling + if (dots === '...') { + label = label.slice(0, -2) + ' '; + } else if (dots === '.. ') { + label = label.slice(0, -1) + '.'; + } else if (dots === '. ') { + label = label.slice(0, -2) + '. '; } - // Use a fixed width to prevent the button from wobbling - $button.css('width', $button.css('width')); - - progressTimer = icinga.timer.register(function () { - var label = isInput ? $button.prop('value') : $button.html(); - var dots = label.substr(-3); - - // Using empty spaces here to prevent centered labels from wobbling - if (dots === '...') { - label = label.slice(0, -2) + ' '; - } else if (dots === '.. ') { - label = label.slice(0, -1) + '.'; - } else if (dots === '. ') { - label = label.slice(0, -2) + '. '; - } - - if (isInput) { - $button.prop('value', label); - } else { - $button.html(label); - } - }, null, 100); - } else if ($button.next().hasClass('spinner')) { - $('i', $button.next()).addClass('active'); - } else if ($form.attr('data-progress-element')) { - var $progressElement = $('#' + $form.attr('data-progress-element')); - if ($progressElement.length) { + if (isInput) { + $button.prop('value', label); + } else { + $button.html(label); + } + }, null, 100); + } else if ($button.length && $button.next().hasClass('spinner')) { + $('i', $button.next()).addClass('active'); + } else if ($form.attr('data-progress-element')) { + var $progressElement = $('#' + $form.attr('data-progress-element')); + if ($progressElement.length) { + if ($progressElement.hasClass('spinner')) { $('i', $progressElement).addClass('active'); + } else { + $('i.autosubmit-warning', $progressElement).addClass('spinning'); } } } From 07b17cc7018c91d69a5bf5739b1576f937f05d54 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 21 Aug 2015 09:52:57 +0200 Subject: [PATCH 19/30] Wizard: Add Spinner decorator to the first (and only) submit button refs #8369 --- library/Icinga/Web/Wizard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Icinga/Web/Wizard.php b/library/Icinga/Web/Wizard.php index f70452d3b..bf68e3527 100644 --- a/library/Icinga/Web/Wizard.php +++ b/library/Icinga/Web/Wizard.php @@ -606,7 +606,7 @@ class Wizard 'type' => 'submit', 'value' => $pages[1]->getName(), 'label' => t('Next'), - 'decorators' => array('ViewHelper') + 'decorators' => array('ViewHelper', 'Spinner') ) ); } elseif ($index < count($pages) - 1) { From 7dd3fc6c78fa929bd9530242dd50a46291d5356d Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 21 Aug 2015 09:54:05 +0200 Subject: [PATCH 20/30] Make sure that the spinner is only animated when visible refs #8369 --- public/css/icinga/forms.less | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index 1563b8c0d..18b7da2b8 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -117,11 +117,14 @@ div.spinner { &.active { visibility: visible; + + &:before { + .animate(spin 2s infinite linear); + } } &:before { margin: 0; // Disables wobbling - .animate(spin 2s infinite linear); } } } From 7244906515d7f5ace611533768e06907756396c0 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 21 Aug 2015 10:16:23 +0200 Subject: [PATCH 21/30] Wizard: Use a constant for the name and id of the progress element refs #8369 --- library/Icinga/Web/Wizard.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/library/Icinga/Web/Wizard.php b/library/Icinga/Web/Wizard.php index bf68e3527..d397db52b 100644 --- a/library/Icinga/Web/Wizard.php +++ b/library/Icinga/Web/Wizard.php @@ -38,6 +38,11 @@ class Wizard */ const BTN_PREV = 'btn_prev'; + /** + * The name and id of the element for showing the user an activity indicator when advancing the wizard + */ + const PROGRESS_ELEMENT = 'wizard_progress'; + /** * This wizard's parent * @@ -655,21 +660,21 @@ class Wizard ); } - $page->setAttrib('data-progress-element', 'wizard-progress'); + $page->setAttrib('data-progress-element', static::PROGRESS_ELEMENT); $page->addElement( 'note', - 'progress', + static::PROGRESS_ELEMENT, array( - 'order' => 99, + 'order' => 99, // Ensures that it's shown on the right even if a sub-class adds another button 'decorators' => array( 'ViewHelper', - array('Spinner', array('id' => 'wizard-progress')) + array('Spinner', array('id' => static::PROGRESS_ELEMENT)) ) ) ); $page->addDisplayGroup( - array(static::BTN_PREV, static::BTN_NEXT, 'progress'), + array(static::BTN_PREV, static::BTN_NEXT, static::PROGRESS_ELEMENT), 'buttons', array( 'decorators' => array( From a960f2cb4c246530fa332345cacea46824521b35 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 21 Aug 2015 10:17:03 +0200 Subject: [PATCH 22/30] forms.less: Animate the icon char, not the i-tag refs #8369 --- public/css/icinga/forms.less | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index 18b7da2b8..b3933b496 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -335,14 +335,11 @@ i.autosubmit-warning { margin-left: 0.2em; margin-top: 0.25em; - &.spinning { + &.spinning:before { + margin: 0; // Disables wobbling + font-size: 90%; // icon-spin6 seems to be bigger than icon-cw + content: '\e874'; // icon-spin6 .animate(spin 2s infinite linear); - - &:before { - margin: 0; // Disables wobbling - font-size: 90%; // icon-spin6 seems to be bigger than icon-cw - content: '\e874'; // icon-spin6 - } } } From c395dbd813b34b798a13c5b8fb67598427e141ce Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 21 Aug 2015 10:35:10 +0200 Subject: [PATCH 23/30] Wizard: Add missing progress element to custom form scripts refs #8369 --- .../views/scripts/form/setup-modules.phtml | 12 ++++++++++-- .../views/scripts/form/setup-requirements.phtml | 10 +++++++++- .../views/scripts/form/setup-summary.phtml | 11 ++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/modules/setup/application/views/scripts/form/setup-modules.phtml b/modules/setup/application/views/scripts/form/setup-modules.phtml index 8d8e9ecf9..859acfaa2 100644 --- a/modules/setup/application/views/scripts/form/setup-modules.phtml +++ b/modules/setup/application/views/scripts/form/setup-modules.phtml @@ -3,11 +3,18 @@ use Icinga\Web\Wizard; ?> -
+

translate('Modules', 'setup.page.title'); ?>

translate('The following modules were found in your Icinga Web 2 installation. To enable and configure a module, just tick it and click "Next".'); ?>

getElements() as $element): ?> - getName(), array(Wizard::BTN_PREV, Wizard::BTN_NEXT, $form->getTokenElementName(), $form->getUidElementName()))): ?> + getName(), array(Wizard::BTN_PREV, Wizard::BTN_NEXT, Wizard::PROGRESS_ELEMENT, $form->getTokenElementName(), $form->getUidElementName()))): ?>

@@ -20,5 +27,6 @@ use Icinga\Web\Wizard;
getElement(Wizard::BTN_PREV); ?> getElement(Wizard::BTN_NEXT); ?> + getElement(Wizard::PROGRESS_ELEMENT); ?>
diff --git a/modules/setup/application/views/scripts/form/setup-requirements.phtml b/modules/setup/application/views/scripts/form/setup-requirements.phtml index fbd2c692a..3ddd5b404 100644 --- a/modules/setup/application/views/scripts/form/setup-requirements.phtml +++ b/modules/setup/application/views/scripts/form/setup-requirements.phtml @@ -9,7 +9,14 @@ use Icinga\Web\Wizard;

translate('Module'); ?>

getRequirements(); ?> -
+ getElement($form->getTokenElementName()); ?> getElement($form->getUidElementName()); ?>
@@ -21,6 +28,7 @@ use Icinga\Web\Wizard; } echo $btn; ?> + getElement(Wizard::PROGRESS_ELEMENT); ?>
translate('You may also need to restart the web-server for the changes to take effect!'); ?> qlink( diff --git a/modules/setup/application/views/scripts/form/setup-summary.phtml b/modules/setup/application/views/scripts/form/setup-summary.phtml index e8053a897..7c91ecd05 100644 --- a/modules/setup/application/views/scripts/form/setup-summary.phtml +++ b/modules/setup/application/views/scripts/form/setup-summary.phtml @@ -20,11 +20,20 @@ use Icinga\Web\Wizard;
- + getElement($form->getTokenElementName()); ?> getElement($form->getUidElementName()); ?>
getElement(Wizard::BTN_PREV); ?> getElement(Wizard::BTN_NEXT)->setAttrib('class', 'finish'); ?> + getElement(Wizard::PROGRESS_ELEMENT); ?>
\ No newline at end of file From b9d64b40a4f62d72d06f0e0945e1603ca1fa8650 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 21 Aug 2015 10:36:08 +0200 Subject: [PATCH 24/30] forms.less: Fix help icon layout --- library/Icinga/Web/Form/Decorator/Help.php | 5 ++++- public/css/icinga/forms.less | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/library/Icinga/Web/Form/Decorator/Help.php b/library/Icinga/Web/Form/Decorator/Help.php index 152d548af..531072a6b 100644 --- a/library/Icinga/Web/Form/Decorator/Help.php +++ b/library/Icinga/Web/Form/Decorator/Help.php @@ -96,7 +96,10 @@ class Help extends Zend_Form_Decorator_Abstract $helpContent = $this->getView()->icon( 'help', $description . ($description && $requirement ? ' ' : '') . $requirement, - array('aria-hidden' => $this->accessible ? 'true' : 'false') + array( + 'class' => 'help', + 'aria-hidden' => $this->accessible ? 'true' : 'false' + ) ) . $helpContent; } diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index b3933b496..16b4968b6 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -274,12 +274,17 @@ form div.element { form label { display: inline-block; - margin-top: 0.3em; + vertical-align: top; + margin-top: 0.25em; margin-right: 1em; font-size: 0.9em; width: 10em; } +form div.element i.help:before { + margin-top: 0.25em; +} + label ~ * { vertical-align: top; } From 89bc1f13edec7d5e57e44e48f393cd24178694a8 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 21 Aug 2015 10:53:16 +0200 Subject: [PATCH 25/30] forms.less: Prevent that the sort control "wobbles" I love this word.. refs #8369 --- public/css/icinga/forms.less | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index 16b4968b6..574acadfa 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -340,9 +340,11 @@ i.autosubmit-warning { margin-left: 0.2em; margin-top: 0.25em; - &.spinning:before { + &:before { margin: 0; // Disables wobbling - font-size: 90%; // icon-spin6 seems to be bigger than icon-cw + } + + &.spinning:before { content: '\e874'; // icon-spin6 .animate(spin 2s infinite linear); } From 747f6dcf770b91097402af6eb9c59fa1a4c0c2b4 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 21 Aug 2015 11:40:38 +0200 Subject: [PATCH 26/30] Form: Show the form autosubmit warning in the header tag... ...and use a unique id for the progress element. refs #8369 --- library/Icinga/Web/Form.php | 38 +++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index 40ddf4ee0..ef8168b5c 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -669,7 +669,7 @@ class Form extends Zend_Form { $this->useFormAutosubmit = (bool) $state; if ($this->useFormAutosubmit) { - $this->setAttrib('data-progress-element', 'form-header'); + $this->setAttrib('data-progress-element', 'header-' . $this->getId()); } else { $this->removeAttrib('data-progress-element'); } @@ -1206,13 +1206,16 @@ class Form extends Zend_Form 'form' => $this )); } else { - $this->addDecorator('Description', array('tag' => 'h1')); - if ($this->getUseFormAutosubmit()) { - $this->addDecorator('Autosubmit', array('accessible' => true)) - ->addDecorator('HtmlTag', array('tag' => 'div', 'class' => 'header', 'id' => 'form-header')); - } - - $this->addDecorator('FormDescriptions') + $this->addDecorator('Description', array('tag' => 'h1', 'escape' => !$this->getUseFormAutosubmit())) + ->addDecorator( + 'HtmlTag', + array( + 'tag' => 'div', + 'class' => 'header', + 'id' => 'header-' . $this->getId() + ) + ) + ->addDecorator('FormDescriptions') ->addDecorator('FormNotifications') ->addDecorator('FormErrors', array('onlyCustomFormErrors' => true)) ->addDecorator('FormElements') @@ -1256,6 +1259,25 @@ class Form extends Zend_Form return $name; } + /** + * Retrieve form description + * + * This will return the escaped description with the autosubmit warning icon if form autosubmit is enabled. + * + * @return string + */ + public function getDescription() + { + $description = parent::getDescription(); + if ($description && $this->getUseFormAutosubmit()) { + $autosubmit = $this->_getDecorator('Autosubmit', array('accessible' => true)); + $autosubmit->setElement($this); + $description = $autosubmit->render($this->getView()->escape($description)); + } + + return $description; + } + /** * Set the action to submit this form against * From a11705a3fc7237fbd6ded2ad3875e5cd1ab52606 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 21 Aug 2015 11:46:39 +0200 Subject: [PATCH 27/30] monitoring: Show the autosubmit warning when toggling object features refs #8369 --- modules/monitoring/public/css/module.less | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 3aabe1f51..6ea967a1c 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -186,10 +186,6 @@ table.avp { } } - .autosubmit-warning { - display: none; - } - .object-features { label { font-weight: normal; From 08aefe0b25b668f8163118addf934423d2ddb371 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 21 Aug 2015 13:28:35 +0200 Subject: [PATCH 28/30] js: Allow buttons to animate themself refs #8369 --- public/js/icinga/events.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index 470486285..1114f79f0 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -336,6 +336,8 @@ // Show a spinner depending on how the form is being submitted if (autosubmit && typeof $el !== 'undefined' && $el.next().hasClass('autosubmit-warning')) { $el.next().addClass('spinning'); + } else if ($button.length && $button.is('button') && $button.hasClass('animated')) { + $button.addClass('active'); } else if ($button.length && $button.attr('data-progress-label')) { var isInput = $button.is('input'); if (isInput) { From 1cb2009dcd9d4dcf35fc282a3688d8398958761e Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 21 Aug 2015 13:29:29 +0200 Subject: [PATCH 29/30] Animate the button when reordering authentication backends refs #8369 --- .../scripts/form/reorder-authbackend.phtml | 4 +- public/css/icinga/animation.less | 251 ++++++++++++++++++ public/css/icinga/forms.less | 10 + 3 files changed, 263 insertions(+), 2 deletions(-) diff --git a/application/views/scripts/form/reorder-authbackend.phtml b/application/views/scripts/form/reorder-authbackend.phtml index ec1cf7810..4edc7e06f 100644 --- a/application/views/scripts/form/reorder-authbackend.phtml +++ b/application/views/scripts/form/reorder-authbackend.phtml @@ -39,7 +39,7 @@ 0): ?> -