backport #29516: added animation when modal backdrop is static

This commit is contained in:
Johann-S 2019-10-28 16:28:11 +02:00 committed by XhmikosR
parent 29f585365f
commit dd96b832f7
5 changed files with 121 additions and 9 deletions

View File

@ -38,6 +38,7 @@ const DefaultType = {
const Event = { const Event = {
HIDE : `hide${EVENT_KEY}`, HIDE : `hide${EVENT_KEY}`,
HIDE_PREVENTED : `hidePrevented${EVENT_KEY}`,
HIDDEN : `hidden${EVENT_KEY}`, HIDDEN : `hidden${EVENT_KEY}`,
SHOW : `show${EVENT_KEY}`, SHOW : `show${EVENT_KEY}`,
SHOWN : `shown${EVENT_KEY}`, SHOWN : `shown${EVENT_KEY}`,
@ -56,7 +57,8 @@ const ClassName = {
BACKDROP : 'modal-backdrop', BACKDROP : 'modal-backdrop',
OPEN : 'modal-open', OPEN : 'modal-open',
FADE : 'fade', FADE : 'fade',
SHOW : 'show' SHOW : 'show',
STATIC : 'modal-static'
} }
const Selector = { const Selector = {
@ -234,6 +236,29 @@ class Modal {
return config 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) { _showElement(relatedTarget) {
const transition = $(this._element).hasClass(ClassName.FADE) const transition = $(this._element).hasClass(ClassName.FADE)
const modalBody = this._dialog ? this._dialog.querySelector(Selector.MODAL_BODY) : null const modalBody = this._dialog ? this._dialog.querySelector(Selector.MODAL_BODY) : null
@ -303,8 +328,7 @@ class Modal {
if (this._isShown && this._config.keyboard) { if (this._isShown && this._config.keyboard) {
$(this._element).on(Event.KEYDOWN_DISMISS, (event) => { $(this._element).on(Event.KEYDOWN_DISMISS, (event) => {
if (event.which === ESCAPE_KEYCODE) { if (event.which === ESCAPE_KEYCODE) {
event.preventDefault() this._triggerBackdropTransition()
this.hide()
} }
}) })
} else if (!this._isShown) { } else if (!this._isShown) {
@ -362,11 +386,8 @@ class Modal {
if (event.target !== event.currentTarget) { if (event.target !== event.currentTarget) {
return return
} }
if (this._config.backdrop === 'static') {
this._element.focus() this._triggerBackdropTransition()
} else {
this.hide()
}
}) })
if (animate) { if (animate) {

View File

@ -833,4 +833,26 @@ $(function () {
}) })
.bootstrapModal('show') .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'
})
})
}) })

View File

@ -48,6 +48,11 @@
.modal.show & { .modal.show & {
transform: $modal-show-transform; transform: $modal-show-transform;
} }
// When trying to close, animate focus to scale
.modal.modal-static & {
transform: $modal-scale-transform;
}
} }
.modal-dialog-scrollable { .modal-dialog-scrollable {

View File

@ -976,6 +976,7 @@ $modal-sm: 300px !default;
$modal-fade-transform: translate(0, -50px) !default; $modal-fade-transform: translate(0, -50px) !default;
$modal-show-transform: none !default; $modal-show-transform: none !default;
$modal-transition: transform .3s ease-out !default; $modal-transition: transform .3s ease-out !default;
$modal-scale-transform: scale(1.02) !default;
// Alerts // Alerts

View File

@ -135,6 +135,65 @@ Toggle a working modal demo by clicking the button below. It will slide down and
</div> </div>
{% endhighlight %} {% 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 ### 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. 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>backdrop</td>
<td>boolean or the string <code>'static'</code></td> <td>boolean or the string <code>'static'</code></td>
<td>true</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>
<tr> <tr>
<td>keyboard</td> <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>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> <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>
<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> </tbody>
</table> </table>