Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/bootstrap.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohann-S <johann.servoire@gmail.com>2019-10-28 17:28:11 +0300
committerXhmikosR <xhmikosr@gmail.com>2019-11-02 11:02:07 +0300
commitdd96b832f787e91db03ebc687a934deea335bed5 (patch)
treed559dd6c2bee13b13db7efbcea9692d7f1c1ad3f
parent29f585365fe71a74958d56beac98ab4b7e27a6b1 (diff)
backport #29516: added animation when modal backdrop is static
-rw-r--r--js/src/modal.js37
-rw-r--r--js/tests/unit/modal.js22
-rw-r--r--scss/_modal.scss5
-rw-r--r--scss/_variables.scss1
-rw-r--r--site/docs/4.3/components/modal.md65
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 = $('<div class="modal" data-backdrop="static"><div class="modal-dialog" /></div>').appendTo('#qunit-fixture')
+
+ $modal.on('shown.bs.modal', function () {
+ $modal.trigger('click')
+ setTimeout(function () {
+ var modal = $modal.data('bs.modal')
+
+ assert.strictEqual(modal._isShown, true)
+ done()
+ }, 10)
+ })
+ .on('hidden.bs.modal', function () {
+ assert.strictEqual(true, false, 'should not hide the modal')
+ })
+ .bootstrapModal({
+ backdrop: 'static'
+ })
+ })
})
diff --git a/scss/_modal.scss b/scss/_modal.scss
index 9a036883a0..9053c173f8 100644
--- a/scss/_modal.scss
+++ b/scss/_modal.scss
@@ -48,6 +48,11 @@
.modal.show & {
transform: $modal-show-transform;
}
+
+ // When trying to close, animate focus to scale
+ .modal.modal-static & {
+ transform: $modal-scale-transform;
+ }
}
.modal-dialog-scrollable {
diff --git a/scss/_variables.scss b/scss/_variables.scss
index cc4e0ad5e4..28db6f9943 100644
--- a/scss/_variables.scss
+++ b/scss/_variables.scss
@@ -976,6 +976,7 @@ $modal-sm: 300px !default;
$modal-fade-transform: translate(0, -50px) !default;
$modal-show-transform: none !default;
$modal-transition: transform .3s ease-out !default;
+$modal-scale-transform: scale(1.02) !default;
// Alerts
diff --git a/site/docs/4.3/components/modal.md b/site/docs/4.3/components/modal.md
index b2a7fc6a39..f74253df09 100644
--- a/site/docs/4.3/components/modal.md
+++ b/site/docs/4.3/components/modal.md
@@ -135,6 +135,65 @@ Toggle a working modal demo by clicking the button below. It will slide down and
</div>
{% 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.
+
+<div id="staticBackdropLive" class="modal fade" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="staticBackdropLiveLabel" aria-hidden="true">
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h5 class="modal-title" id="staticBackdropLiveLabel">Modal title</h5>
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <p>I will not close if you click outside me. Don't even try to press escape key.</p>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+ <button type="button" class="btn btn-primary">Understood</button>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class="bd-example">
+ <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#staticBackdropLive">
+ Launch static backdrop modal
+ </button>
+</div>
+
+{% highlight html %}
+<!-- Button trigger modal -->
+<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#staticBackdrop">
+ Launch static backdrop modal
+</button>
+
+<!-- Modal -->
+<div class="modal fade" id="staticBackdrop" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="staticBackdropLabel" aria-hidden="true">
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h5 class="modal-title" id="staticBackdropLabel">Modal title</h5>
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ ...
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+ <button type="button" class="btn btn-primary">Understood</button>
+ </div>
+ </div>
+ </div>
+</div>
+{% 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
<td>backdrop</td>
<td>boolean or the string <code>'static'</code></td>
<td>true</td>
- <td>Includes a modal-backdrop element. Alternatively, specify <code>static</code> for a backdrop which doesn't close the modal on click.</td>
+ <td>Includes a modal-backdrop element. Alternatively, specify <code>static</code> for a backdrop which doesn't close the modal on click or on escape key press.</td>
</tr>
<tr>
<td>keyboard</td>
@@ -836,6 +895,10 @@ Bootstrap's modal class exposes a few events for hooking into modal functionalit
<td>hidden.bs.modal</td>
<td>This event is fired when the modal has finished being hidden from the user (will wait for CSS transitions to complete).</td>
</tr>
+ <tr>
+ <td>hidePrevented.bs.modal</td>
+ <td>This event is fired when the modal is shown, its backdrop is <code>static</code> and a click outside the modal or a scape key press is performed.</td>
+ </tr>
</tbody>
</table>