mirror of
https://github.com/twbs/bootstrap.git
synced 2025-08-11 08:04:59 +02:00
Fix handling of transitionend events dispatched by nested elements(#33845)
Fix handling of transitionend events dispatched by nested elements Properly handle events from nested elements Change `emulateTransitionEnd` to `executeAfterTransition` &&
This commit is contained in:
@@ -7,10 +7,8 @@
|
||||
|
||||
import Data from './dom/data'
|
||||
import {
|
||||
emulateTransitionEnd,
|
||||
execute,
|
||||
getElement,
|
||||
getTransitionDurationFromElement
|
||||
executeAfterTransition,
|
||||
getElement
|
||||
} from './util/index'
|
||||
import EventHandler from './dom/event-handler'
|
||||
|
||||
@@ -44,15 +42,7 @@ class BaseComponent {
|
||||
}
|
||||
|
||||
_queueCallback(callback, element, isAnimated = true) {
|
||||
if (!isAnimated) {
|
||||
execute(callback)
|
||||
return
|
||||
}
|
||||
|
||||
const transitionDuration = getTransitionDurationFromElement(element)
|
||||
EventHandler.one(element, 'transitionend', () => execute(callback))
|
||||
|
||||
emulateTransitionEnd(element, transitionDuration)
|
||||
executeAfterTransition(callback, element, isAnimated)
|
||||
}
|
||||
|
||||
/** Static */
|
||||
|
@@ -7,9 +7,7 @@
|
||||
|
||||
import {
|
||||
defineJQueryPlugin,
|
||||
emulateTransitionEnd,
|
||||
getElementFromSelector,
|
||||
getTransitionDurationFromElement,
|
||||
isRTL,
|
||||
isVisible,
|
||||
reflow,
|
||||
@@ -339,25 +337,28 @@ class Modal extends BaseComponent {
|
||||
return
|
||||
}
|
||||
|
||||
const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight
|
||||
const { classList, scrollHeight, style } = this._element
|
||||
const isModalOverflowing = scrollHeight > document.documentElement.clientHeight
|
||||
|
||||
if (!isModalOverflowing) {
|
||||
this._element.style.overflowY = 'hidden'
|
||||
// return if the following background transition hasn't yet completed
|
||||
if ((!isModalOverflowing && style.overflowY === 'hidden') || classList.contains(CLASS_NAME_STATIC)) {
|
||||
return
|
||||
}
|
||||
|
||||
this._element.classList.add(CLASS_NAME_STATIC)
|
||||
const modalTransitionDuration = getTransitionDurationFromElement(this._dialog)
|
||||
EventHandler.off(this._element, 'transitionend')
|
||||
EventHandler.one(this._element, 'transitionend', () => {
|
||||
this._element.classList.remove(CLASS_NAME_STATIC)
|
||||
if (!isModalOverflowing) {
|
||||
style.overflowY = 'hidden'
|
||||
}
|
||||
|
||||
classList.add(CLASS_NAME_STATIC)
|
||||
this._queueCallback(() => {
|
||||
classList.remove(CLASS_NAME_STATIC)
|
||||
if (!isModalOverflowing) {
|
||||
EventHandler.one(this._element, 'transitionend', () => {
|
||||
this._element.style.overflowY = ''
|
||||
})
|
||||
emulateTransitionEnd(this._element, modalTransitionDuration)
|
||||
this._queueCallback(() => {
|
||||
style.overflowY = ''
|
||||
}, this._dialog)
|
||||
}
|
||||
})
|
||||
emulateTransitionEnd(this._element, modalTransitionDuration)
|
||||
}, this._dialog)
|
||||
|
||||
this._element.focus()
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
import EventHandler from '../dom/event-handler'
|
||||
import { emulateTransitionEnd, execute, getElement, getTransitionDurationFromElement, reflow, typeCheckConfig } from './index'
|
||||
import { execute, executeAfterTransition, getElement, reflow, typeCheckConfig } from './index'
|
||||
|
||||
const Default = {
|
||||
isVisible: true, // if false, we use the backdrop helper without adding any element to the dom
|
||||
@@ -122,14 +122,7 @@ class Backdrop {
|
||||
}
|
||||
|
||||
_emulateAnimation(callback) {
|
||||
if (!this._config.isAnimated) {
|
||||
execute(callback)
|
||||
return
|
||||
}
|
||||
|
||||
const backdropTransitionDuration = getTransitionDurationFromElement(this._getElement())
|
||||
EventHandler.one(this._getElement(), 'transitionend', () => execute(callback))
|
||||
emulateTransitionEnd(this._getElement(), backdropTransitionDuration)
|
||||
executeAfterTransition(callback, this._getElement(), this._config.isAnimated)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -126,24 +126,6 @@ const getElement = obj => {
|
||||
return null
|
||||
}
|
||||
|
||||
const emulateTransitionEnd = (element, duration) => {
|
||||
let called = false
|
||||
const durationPadding = 5
|
||||
const emulatedDuration = duration + durationPadding
|
||||
|
||||
function listener() {
|
||||
called = true
|
||||
element.removeEventListener(TRANSITION_END, listener)
|
||||
}
|
||||
|
||||
element.addEventListener(TRANSITION_END, listener)
|
||||
setTimeout(() => {
|
||||
if (!called) {
|
||||
triggerTransitionEnd(element)
|
||||
}
|
||||
}, emulatedDuration)
|
||||
}
|
||||
|
||||
const typeCheckConfig = (componentName, config, configTypes) => {
|
||||
Object.keys(configTypes).forEach(property => {
|
||||
const expectedTypes = configTypes[property]
|
||||
@@ -252,6 +234,35 @@ const execute = callback => {
|
||||
}
|
||||
}
|
||||
|
||||
const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
|
||||
if (!waitForTransition) {
|
||||
execute(callback)
|
||||
return
|
||||
}
|
||||
|
||||
const durationPadding = 5
|
||||
const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding
|
||||
|
||||
let called = false
|
||||
|
||||
const handler = ({ target }) => {
|
||||
if (target !== transitionElement) {
|
||||
return
|
||||
}
|
||||
|
||||
called = true
|
||||
transitionElement.removeEventListener(TRANSITION_END, handler)
|
||||
execute(callback)
|
||||
}
|
||||
|
||||
transitionElement.addEventListener(TRANSITION_END, handler)
|
||||
setTimeout(() => {
|
||||
if (!called) {
|
||||
triggerTransitionEnd(transitionElement)
|
||||
}
|
||||
}, emulatedDuration)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the previous/next element of a list.
|
||||
*
|
||||
@@ -288,7 +299,6 @@ export {
|
||||
getTransitionDurationFromElement,
|
||||
triggerTransitionEnd,
|
||||
isElement,
|
||||
emulateTransitionEnd,
|
||||
typeCheckConfig,
|
||||
isVisible,
|
||||
isDisabled,
|
||||
@@ -300,5 +310,6 @@ export {
|
||||
onDOMContentLoaded,
|
||||
isRTL,
|
||||
defineJQueryPlugin,
|
||||
execute
|
||||
execute,
|
||||
executeAfterTransition
|
||||
}
|
||||
|
Reference in New Issue
Block a user