diff --git a/public/scripts/popup.js b/public/scripts/popup.js index 4ece1b468..ccc2c9f54 100644 --- a/public/scripts/popup.js +++ b/public/scripts/popup.js @@ -334,10 +334,21 @@ export class Popup { evt.preventDefault(); evt.stopPropagation(); await this.complete(POPUP_RESULT.CANCELLED); - window.removeEventListener('cancel', cancelListenerBound); }; - const cancelListenerBound = cancelListener.bind(this); - this.dlg.addEventListener('cancel', cancelListenerBound); + this.dlg.addEventListener('cancel', cancelListener.bind(this)); + + // Don't ask me why this is needed. I don't get it. But we have to keep it. + // We make sure that the modal on it's own doesn't hide. Dunno why, if onClosing is triggered multiple times through the cancel event, and stopped + // It seems to just call 'close' on the dialog even if the 'cancel' event was prevented. + // Here, we just say that close should not happen if the dalog has no result. + const closeListener = async (evt) => { + if (this.result === undefined) { + evt.preventDefault(); + evt.stopPropagation(); + this.dlg.showModal(); + } + }; + this.dlg.addEventListener('close', closeListener.bind(this)); const keyListener = async (evt) => { switch (evt.key) { @@ -366,16 +377,16 @@ export class Popup { evt.preventDefault(); evt.stopPropagation(); const result = Number(document.activeElement.getAttribute('data-result') ?? this.defaultResult); + + // Call complete on the popup. Make sure that we handle `onClosing` cancels correctly and don't remove the listener then. await this.complete(result); - window.removeEventListener('keydown', keyListenerBound); break; } } }; - const keyListenerBound = keyListener.bind(this); - this.dlg.addEventListener('keydown', keyListenerBound); + this.dlg.addEventListener('keydown', keyListener.bind(this)); } /** @@ -445,9 +456,11 @@ export class Popup { * - popup with `POPUP_TYPE.INPUT` will return the input value - or `false` on negative and `null` on cancelled * - All other will return the result value as provided as `POPUP_RESULT` or a custom number value * + * IMPORTANT: If the popup closing was cancelled via the `onClosing` handler, the return value will be `Promise`. + * * @param {POPUP_RESULT|number} result - The result of the popup (either an existing `POPUP_RESULT` or a custom result value) * - * @returns {Promise} A promise that resolves with the value of the popup when it is completed. + * @returns {Promise} A promise that resolves with the value of the popup when it is completed. Returns `undefined` if the closing action was cancelled. */ async complete(result) { // In all cases besides INPUT the popup value should be the result @@ -481,7 +494,13 @@ export class Popup { if (this.onClosing) { const shouldClose = this.onClosing(this); - if (!shouldClose) return; + if (!shouldClose) { + // Set values back if we cancel out of closing the popup + this.value = undefined; + this.result = undefined; + this.inputResults = undefined; + return undefined; + } } Popup.util.lastResult = { value, result, inputResults: this.inputResults };