From 65a84d58a99c75540d77cef21d59f578fa3d0f19 Mon Sep 17 00:00:00 2001 From: Cyril Fluck Date: Wed, 3 Jan 2024 11:24:05 -0800 Subject: [PATCH] Clicking rapidly does not automatically closes the modal If a user double clicks to open the modal, the second click gets otherwise captured by the overlay and the modal gets closed even before being visible to the user. --- addon/components/basic-dialog.js | 27 +++++--------- addon/components/overlay.js | 36 +++++++++++++++++++ addon/templates/components/basic-dialog.hbs | 17 ++++----- addon/templates/components/liquid-dialog.hbs | 17 ++++----- .../components/liquid-tether-dialog.hbs | 9 ++--- addon/templates/components/overlay.hbs | 10 ++++++ addon/templates/components/tether-dialog.hbs | 9 ++--- addon/utils/config-utils.js | 12 +++++++ app/components/ember-modal-dialog/overlay.js | 1 + package.json | 5 +-- tests/helpers/modal-asserts.js | 1 + yarn.lock | 25 ++++++++----- 12 files changed, 106 insertions(+), 63 deletions(-) create mode 100644 addon/components/overlay.js create mode 100644 addon/templates/components/overlay.hbs create mode 100644 app/components/ember-modal-dialog/overlay.js diff --git a/addon/components/basic-dialog.js b/addon/components/basic-dialog.js index af975aec..27c338a6 100644 --- a/addon/components/basic-dialog.js +++ b/addon/components/basic-dialog.js @@ -5,6 +5,7 @@ import Component from '@ember/component'; import { isEmpty } from '@ember/utils'; import layout from '../templates/components/basic-dialog'; import { dasherize } from '@ember/string'; +import { isIOS, clickHandlerDelay } from '../utils/config-utils'; @tagName('') @templateLayout(layout) @@ -107,7 +108,6 @@ export default class BasicDialog extends Component { if (!this.clickOutsideToClose) { return; } - this.makeOverlayClickableOnIOS(); this.handleClick = ({ target }) => { // if the click has already resulted in the target @@ -135,39 +135,28 @@ export default class BasicDialog extends Component { } }; + const registerDelay = clickHandlerDelay(this); + const registerClick = () => document.addEventListener('click', this.handleClick); // setTimeout needed or else the click handler will catch the click that spawned this modal dialog - setTimeout(registerClick); + setTimeout(registerClick, registerDelay); - if (this.isIOS) { + if (isIOS) { const registerTouch = () => document.addEventListener('touchend', this.handleClick); - setTimeout(registerTouch); + setTimeout(registerTouch, registerDelay); } super.didInsertElement(...arguments); } willDestroyElement() { document.removeEventListener('click', this.handleClick); - if (this.isIOS) { + if (isIOS) { document.removeEventListener('touchend', this.handleClick); } - super.willDestroyElement(...arguments); - } - - @computed - get isIOS() { - return /iPad|iPhone|iPod/.test(navigator.userAgent); - } - makeOverlayClickableOnIOS() { - if (this.isIOS) { - let overlayEl = document.querySelector('div[data-emd-overlay]'); - if (overlayEl) { - overlayEl.style.cursor = 'pointer'; - } - } + super.willDestroyElement(...arguments); } } diff --git a/addon/components/overlay.js b/addon/components/overlay.js new file mode 100644 index 00000000..c68a23e0 --- /dev/null +++ b/addon/components/overlay.js @@ -0,0 +1,36 @@ +import Component from '@ember/component'; +import { action } from '@ember/object'; +import { tagName, layout as templateLayout } from '@ember-decorators/component'; +import { isIOS, clickHandlerDelay } from '../utils/config-utils'; +import layout from '../templates/components/overlay'; + +@tagName('') +@templateLayout(layout) +export default class OverlayComponent extends Component { + @action + _onClickOverlay(event) { + let { onClickOverlay } = this; + if (onClickOverlay) { + onClickOverlay(event); + } + } + + @action + didInsert(element) { + const registerClick = () => { + element.addEventListener('click', this._onClickOverlay); + }; + + // setTimeout needed or else the click handler will catch the click that spawned this modal dialog + setTimeout(registerClick, clickHandlerDelay(this)); + + if (isIOS) { + element.style.cursor = 'pointer'; + } + } + + @action + willDestroyNode(element) { + element.removeEventListener('click', this._onClickOverlay); + } +} diff --git a/addon/templates/components/basic-dialog.hbs b/addon/templates/components/basic-dialog.hbs index 8ecce15b..8c2fa2a5 100644 --- a/addon/templates/components/basic-dialog.hbs +++ b/addon/templates/components/basic-dialog.hbs @@ -2,13 +2,10 @@ {{#if this.isOverlaySibling}}
{{#if this.hasOverlay}} -
-
+ @onClickOverlay={{this.onClickOverlay}} + /> {{/if}} {{#if this.hasOverlay}} -
{{yield}} -
+ {{else}}
{{#if this.hasOverlay}} -
-
+ @onClickOverlay={{this.onClickOverlay}} + /> {{/if}}
{{yield}} @@ -36,16 +33,14 @@ }} > {{#if this.hasOverlay}} -
{{yield}}
-
+ {{else}}
{{yield}} diff --git a/addon/templates/components/liquid-tether-dialog.hbs b/addon/templates/components/liquid-tether-dialog.hbs index a21260eb..c06fee4f 100644 --- a/addon/templates/components/liquid-tether-dialog.hbs +++ b/addon/templates/components/liquid-tether-dialog.hbs @@ -1,12 +1,9 @@ {{#if this.hasOverlay}} -
-
+ @onClickOverlay={{this.onClickOverlay}} + />
{{/if}} + {{yield}} +
\ No newline at end of file diff --git a/addon/templates/components/tether-dialog.hbs b/addon/templates/components/tether-dialog.hbs index 23bc7f01..d07aaad4 100644 --- a/addon/templates/components/tether-dialog.hbs +++ b/addon/templates/components/tether-dialog.hbs @@ -1,12 +1,9 @@ {{#if this.hasOverlay}} -
-
+ @onClickOverlay={{this.onClickOverlay}} + />
{{/if}}