1
0
mirror of https://github.com/twbs/bootstrap.git synced 2025-08-12 00:24:03 +02:00

Fix TypeError when Bootstrap is included in head (#32024)

* extend jquery after domContentLoaded event is fired

* add unittest for util onDOMContentLoaded

* wait for trigger jquery event after domContentLoaded

* remove domcontentready from eventHandler

* move istanbul ignore statements to correct line

Co-authored-by: XhmikosR <xhmikosr@gmail.com>
This commit is contained in:
Sascha
2020-11-01 14:32:36 +01:00
committed by GitHub
parent 3a5f9f5cf0
commit c21506d499
14 changed files with 184 additions and 126 deletions

View File

@@ -7,6 +7,7 @@
import { import {
getjQuery, getjQuery,
onDOMContentLoaded,
TRANSITION_END, TRANSITION_END,
emulateTransitionEnd, emulateTransitionEnd,
getElementFromSelector, getElementFromSelector,
@@ -146,8 +147,6 @@ class Alert {
*/ */
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DISMISS, Alert.handleDismiss(new Alert())) EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DISMISS, Alert.handleDismiss(new Alert()))
const $ = getjQuery()
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* jQuery * jQuery
@@ -155,15 +154,18 @@ const $ = getjQuery()
* add .alert to jQuery only if jQuery is present * add .alert to jQuery only if jQuery is present
*/ */
/* istanbul ignore if */ onDOMContentLoaded(() => {
if ($) { const $ = getjQuery()
const JQUERY_NO_CONFLICT = $.fn[NAME] /* istanbul ignore if */
$.fn[NAME] = Alert.jQueryInterface if ($) {
$.fn[NAME].Constructor = Alert const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME].noConflict = () => { $.fn[NAME] = Alert.jQueryInterface
$.fn[NAME] = JQUERY_NO_CONFLICT $.fn[NAME].Constructor = Alert
return Alert.jQueryInterface $.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return Alert.jQueryInterface
}
} }
} })
export default Alert export default Alert

View File

@@ -5,7 +5,7 @@
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
*/ */
import { getjQuery } from './util/index' import { getjQuery, onDOMContentLoaded } from './util/index'
import Data from './dom/data' import Data from './dom/data'
import EventHandler from './dom/event-handler' import EventHandler from './dom/event-handler'
@@ -97,24 +97,26 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {
data.toggle() data.toggle()
}) })
const $ = getjQuery()
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* jQuery * jQuery
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* add .button to jQuery only if jQuery is present * add .button to jQuery only if jQuery is present
*/ */
/* istanbul ignore if */
if ($) {
const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME] = Button.jQueryInterface
$.fn[NAME].Constructor = Button
$.fn[NAME].noConflict = () => { onDOMContentLoaded(() => {
$.fn[NAME] = JQUERY_NO_CONFLICT const $ = getjQuery()
return Button.jQueryInterface /* istanbul ignore if */
if ($) {
const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME] = Button.jQueryInterface
$.fn[NAME].Constructor = Button
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return Button.jQueryInterface
}
} }
} })
export default Button export default Button

View File

@@ -7,6 +7,7 @@
import { import {
getjQuery, getjQuery,
onDOMContentLoaded,
TRANSITION_END, TRANSITION_END,
emulateTransitionEnd, emulateTransitionEnd,
getElementFromSelector, getElementFromSelector,
@@ -611,23 +612,25 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
} }
}) })
const $ = getjQuery()
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* jQuery * jQuery
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* add .carousel to jQuery only if jQuery is present * add .carousel to jQuery only if jQuery is present
*/ */
/* istanbul ignore if */
if ($) { onDOMContentLoaded(() => {
const JQUERY_NO_CONFLICT = $.fn[NAME] const $ = getjQuery()
$.fn[NAME] = Carousel.jQueryInterface /* istanbul ignore if */
$.fn[NAME].Constructor = Carousel if ($) {
$.fn[NAME].noConflict = () => { const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME] = JQUERY_NO_CONFLICT $.fn[NAME] = Carousel.jQueryInterface
return Carousel.jQueryInterface $.fn[NAME].Constructor = Carousel
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return Carousel.jQueryInterface
}
} }
} })
export default Carousel export default Carousel

View File

@@ -7,6 +7,7 @@
import { import {
getjQuery, getjQuery,
onDOMContentLoaded,
TRANSITION_END, TRANSITION_END,
emulateTransitionEnd, emulateTransitionEnd,
getSelectorFromElement, getSelectorFromElement,
@@ -408,23 +409,25 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
}) })
}) })
const $ = getjQuery()
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* jQuery * jQuery
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* add .collapse to jQuery only if jQuery is present * add .collapse to jQuery only if jQuery is present
*/ */
/* istanbul ignore if */
if ($) { onDOMContentLoaded(() => {
const JQUERY_NO_CONFLICT = $.fn[NAME] const $ = getjQuery()
$.fn[NAME] = Collapse.jQueryInterface /* istanbul ignore if */
$.fn[NAME].Constructor = Collapse if ($) {
$.fn[NAME].noConflict = () => { const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME] = JQUERY_NO_CONFLICT $.fn[NAME] = Collapse.jQueryInterface
return Collapse.jQueryInterface $.fn[NAME].Constructor = Collapse
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return Collapse.jQueryInterface
}
} }
} })
export default Collapse export default Collapse

View File

@@ -14,7 +14,6 @@ import { defaultPreventedPreservedOnDispatch } from './polyfill'
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
*/ */
const $ = getjQuery()
const namespaceRegex = /[^.]*(?=\..*)\.|.*/ const namespaceRegex = /[^.]*(?=\..*)\.|.*/
const stripNameRegex = /\..*/ const stripNameRegex = /\..*/
const stripUidRegex = /::\d+$/ const stripUidRegex = /::\d+$/
@@ -272,6 +271,7 @@ const EventHandler = {
return null return null
} }
const $ = getjQuery()
const typeEvent = event.replace(stripNameRegex, '') const typeEvent = event.replace(stripNameRegex, '')
const inNamespace = event !== typeEvent const inNamespace = event !== typeEvent
const isNative = nativeEvents.indexOf(typeEvent) > -1 const isNative = nativeEvents.indexOf(typeEvent) > -1

View File

@@ -7,6 +7,7 @@
import { import {
getjQuery, getjQuery,
onDOMContentLoaded,
getElementFromSelector, getElementFromSelector,
isElement, isElement,
isVisible, isVisible,
@@ -512,23 +513,25 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
}) })
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, e => e.stopPropagation()) EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, e => e.stopPropagation())
const $ = getjQuery()
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* jQuery * jQuery
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* add .dropdown to jQuery only if jQuery is present * add .dropdown to jQuery only if jQuery is present
*/ */
/* istanbul ignore if */
if ($) { onDOMContentLoaded(() => {
const JQUERY_NO_CONFLICT = $.fn[NAME] const $ = getjQuery()
$.fn[NAME] = Dropdown.jQueryInterface /* istanbul ignore if */
$.fn[NAME].Constructor = Dropdown if ($) {
$.fn[NAME].noConflict = () => { const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME] = JQUERY_NO_CONFLICT $.fn[NAME] = Dropdown.jQueryInterface
return Dropdown.jQueryInterface $.fn[NAME].Constructor = Dropdown
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return Dropdown.jQueryInterface
}
} }
} })
export default Dropdown export default Dropdown

View File

@@ -7,6 +7,7 @@
import { import {
getjQuery, getjQuery,
onDOMContentLoaded,
TRANSITION_END, TRANSITION_END,
emulateTransitionEnd, emulateTransitionEnd,
getElementFromSelector, getElementFromSelector,
@@ -607,23 +608,25 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
data.show(this) data.show(this)
}) })
const $ = getjQuery()
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* jQuery * jQuery
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* add .modal to jQuery only if jQuery is present * add .modal to jQuery only if jQuery is present
*/ */
/* istanbul ignore if */
if ($) { onDOMContentLoaded(() => {
const JQUERY_NO_CONFLICT = $.fn[NAME] const $ = getjQuery()
$.fn[NAME] = Modal.jQueryInterface /* istanbul ignore if */
$.fn[NAME].Constructor = Modal if ($) {
$.fn[NAME].noConflict = () => { const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME] = JQUERY_NO_CONFLICT $.fn[NAME] = Modal.jQueryInterface
return Modal.jQueryInterface $.fn[NAME].Constructor = Modal
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return Modal.jQueryInterface
}
} }
} })
export default Modal export default Modal

View File

@@ -5,7 +5,7 @@
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
*/ */
import { getjQuery } from './util/index' import { getjQuery, onDOMContentLoaded } from './util/index'
import Data from './dom/data' import Data from './dom/data'
import SelectorEngine from './dom/selector-engine' import SelectorEngine from './dom/selector-engine'
import Tooltip from './tooltip' import Tooltip from './tooltip'
@@ -167,22 +167,24 @@ class Popover extends Tooltip {
} }
} }
const $ = getjQuery()
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* jQuery * jQuery
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
*/ */
/* istanbul ignore if */
if ($) { onDOMContentLoaded(() => {
const JQUERY_NO_CONFLICT = $.fn[NAME] const $ = getjQuery()
$.fn[NAME] = Popover.jQueryInterface /* istanbul ignore if */
$.fn[NAME].Constructor = Popover if ($) {
$.fn[NAME].noConflict = () => { const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME] = JQUERY_NO_CONFLICT $.fn[NAME] = Popover.jQueryInterface
return Popover.jQueryInterface $.fn[NAME].Constructor = Popover
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return Popover.jQueryInterface
}
} }
} })
export default Popover export default Popover

View File

@@ -7,6 +7,7 @@
import { import {
getjQuery, getjQuery,
onDOMContentLoaded,
getSelectorFromElement, getSelectorFromElement,
getUID, getUID,
isElement, isElement,
@@ -317,22 +318,24 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
.forEach(spy => new ScrollSpy(spy, Manipulator.getDataAttributes(spy))) .forEach(spy => new ScrollSpy(spy, Manipulator.getDataAttributes(spy)))
}) })
const $ = getjQuery()
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* jQuery * jQuery
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
*/ */
/* istanbul ignore if */
if ($) { onDOMContentLoaded(() => {
const JQUERY_NO_CONFLICT = $.fn[NAME] const $ = getjQuery()
$.fn[NAME] = ScrollSpy.jQueryInterface /* istanbul ignore if */
$.fn[NAME].Constructor = ScrollSpy if ($) {
$.fn[NAME].noConflict = () => { const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME] = JQUERY_NO_CONFLICT $.fn[NAME] = ScrollSpy.jQueryInterface
return ScrollSpy.jQueryInterface $.fn[NAME].Constructor = ScrollSpy
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return ScrollSpy.jQueryInterface
}
} }
} })
export default ScrollSpy export default ScrollSpy

View File

@@ -7,6 +7,7 @@
import { import {
getjQuery, getjQuery,
onDOMContentLoaded,
TRANSITION_END, TRANSITION_END,
emulateTransitionEnd, emulateTransitionEnd,
getElementFromSelector, getElementFromSelector,
@@ -235,23 +236,25 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
data.show() data.show()
}) })
const $ = getjQuery()
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* jQuery * jQuery
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* add .tab to jQuery only if jQuery is present * add .tab to jQuery only if jQuery is present
*/ */
/* istanbul ignore if */
if ($) { onDOMContentLoaded(() => {
const JQUERY_NO_CONFLICT = $.fn[NAME] const $ = getjQuery()
$.fn[NAME] = Tab.jQueryInterface /* istanbul ignore if */
$.fn[NAME].Constructor = Tab if ($) {
$.fn[NAME].noConflict = () => { const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME] = JQUERY_NO_CONFLICT $.fn[NAME] = Tab.jQueryInterface
return Tab.jQueryInterface $.fn[NAME].Constructor = Tab
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return Tab.jQueryInterface
}
} }
} })
export default Tab export default Tab

View File

@@ -7,6 +7,7 @@
import { import {
getjQuery, getjQuery,
onDOMContentLoaded,
TRANSITION_END, TRANSITION_END,
emulateTransitionEnd, emulateTransitionEnd,
getTransitionDurationFromElement, getTransitionDurationFromElement,
@@ -213,23 +214,25 @@ class Toast {
} }
} }
const $ = getjQuery()
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* jQuery * jQuery
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* add .toast to jQuery only if jQuery is present * add .toast to jQuery only if jQuery is present
*/ */
/* istanbul ignore if */
if ($) { onDOMContentLoaded(() => {
const JQUERY_NO_CONFLICT = $.fn[NAME] const $ = getjQuery()
$.fn[NAME] = Toast.jQueryInterface /* istanbul ignore if */
$.fn[NAME].Constructor = Toast if ($) {
$.fn[NAME].noConflict = () => { const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME] = JQUERY_NO_CONFLICT $.fn[NAME] = Toast.jQueryInterface
return Toast.jQueryInterface $.fn[NAME].Constructor = Toast
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return Toast.jQueryInterface
}
} }
} })
export default Toast export default Toast

View File

@@ -7,6 +7,7 @@
import { import {
getjQuery, getjQuery,
onDOMContentLoaded,
TRANSITION_END, TRANSITION_END,
emulateTransitionEnd, emulateTransitionEnd,
findShadowRoot, findShadowRoot,
@@ -793,23 +794,25 @@ class Tooltip {
} }
} }
const $ = getjQuery()
/** /**
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* jQuery * jQuery
* ------------------------------------------------------------------------ * ------------------------------------------------------------------------
* add .tooltip to jQuery only if jQuery is present * add .tooltip to jQuery only if jQuery is present
*/ */
/* istanbul ignore if */
if ($) { onDOMContentLoaded(() => {
const JQUERY_NO_CONFLICT = $.fn[NAME] const $ = getjQuery()
$.fn[NAME] = Tooltip.jQueryInterface /* istanbul ignore if */
$.fn[NAME].Constructor = Tooltip if ($) {
$.fn[NAME].noConflict = () => { const JQUERY_NO_CONFLICT = $.fn[NAME]
$.fn[NAME] = JQUERY_NO_CONFLICT $.fn[NAME] = Tooltip.jQueryInterface
return Tooltip.jQueryInterface $.fn[NAME].Constructor = Tooltip
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return Tooltip.jQueryInterface
}
} }
} })
export default Tooltip export default Tooltip

View File

@@ -180,8 +180,15 @@ const getjQuery = () => {
return null return null
} }
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', callback)
} else {
callback()
}
}
export { export {
getjQuery,
TRANSITION_END, TRANSITION_END,
getUID, getUID,
getSelectorFromElement, getSelectorFromElement,
@@ -194,5 +201,7 @@ export {
isVisible, isVisible,
findShadowRoot, findShadowRoot,
noop, noop,
reflow reflow,
getjQuery,
onDOMContentLoaded
} }

View File

@@ -394,4 +394,23 @@ describe('Util', () => {
expect(Util.getjQuery()).toEqual(null) expect(Util.getjQuery()).toEqual(null)
}) })
}) })
describe('onDOMContentLoaded', () => {
it('should execute callback when DOMContentLoaded is fired', () => {
const spy = jasmine.createSpy()
spyOnProperty(document, 'readyState').and.returnValue('loading')
Util.onDOMContentLoaded(spy)
window.document.dispatchEvent(new Event('DOMContentLoaded', {
bubbles: true,
cancelable: true
}))
expect(spy).toHaveBeenCalled()
})
it('should execute callback if readyState is not "loading"', () => {
const spy = jasmine.createSpy()
Util.onDOMContentLoaded(spy)
expect(spy).toHaveBeenCalled()
})
})
}) })