mirror of https://github.com/twbs/bootstrap.git
[V4] Throw error when a plugin is in transition (#17823)
* Throw error when a plugin is in transition * Add unit tests about plugins in transition
This commit is contained in:
parent
1fb6d8c46a
commit
297c47c3fd
|
@ -116,9 +116,10 @@ const Carousel = (($) => {
|
||||||
// public
|
// public
|
||||||
|
|
||||||
next() {
|
next() {
|
||||||
if (!this._isSliding) {
|
if (this._isSliding) {
|
||||||
this._slide(Direction.NEXT)
|
throw new Error('Carousel is sliding')
|
||||||
}
|
}
|
||||||
|
this._slide(Direction.NEXT)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextWhenVisible() {
|
nextWhenVisible() {
|
||||||
|
@ -129,9 +130,10 @@ const Carousel = (($) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
prev() {
|
prev() {
|
||||||
if (!this._isSliding) {
|
if (this._isSliding) {
|
||||||
this._slide(Direction.PREVIOUS)
|
throw new Error('Carousel is sliding')
|
||||||
}
|
}
|
||||||
|
this._slide(Direction.PREVIOUS)
|
||||||
}
|
}
|
||||||
|
|
||||||
pause(event) {
|
pause(event) {
|
||||||
|
|
|
@ -112,8 +112,11 @@ const Collapse = (($) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
show() {
|
show() {
|
||||||
if (this._isTransitioning ||
|
if (this._isTransitioning) {
|
||||||
$(this._element).hasClass(ClassName.ACTIVE)) {
|
throw new Error('Collapse is transitioning')
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($(this._element).hasClass(ClassName.ACTIVE)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,8 +196,11 @@ const Collapse = (($) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
hide() {
|
hide() {
|
||||||
if (this._isTransitioning ||
|
if (this._isTransitioning) {
|
||||||
!$(this._element).hasClass(ClassName.ACTIVE)) {
|
throw new Error('Collapse is transitioning')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$(this._element).hasClass(ClassName.ACTIVE)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,7 @@ const Modal = (($) => {
|
||||||
this._isShown = false
|
this._isShown = false
|
||||||
this._isBodyOverflowing = false
|
this._isBodyOverflowing = false
|
||||||
this._ignoreBackdropClick = false
|
this._ignoreBackdropClick = false
|
||||||
|
this._isTransitioning = false
|
||||||
this._originalBodyPadding = 0
|
this._originalBodyPadding = 0
|
||||||
this._scrollbarWidth = 0
|
this._scrollbarWidth = 0
|
||||||
}
|
}
|
||||||
|
@ -110,6 +111,14 @@ const Modal = (($) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
show(relatedTarget) {
|
show(relatedTarget) {
|
||||||
|
if (this._isTransitioning) {
|
||||||
|
throw new Error('Modal is transitioning')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Util.supportsTransitionEnd() &&
|
||||||
|
$(this._element).hasClass(ClassName.FADE)) {
|
||||||
|
this._isTransitioning = true
|
||||||
|
}
|
||||||
const showEvent = $.Event(Event.SHOW, {
|
const showEvent = $.Event(Event.SHOW, {
|
||||||
relatedTarget
|
relatedTarget
|
||||||
})
|
})
|
||||||
|
@ -152,8 +161,17 @@ const Modal = (($) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
const hideEvent = $.Event(Event.HIDE)
|
if (this._isTransitioning) {
|
||||||
|
throw new Error('Modal is transitioning')
|
||||||
|
}
|
||||||
|
|
||||||
|
const transition = Util.supportsTransitionEnd() &&
|
||||||
|
$(this._element).hasClass(ClassName.FADE)
|
||||||
|
if (transition) {
|
||||||
|
this._isTransitioning = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const hideEvent = $.Event(Event.HIDE)
|
||||||
$(this._element).trigger(hideEvent)
|
$(this._element).trigger(hideEvent)
|
||||||
|
|
||||||
if (!this._isShown || hideEvent.isDefaultPrevented()) {
|
if (!this._isShown || hideEvent.isDefaultPrevented()) {
|
||||||
|
@ -172,9 +190,7 @@ const Modal = (($) => {
|
||||||
$(this._element).off(Event.CLICK_DISMISS)
|
$(this._element).off(Event.CLICK_DISMISS)
|
||||||
$(this._dialog).off(Event.MOUSEDOWN_DISMISS)
|
$(this._dialog).off(Event.MOUSEDOWN_DISMISS)
|
||||||
|
|
||||||
if (Util.supportsTransitionEnd() &&
|
if (transition) {
|
||||||
$(this._element).hasClass(ClassName.FADE)) {
|
|
||||||
|
|
||||||
$(this._element)
|
$(this._element)
|
||||||
.one(Util.TRANSITION_END, (event) => this._hideModal(event))
|
.one(Util.TRANSITION_END, (event) => this._hideModal(event))
|
||||||
.emulateTransitionEnd(TRANSITION_DURATION)
|
.emulateTransitionEnd(TRANSITION_DURATION)
|
||||||
|
@ -240,6 +256,7 @@ const Modal = (($) => {
|
||||||
if (this._config.focus) {
|
if (this._config.focus) {
|
||||||
this._element.focus()
|
this._element.focus()
|
||||||
}
|
}
|
||||||
|
this._isTransitioning = false
|
||||||
$(this._element).trigger(shownEvent)
|
$(this._element).trigger(shownEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +304,8 @@ const Modal = (($) => {
|
||||||
|
|
||||||
_hideModal() {
|
_hideModal() {
|
||||||
this._element.style.display = 'none'
|
this._element.style.display = 'none'
|
||||||
this._element.setAttribute('aria-hidden', true)
|
this._element.setAttribute('aria-hidden', 'true')
|
||||||
|
this._isTransitioning = false
|
||||||
this._showBackdrop(() => {
|
this._showBackdrop(() => {
|
||||||
$(document.body).removeClass(ClassName.OPEN)
|
$(document.body).removeClass(ClassName.OPEN)
|
||||||
this._resetAdjustments()
|
this._resetAdjustments()
|
||||||
|
|
|
@ -123,11 +123,12 @@ const Tooltip = (($) => {
|
||||||
constructor(element, config) {
|
constructor(element, config) {
|
||||||
|
|
||||||
// private
|
// private
|
||||||
this._isEnabled = true
|
this._isEnabled = true
|
||||||
this._timeout = 0
|
this._timeout = 0
|
||||||
this._hoverState = ''
|
this._hoverState = ''
|
||||||
this._activeTrigger = {}
|
this._activeTrigger = {}
|
||||||
this._tether = null
|
this._isTransitioning = false
|
||||||
|
this._tether = null
|
||||||
|
|
||||||
// protected
|
// protected
|
||||||
this.element = element
|
this.element = element
|
||||||
|
@ -245,9 +246,12 @@ const Tooltip = (($) => {
|
||||||
if ($(this.element).css('display') === 'none') {
|
if ($(this.element).css('display') === 'none') {
|
||||||
throw new Error('Please use show on visible elements')
|
throw new Error('Please use show on visible elements')
|
||||||
}
|
}
|
||||||
const showEvent = $.Event(this.constructor.Event.SHOW)
|
|
||||||
|
|
||||||
|
const showEvent = $.Event(this.constructor.Event.SHOW)
|
||||||
if (this.isWithContent() && this._isEnabled) {
|
if (this.isWithContent() && this._isEnabled) {
|
||||||
|
if (this._isTransitioning) {
|
||||||
|
throw new Error('Tooltip is transitioning')
|
||||||
|
}
|
||||||
$(this.element).trigger(showEvent)
|
$(this.element).trigger(showEvent)
|
||||||
|
|
||||||
const isInTheDom = $.contains(
|
const isInTheDom = $.contains(
|
||||||
|
@ -303,7 +307,8 @@ const Tooltip = (($) => {
|
||||||
|
|
||||||
const complete = () => {
|
const complete = () => {
|
||||||
const prevHoverState = this._hoverState
|
const prevHoverState = this._hoverState
|
||||||
this._hoverState = null
|
this._hoverState = null
|
||||||
|
this._isTransitioning = false
|
||||||
|
|
||||||
$(this.element).trigger(this.constructor.Event.SHOWN)
|
$(this.element).trigger(this.constructor.Event.SHOWN)
|
||||||
|
|
||||||
|
@ -313,6 +318,7 @@ const Tooltip = (($) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Util.supportsTransitionEnd() && $(this.tip).hasClass(ClassName.FADE)) {
|
if (Util.supportsTransitionEnd() && $(this.tip).hasClass(ClassName.FADE)) {
|
||||||
|
this._isTransitioning = true
|
||||||
$(this.tip)
|
$(this.tip)
|
||||||
.one(Util.TRANSITION_END, complete)
|
.one(Util.TRANSITION_END, complete)
|
||||||
.emulateTransitionEnd(Tooltip._TRANSITION_DURATION)
|
.emulateTransitionEnd(Tooltip._TRANSITION_DURATION)
|
||||||
|
@ -326,6 +332,9 @@ const Tooltip = (($) => {
|
||||||
hide(callback) {
|
hide(callback) {
|
||||||
const tip = this.getTipElement()
|
const tip = this.getTipElement()
|
||||||
const hideEvent = $.Event(this.constructor.Event.HIDE)
|
const hideEvent = $.Event(this.constructor.Event.HIDE)
|
||||||
|
if (this._isTransitioning) {
|
||||||
|
throw new Error('Tooltip is transitioning')
|
||||||
|
}
|
||||||
const complete = () => {
|
const complete = () => {
|
||||||
if (this._hoverState !== HoverState.ACTIVE && tip.parentNode) {
|
if (this._hoverState !== HoverState.ACTIVE && tip.parentNode) {
|
||||||
tip.parentNode.removeChild(tip)
|
tip.parentNode.removeChild(tip)
|
||||||
|
@ -333,6 +342,7 @@ const Tooltip = (($) => {
|
||||||
|
|
||||||
this.element.removeAttribute('aria-describedby')
|
this.element.removeAttribute('aria-describedby')
|
||||||
$(this.element).trigger(this.constructor.Event.HIDDEN)
|
$(this.element).trigger(this.constructor.Event.HIDDEN)
|
||||||
|
this._isTransitioning = false
|
||||||
this.cleanupTether()
|
this.cleanupTether()
|
||||||
|
|
||||||
if (callback) {
|
if (callback) {
|
||||||
|
@ -350,7 +360,7 @@ const Tooltip = (($) => {
|
||||||
|
|
||||||
if (Util.supportsTransitionEnd() &&
|
if (Util.supportsTransitionEnd() &&
|
||||||
$(this.tip).hasClass(ClassName.FADE)) {
|
$(this.tip).hasClass(ClassName.FADE)) {
|
||||||
|
this._isTransitioning = true
|
||||||
$(tip)
|
$(tip)
|
||||||
.one(Util.TRANSITION_END, complete)
|
.one(Util.TRANSITION_END, complete)
|
||||||
.emulateTransitionEnd(TRANSITION_DURATION)
|
.emulateTransitionEnd(TRANSITION_DURATION)
|
||||||
|
|
|
@ -46,11 +46,31 @@
|
||||||
<script src="../../dist/carousel.js"></script>
|
<script src="../../dist/carousel.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(function() {
|
// Should throw an error because carousel is in transition
|
||||||
|
function testCarouselTransitionError() {
|
||||||
|
var err = false
|
||||||
|
var $carousel = $('#carousel-example-generic')
|
||||||
|
$carousel.on('slid.bs.carousel', function () {
|
||||||
|
$carousel.off('slid.bs.carousel')
|
||||||
|
if (!err) {
|
||||||
|
alert('No error thrown for : testCarouselTransitionError')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
$carousel.carousel('next').carousel('prev')
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
err = true
|
||||||
|
console.error(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
// Test to show that the carousel doesn't slide when the current tab isn't visible
|
// Test to show that the carousel doesn't slide when the current tab isn't visible
|
||||||
$('#carousel-example-generic').on('slid.bs.carousel', function(event) {
|
$('#carousel-example-generic').on('slid.bs.carousel', function (event) {
|
||||||
console.log('slid at ', event.timeStamp)
|
console.log('slid at ', event.timeStamp)
|
||||||
})
|
})
|
||||||
|
testCarouselTransitionError()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -61,5 +61,30 @@
|
||||||
<script src="../vendor/jquery.min.js"></script>
|
<script src="../vendor/jquery.min.js"></script>
|
||||||
<script src="../../dist/util.js"></script>
|
<script src="../../dist/util.js"></script>
|
||||||
<script src="../../dist/collapse.js"></script>
|
<script src="../../dist/collapse.js"></script>
|
||||||
|
<script>
|
||||||
|
// JavaScript Test
|
||||||
|
$(function () {
|
||||||
|
testCollapseTransitionError()
|
||||||
|
});
|
||||||
|
|
||||||
|
// Should throw an error because carousel is in transition
|
||||||
|
function testCollapseTransitionError() {
|
||||||
|
var err = false
|
||||||
|
$('#collapseOne').on('hidden.bs.collapse', function (e) {
|
||||||
|
$(this).off('hidden.bs.collapse')
|
||||||
|
if (!err) {
|
||||||
|
alert('No error thrown for : testCollapseTransitionError')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
$('#collapseOne').collapse('hide').collapse('show')
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
err = true
|
||||||
|
console.error(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -188,6 +188,26 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should throw an error because modal is in transition
|
||||||
|
function testModalTransitionError() {
|
||||||
|
var err = false
|
||||||
|
// Close #myModal
|
||||||
|
$('#myModal').on('shown.bs.modal', function () {
|
||||||
|
$('#myModal').modal('hide').off('shown.bs.modal')
|
||||||
|
if (!err) {
|
||||||
|
alert('No error thrown for : testModalTransitionError')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
$('#myModal').modal('show').modal('hide')
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
err = true
|
||||||
|
console.error(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
$('[data-toggle="popover"]').popover()
|
$('[data-toggle="popover"]').popover()
|
||||||
$('[data-toggle="tooltip"]').tooltip()
|
$('[data-toggle="tooltip"]').tooltip()
|
||||||
|
@ -200,6 +220,7 @@
|
||||||
$('#firefoxModal').on('focus', reportFirefoxTestResult.bind(false))
|
$('#firefoxModal').on('focus', reportFirefoxTestResult.bind(false))
|
||||||
$('#ff-bug-input').on('focus', reportFirefoxTestResult.bind(true))
|
$('#ff-bug-input').on('focus', reportFirefoxTestResult.bind(true))
|
||||||
})
|
})
|
||||||
|
testModalTransitionError()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -42,7 +42,26 @@
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
$('[data-toggle="tooltip"]').tooltip()
|
$('[data-toggle="tooltip"]').tooltip()
|
||||||
|
testTooltipTransitionError()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Should throw an error because tooltip is in transition
|
||||||
|
function testTooltipTransitionError() {
|
||||||
|
var err = false
|
||||||
|
$('#btnOne').on('shown.bs.tooltip', function () {
|
||||||
|
$('#btnOne').tooltip('hide').off('shown.bs.tooltip')
|
||||||
|
if (!err) {
|
||||||
|
alert('No error thrown for : testTooltipTransitionError')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
$('#btnOne').tooltip('show').tooltip('hide')
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
err = true
|
||||||
|
console.error(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in New Issue