From c5fde2324eee12c3fc6c023d11299dd035a0a805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannis=20Mo=C3=9Fhammer?= Date: Thu, 29 Aug 2013 14:09:20 +0200 Subject: [PATCH] Generalize form handling in Icinga\Web Form & Tests configForm.js is now form.js and applied on all forms, the autosubmit is now a special attribute for input fields, so the PHP code doesn't create JS snippets anymore refs #4622 --- application/forms/Config/LoggingForm.php | 1 - library/Icinga/Web/Form.php | 5 +- public/js/icinga/componentLoader.js | 9 +- public/js/icinga/components/configForm.js | 50 --------- public/js/icinga/components/form.js | 119 ++++++++++++++++++++++ 5 files changed, 131 insertions(+), 53 deletions(-) delete mode 100644 public/js/icinga/components/configForm.js create mode 100644 public/js/icinga/components/form.js diff --git a/application/forms/Config/LoggingForm.php b/application/forms/Config/LoggingForm.php index 59fc43bfb..e29975fc9 100644 --- a/application/forms/Config/LoggingForm.php +++ b/application/forms/Config/LoggingForm.php @@ -126,7 +126,6 @@ class LoggingForm extends Form if ($this->config === null) { $this->config = new Zend_Config(array()); } - $this->setAttrib('data-icinga-component', 'app/configForm'); $logging = $this->config->logging; if ($logging === null) { $logging = new IcingaConfig(array()); diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index a8b2e4476..dd5c2801b 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -218,6 +218,8 @@ class Form extends Zend_Form } $this->addElementDecorators(); $this->created = true; + $this->setAttrib('data-icinga-component', 'app/form'); + } } @@ -308,7 +310,7 @@ class Form extends Zend_Form foreach ($triggerElements as $elementName) { $element = $this->getElement($elementName); if ($element !== null) { - $element->setAttrib('data-icinga-autosubmit', 'true'); + $element->setAttrib('data-icinga-form-autosubmit', 'true'); } else { throw new ProgrammingError( 'You need to add the element "' . $elementName . '" to' . @@ -350,6 +352,7 @@ class Form extends Zend_Form } } + /** * Check whether this form has been submitted * diff --git a/public/js/icinga/componentLoader.js b/public/js/icinga/componentLoader.js index 7df388f4e..866826be1 100644 --- a/public/js/icinga/componentLoader.js +++ b/public/js/icinga/componentLoader.js @@ -24,7 +24,14 @@ define(['jquery', 'logging', 'icinga/componentRegistry'], function ($, log, regi requirejs( ['modules/' + cmpType], function (Cmp) { - var cmp = new Cmp(target); + var cmp; + try { + cmp = new Cmp(target); + } catch (e) { + log.emergency('Error in component "' + cmpType + '" : "' + e + '"'); + err(e); + return; + } if (fin) { fin(cmp); } diff --git a/public/js/icinga/components/configForm.js b/public/js/icinga/components/configForm.js deleted file mode 100644 index da30cf78c..000000000 --- a/public/js/icinga/components/configForm.js +++ /dev/null @@ -1,50 +0,0 @@ -// {{{ICINGA_LICENSE_HEADER}}} -// {{{ICINGA_LICENSE_HEADER}}} - -define(['jquery'], function($) { - "use strict"; - - var ATTR_MODIFIED = 'data-icinga-form-modified'; - - var isAutoSubmitInput = function(el) { - return $(el).attr('data-icinga-autosubmit') == 'true'; - } - - var getFormObject = function(targetForm) { - var form = $(targetForm); - - form.isModified = function() { - return form.attr(ATTR_MODIFIED) == 'true'; - } - form.setModificationFlag = function() { - form.attr(ATTR_MODIFIED, true); - } - form.clearModificationFlag = function() { - form.attr(ATTR_MODIFIED, false); - } - return form; - } - - var registerChangeDetection = function(form) { - form.change(function(changed) { - if (isAutoSubmitInput(changed.target)) { - form.clearModificationFlag(); - form.submit(); - } else { - form.setModificationFlag(); - } - }); - - form.submit(form.clearModificationFlag); - window.addEventListener('beforeunload', function() { - if (form.isModified()) { - return 'All unsaved changes will be lost when leaving this page'; - } - }) - } - - return function(targetForm) { - var form = getFormObject(targetForm); - registerChangeDetection(form); - } -}); \ No newline at end of file diff --git a/public/js/icinga/components/form.js b/public/js/icinga/components/form.js new file mode 100644 index 000000000..323088061 --- /dev/null +++ b/public/js/icinga/components/form.js @@ -0,0 +1,119 @@ +/*global Icinga:false define:false require:false base_url:false console:false */ +// {{{ICINGA_LICENSE_HEADER}}} +// {{{ICINGA_LICENSE_HEADER}}} + +/** + * Icinga app/form component. + * + * This component makes sure a user has to confirm when trying to discard unsaved changes + * by leaving the current page. It also implements the code for autosubmitting fields having the + * 'data-icinga-form-autosubmit' component. + */ +define(['jquery'], function($) { + "use strict"; + + /** + * The attribute name marking forms as being modified + * + * @type {string} + */ + var ATTR_MODIFIED = 'data-icinga-form-modified'; + + /** + * Return true when the input element is a autosubmit field + * + * @param {string|DOMElement|jQuery} el The element to test for autosubmission + * + * @returns {boolean} True when the element should be automatically submitted + */ + var isAutoSubmitInput = function(el) { + return $(el).attr('data-icinga-form-autosubmit') === 'true' || + $(el).attr('data-icinga-form-autosubmit') === '1'; + }; + + /** + * Takes a form and returns an overloaded jQuery object + * + * The returned object is the jQuery mathcer with the following additional methods: + * + * - isModified : Return true when the form is marked as modified + * - setModificationFlag : Mark this form as being modified + * - clearModificationFlag : Clear the modification mark + * + * @param targetForm + * @returns {JQuery} + */ + var getFormObject = function(targetForm) { + var form = $(targetForm); + /** + * Return true when the form is marked as modified + * + * @returns {boolean} True when the form has the @see ATTR_MODIFIED attribute set to 'true', otherwise false + */ + form.isModified = function() { + return form.attr(ATTR_MODIFIED) === 'true' || + form.attr(ATTR_MODIFIED) === '1'; + }; + + /** + * Mark this form as being modified + */ + form.setModificationFlag = function() { + form.attr(ATTR_MODIFIED, true); + }; + + /** + * Clear the modification flag on this form + */ + form.clearModificationFlag = function() { + form.attr(ATTR_MODIFIED, false); + }; + return form; + }; + + /** + * Register event handler for detecting form modifications. + * + * This handler takes care of autosubmit form fields causing submissions on change and + * makes sure the modification flag on the form is set when changes occur. + * + * @param {jQuery} form A form object returned from @see getFormObject() + */ + var registerFormEventHandler = function(form) { + form.change(function(changed) { + if (isAutoSubmitInput(changed.target)) { + form.clearModificationFlag(); + form.submit(); + } else { + form.setModificationFlag(); + } + + }); + // submissions should clear the modification flag + form.submit(form.clearModificationFlag); + }; + + /** + * Register an eventhandler that triggers a confirmation message when the user tries to leave a modified form + * + * @param {jQuery} form A form object returned from @see getFormObject() + */ + var registerLeaveConfirmationHandler = function(form) { + + $(window).bind('beforeunload', function() { + if (form.isModified()) { + return 'All unsaved changes will be lost when leaving this page'; + } + }); + }; + + + /** + * The component bootstrap + */ + return function(targetForm) { + var form = getFormObject(targetForm); + registerFormEventHandler(form); + registerLeaveConfirmationHandler(form); + }; +}); \ No newline at end of file