From 0066eb8b4277ec06751e5f09bb11d08990799d1e Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Thu, 30 Jan 2025 16:01:36 +0100 Subject: [PATCH 1/2] Modal.js: Prevent unnecessarily `onKeyDown` call --- public/js/icinga/behavior/modal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/icinga/behavior/modal.js b/public/js/icinga/behavior/modal.js index 0c675f11c1..f0eb27d677 100644 --- a/public/js/icinga/behavior/modal.js +++ b/public/js/icinga/behavior/modal.js @@ -25,7 +25,7 @@ this.on('click', '[data-icinga-modal][href]', this.onModalToggleClick, this); this.on('mousedown', '#layout > #modal', this.onModalLeave, this); this.on('click', '.modal-header > button', this.onModalClose, this); - this.on('keydown', this.onKeyDown, this); + this.on('keydown', '#layout > #modal.active', this.onKeyDown, this); }; Modal.prototype = new Icinga.EventListener(); From bec33235f199cfd511d2c3a99600b02a70b985bd Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 3 Feb 2025 10:02:45 +0100 Subject: [PATCH 2/2] modal.js: Prevent unintentional closing of a modal Don't close modal if it contains changes and: - `ESCAPE` is pressed - User click on the overlay --- public/js/icinga/behavior/modal.js | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/public/js/icinga/behavior/modal.js b/public/js/icinga/behavior/modal.js index f0eb27d677..b3bd1588f7 100644 --- a/public/js/icinga/behavior/modal.js +++ b/public/js/icinga/behavior/modal.js @@ -18,6 +18,7 @@ this.icinga = icinga; this.$layout = $('#layout'); this.$ghost = $('#modal-ghost'); + this.hasChanges = false; this.on('submit', '#modal form', this.onFormSubmit, this); this.on('change', '#modal form select.autosubmit', this.onFormAutoSubmit, this); @@ -26,6 +27,7 @@ this.on('mousedown', '#layout > #modal', this.onModalLeave, this); this.on('click', '.modal-header > button', this.onModalClose, this); this.on('keydown', '#layout > #modal.active', this.onKeyDown, this); + this.on('change', '#modal form', this.OnChange, this); }; Modal.prototype = new Icinga.EventListener(); @@ -180,7 +182,7 @@ var _this = event.data.self; var $target = $(event.target); - if ($target.is('#modal')) { + if (! _this.hasChanges && $target.is('#modal')) { _this.hide($target); } }; @@ -202,9 +204,21 @@ * @param event {Event} The `keydown` event triggered by pushing a key */ Modal.prototype.onKeyDown = function(event) { + if (event.key !== 'Escape') { + return; + } + var _this = event.data.self; - if (! event.isDefaultPrevented() && event.key === 'Escape') { + if (_this.hasChanges || document.activeElement.matches('form :scope')) { + if (! _this.hasChanges) { + document.activeElement.blur(); + } + + return; + } + + if (! event.isDefaultPrevented()) { let $modal = _this.$layout.children('#modal'); if ($modal.length) { _this.hide($modal); @@ -212,6 +226,17 @@ } }; + /** + * Event handler to register whether the modal form has new changes after opening. + * + * This prevents the modal from being unintentionally closed + * + * @param event {Event} The `OnChange` event + */ + Modal.prototype.OnChange = function(event) { + event.data.self.hasChanges = true; + } + /** * Make final preparations and add the modal to the DOM * @@ -249,6 +274,7 @@ // Remove pointerEvent none style to make the button clickable again this.modalOpener.style.pointerEvents = ''; this.modalOpener = null; + this.hasChanges = false; $modal.removeClass('active'); // Using `setTimeout` here to let the transition finish