mirror of
https://github.com/twbs/bootstrap.git
synced 2025-02-19 16:54:24 +01:00
Implement data-dismiss="toast"
to allow user to interact itself with the component (#27155)
This commit is contained in:
parent
2f81ab007c
commit
4cac833447
@ -22,10 +22,11 @@ const Toast = (($) => {
|
||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||
|
||||
const Event = {
|
||||
HIDE : `hide${EVENT_KEY}`,
|
||||
HIDDEN : `hidden${EVENT_KEY}`,
|
||||
SHOW : `show${EVENT_KEY}`,
|
||||
SHOWN : `shown${EVENT_KEY}`
|
||||
CLICK_DISMISS : `click.dismiss${EVENT_KEY}`,
|
||||
HIDE : `hide${EVENT_KEY}`,
|
||||
HIDDEN : `hidden${EVENT_KEY}`,
|
||||
SHOW : `show${EVENT_KEY}`,
|
||||
SHOWN : `shown${EVENT_KEY}`
|
||||
}
|
||||
|
||||
const ClassName = {
|
||||
@ -49,6 +50,10 @@ const Toast = (($) => {
|
||||
}
|
||||
}
|
||||
|
||||
const Selector = {
|
||||
DATA_DISMISS : '[data-dismiss="toast"]'
|
||||
}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Class Definition
|
||||
@ -60,6 +65,7 @@ const Toast = (($) => {
|
||||
this._element = element
|
||||
this._config = this._getConfig(config)
|
||||
this._timeout = null
|
||||
this._setListeners()
|
||||
}
|
||||
|
||||
// Getters
|
||||
@ -104,30 +110,20 @@ const Toast = (($) => {
|
||||
}, this._config.delay.show)
|
||||
}
|
||||
|
||||
hide() {
|
||||
hide(withoutTimeout) {
|
||||
if (!this._element.classList.contains(ClassName.SHOW)) {
|
||||
return
|
||||
}
|
||||
|
||||
$(this._element).trigger(Event.HIDE)
|
||||
|
||||
const complete = () => {
|
||||
$(this._element).trigger(Event.HIDDEN)
|
||||
if (withoutTimeout) {
|
||||
this._close()
|
||||
} else {
|
||||
this._timeout = setTimeout(() => {
|
||||
this._close()
|
||||
}, this._config.delay.hide)
|
||||
}
|
||||
|
||||
this._timeout = setTimeout(() => {
|
||||
this._element.classList.remove(ClassName.SHOW)
|
||||
|
||||
if (this._config.animation) {
|
||||
const transitionDuration = Util.getTransitionDurationFromElement(this._element)
|
||||
|
||||
$(this._element)
|
||||
.one(Util.TRANSITION_END, complete)
|
||||
.emulateTransitionEnd(transitionDuration)
|
||||
} else {
|
||||
complete()
|
||||
}
|
||||
}, this._config.delay.hide)
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@ -138,6 +134,8 @@ const Toast = (($) => {
|
||||
this._element.classList.remove(ClassName.SHOW)
|
||||
}
|
||||
|
||||
$(this._element).off(Event.CLICK_DISMISS)
|
||||
|
||||
$.removeData(this._element, DATA_KEY)
|
||||
this._element = null
|
||||
this._config = null
|
||||
@ -168,6 +166,32 @@ const Toast = (($) => {
|
||||
return config
|
||||
}
|
||||
|
||||
_setListeners() {
|
||||
$(this._element).on(
|
||||
Event.CLICK_DISMISS,
|
||||
Selector.DATA_DISMISS,
|
||||
() => this.hide(true)
|
||||
)
|
||||
}
|
||||
|
||||
_close() {
|
||||
const complete = () => {
|
||||
$(this._element).trigger(Event.HIDDEN)
|
||||
}
|
||||
|
||||
this._element.classList.remove(ClassName.SHOW)
|
||||
|
||||
if (this._config.animation) {
|
||||
const transitionDuration = Util.getTransitionDurationFromElement(this._element)
|
||||
|
||||
$(this._element)
|
||||
.one(Util.TRANSITION_END, complete)
|
||||
.emulateTransitionEnd(transitionDuration)
|
||||
} else {
|
||||
complete()
|
||||
}
|
||||
}
|
||||
|
||||
// Static
|
||||
|
||||
static _jQueryInterface(config) {
|
||||
|
@ -232,4 +232,33 @@ $(function () {
|
||||
})
|
||||
.bootstrapToast('show')
|
||||
})
|
||||
|
||||
|
||||
QUnit.test('should close toast when close element with data-dismiss attribute is set', function (assert) {
|
||||
assert.expect(2)
|
||||
var done = assert.async()
|
||||
|
||||
var toastHtml =
|
||||
'<div class="toast" data-delay="1" data-autohide="false" data-animation="false">' +
|
||||
'<button type="button" class="ml-2 mb-1 close" data-dismiss="toast">' +
|
||||
'close' +
|
||||
'</button>' +
|
||||
'</div>'
|
||||
|
||||
var $toast = $(toastHtml)
|
||||
.bootstrapToast()
|
||||
.appendTo($('#qunit-fixture'))
|
||||
|
||||
$toast
|
||||
.on('shown.bs.toast', function () {
|
||||
assert.strictEqual($toast.hasClass('show'), true)
|
||||
var button = $toast.find('.close')
|
||||
button.trigger('click')
|
||||
})
|
||||
.on('hidden.bs.toast', function () {
|
||||
assert.strictEqual($toast.hasClass('show'), false)
|
||||
done()
|
||||
})
|
||||
.bootstrapToast('show')
|
||||
})
|
||||
})
|
||||
|
@ -26,22 +26,28 @@
|
||||
</div>
|
||||
|
||||
<div class="notifications">
|
||||
<div id="toastAutoHide" class="toast">
|
||||
<div id="toastAutoHide" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header">
|
||||
<img class="rounded mr-2" data-src="holder.js/20x20?size=1&text=.&bg=#007aff" alt="">
|
||||
<strong class="mr-auto">Bootstrap</strong>
|
||||
<small>11 mins ago</small>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Hello, world! This is a toast message with <strong>autohide</strong> in 2 seconds
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" data-autohide="false">
|
||||
<div class="toast" data-autohide="false" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header">
|
||||
<img class="rounded mr-2" data-src="holder.js/20x20?size=1&text=.&bg=#007aff" alt="">
|
||||
<strong class="mr-auto">Bootstrap</strong>
|
||||
<small class="text-muted">2 seconds ago</small>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Heads up, toasts will stack automatically
|
||||
|
@ -24,11 +24,14 @@ A basic toast can include a header (though it doesn't strictly need one) with wh
|
||||
|
||||
<div class="bg-light">
|
||||
{% capture example %}
|
||||
<div class="toast">
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header">
|
||||
<img class="rounded mr-2" data-src="holder.js/20x20?size=1&text=.&bg=#007aff" alt="">
|
||||
<strong class="mr-auto">Bootstrap</strong>
|
||||
<small>11 mins ago</small>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Hello, world! This is a toast message.
|
||||
@ -42,11 +45,14 @@ They're slightly translucent, too, so they blend over whatever they might appear
|
||||
|
||||
<div class="bg-dark">
|
||||
{% capture example %}
|
||||
<div class="toast">
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header">
|
||||
<img class="rounded mr-2" data-src="holder.js/20x20?size=1&text=.&bg=#007aff" alt="">
|
||||
<strong class="mr-auto">Bootstrap</strong>
|
||||
<small class="text-muted">11 mins ago</small>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Hello, world! This is a toast message.
|
||||
@ -60,22 +66,28 @@ Plus, they'll easily stack.
|
||||
|
||||
<div class="bg-light">
|
||||
{% capture example %}
|
||||
<div class="toast">
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header">
|
||||
<img class="rounded mr-2" data-src="holder.js/20x20?size=1&text=.&bg=#007aff" alt="">
|
||||
<strong class="mr-auto">Bootstrap</strong>
|
||||
<small class="text-muted">just now</small>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
See? Just like this.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast">
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header">
|
||||
<img class="rounded mr-2" data-src="holder.js/20x20?size=1&text=.&bg=#007aff" alt="">
|
||||
<strong class="mr-auto">Bootstrap</strong>
|
||||
<small class="text-muted">2 seconds ago</small>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Heads up, toasts will stack automatically
|
||||
@ -88,10 +100,12 @@ Plus, they'll easily stack.
|
||||
## Accessibility
|
||||
|
||||
Toasts are intended to be small interruptions to your visitors or users, so to help those on screen readers, you should wrap your toasts in an [`aria-live` region](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions). This allows screen readers the ability to see suggested interruptions without any visual cues.
|
||||
To improve accessibility level, we strongly recomend to use `autohide: false` and add a `close` button into the header to let user dismiss that element.
|
||||
You also need to adapt the `role` and `aria-live` level depending on the content. If it's an important message like error, use an `alert` role `assertive` otherwise use a role `status` with a `polite` level.
|
||||
|
||||
{% highlight html %}
|
||||
<div role="region" aria-live="polite">
|
||||
<div class="toast">...</div>
|
||||
<div role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div role="alert" aria-live="assertive" aria-atomic="true">...</div>
|
||||
</div>
|
||||
{% endhighlight %}
|
||||
|
||||
@ -107,6 +121,9 @@ Place toasts with custom CSS as you need them. The top right is often used for n
|
||||
<img class="rounded mr-2" data-src="holder.js/20x20?size=1&text=.&bg=#007aff" alt="">
|
||||
<strong class="mr-auto">Bootstrap</strong>
|
||||
<small>11 mins ago</small>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Hello, world! This is a toast message.
|
||||
@ -126,22 +143,28 @@ For systems that generate more notifications, consider using a wrapping element
|
||||
<div style="position: absolute; top: 0; right: 0;">
|
||||
|
||||
<!-- Then put toasts within -->
|
||||
<div class="toast">
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header">
|
||||
<img class="rounded mr-2" data-src="holder.js/20x20?size=1&text=.&bg=#007aff" alt="">
|
||||
<strong class="mr-auto">Bootstrap</strong>
|
||||
<small class="text-muted">just now</small>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
See? Just like this.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast">
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header">
|
||||
<img class="rounded mr-2" data-src="holder.js/20x20?size=1&text=.&bg=#007aff" alt="">
|
||||
<strong class="mr-auto">Bootstrap</strong>
|
||||
<small class="text-muted">2 seconds ago</small>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Heads up, toasts will stack automatically
|
||||
@ -162,11 +185,14 @@ You can also get fancy with flexbox utilities.
|
||||
<div class="d-flex justify-content-center" style="position: absolute; top: 0; right: 0; left: 0;">
|
||||
|
||||
<!-- Then put toasts within -->
|
||||
<div class="toast">
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header">
|
||||
<img class="rounded mr-2" data-src="holder.js/20x20?size=1&text=.&bg=#007aff" alt="">
|
||||
<strong class="mr-auto">Bootstrap</strong>
|
||||
<small>11 mins ago</small>
|
||||
<button type="button" class="close" data-dismiss="toast" aria-label="Close" style="">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Hello, world! This is a toast message.
|
||||
|
Loading…
x
Reference in New Issue
Block a user