From dd96b832f787e91db03ebc687a934deea335bed5 Mon Sep 17 00:00:00 2001 From: Johann-S Date: Mon, 28 Oct 2019 16:28:11 +0200 Subject: [PATCH] backport #29516: added animation when modal backdrop is static --- js/src/modal.js | 37 ++++++++++++++---- js/tests/unit/modal.js | 22 +++++++++++ scss/_modal.scss | 5 +++ scss/_variables.scss | 1 + site/docs/4.3/components/modal.md | 65 ++++++++++++++++++++++++++++++- 5 files changed, 121 insertions(+), 9 deletions(-) diff --git a/js/src/modal.js b/js/src/modal.js index d6abfdec87..24b0425713 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -38,6 +38,7 @@ const DefaultType = { const Event = { HIDE : `hide${EVENT_KEY}`, + HIDE_PREVENTED : `hidePrevented${EVENT_KEY}`, HIDDEN : `hidden${EVENT_KEY}`, SHOW : `show${EVENT_KEY}`, SHOWN : `shown${EVENT_KEY}`, @@ -56,7 +57,8 @@ const ClassName = { BACKDROP : 'modal-backdrop', OPEN : 'modal-open', FADE : 'fade', - SHOW : 'show' + SHOW : 'show', + STATIC : 'modal-static' } const Selector = { @@ -234,6 +236,29 @@ class Modal { return config } + _triggerBackdropTransition() { + if (this._config.backdrop === 'static') { + const hideEventPrevented = $.Event(Event.HIDE_PREVENTED) + + $(this._element).trigger(hideEventPrevented) + if (hideEventPrevented.defaultPrevented) { + return + } + + this._element.classList.add(ClassName.STATIC) + + const modalTransitionDuration = Util.getTransitionDurationFromElement(this._element) + + $(this._element).one(Util.TRANSITION_END, () => { + this._element.classList.remove(ClassName.STATIC) + }) + .emulateTransitionEnd(modalTransitionDuration) + this._element.focus() + } else { + this.hide() + } + } + _showElement(relatedTarget) { const transition = $(this._element).hasClass(ClassName.FADE) const modalBody = this._dialog ? this._dialog.querySelector(Selector.MODAL_BODY) : null @@ -303,8 +328,7 @@ class Modal { if (this._isShown && this._config.keyboard) { $(this._element).on(Event.KEYDOWN_DISMISS, (event) => { if (event.which === ESCAPE_KEYCODE) { - event.preventDefault() - this.hide() + this._triggerBackdropTransition() } }) } else if (!this._isShown) { @@ -362,11 +386,8 @@ class Modal { if (event.target !== event.currentTarget) { return } - if (this._config.backdrop === 'static') { - this._element.focus() - } else { - this.hide() - } + + this._triggerBackdropTransition() }) if (animate) { diff --git a/js/tests/unit/modal.js b/js/tests/unit/modal.js index d22d8a1de7..b1ddc8512f 100644 --- a/js/tests/unit/modal.js +++ b/js/tests/unit/modal.js @@ -833,4 +833,26 @@ $(function () { }) .bootstrapModal('show') }) + + QUnit.test('should not close modal when clicking outside of modal-content if backdrop = static', function (assert) { + assert.expect(1) + var done = assert.async() + var $modal = $(' {% endhighlight %} +### Static backdrop + +When backdrop is set to static, the modal will not close when clicking outside it. Click the button below to try it. + + + +
+ +
+ +{% highlight html %} + + + + + +{% endhighlight %} + + ### Scrolling long content When modals become too long for the user's viewport or device, they scroll independent of the page itself. Try the demo below to see what we mean. @@ -743,7 +802,7 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap backdrop boolean or the string 'static' true - Includes a modal-backdrop element. Alternatively, specify static for a backdrop which doesn't close the modal on click. + Includes a modal-backdrop element. Alternatively, specify static for a backdrop which doesn't close the modal on click or on escape key press. keyboard @@ -836,6 +895,10 @@ Bootstrap's modal class exposes a few events for hooking into modal functionalit hidden.bs.modal This event is fired when the modal has finished being hidden from the user (will wait for CSS transitions to complete). + + hidePrevented.bs.modal + This event is fired when the modal is shown, its backdrop is static and a click outside the modal or a scape key press is performed. +