diff --git a/js/src/alert/alert.js b/js/src/alert/alert.js index 793b5989af..024528b816 100644 --- a/js/src/alert/alert.js +++ b/js/src/alert/alert.js @@ -6,7 +6,7 @@ */ import { - jQuery as $, + getjQuery, TRANSITION_END, emulateTransitionEnd, getElementFromSelector, @@ -165,6 +165,8 @@ class Alert { EventHandler .on(document, Event.CLICK_DATA_API, Selector.DISMISS, Alert.handleDismiss(new Alert())) +const $ = getjQuery() + /** * ------------------------------------------------------------------------ * jQuery @@ -173,7 +175,7 @@ EventHandler */ /* istanbul ignore if */ -if (typeof $ !== 'undefined') { +if ($) { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Alert.jQueryInterface $.fn[NAME].Constructor = Alert diff --git a/js/src/button/button.js b/js/src/button/button.js index b7e20461d6..d64f5130e2 100644 --- a/js/src/button/button.js +++ b/js/src/button/button.js @@ -5,7 +5,7 @@ * -------------------------------------------------------------------------- */ -import { jQuery as $ } from '../util/index' +import { getjQuery } from '../util/index' import Data from '../dom/data' import EventHandler from '../dom/event-handler' import SelectorEngine from '../dom/selector-engine' @@ -179,6 +179,8 @@ EventHandler.on(document, Event.BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, even } }) +const $ = getjQuery() + /** * ------------------------------------------------------------------------ * jQuery @@ -186,7 +188,7 @@ EventHandler.on(document, Event.BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, even * add .button to jQuery only if jQuery is present */ /* istanbul ignore if */ -if (typeof $ !== 'undefined') { +if ($) { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Button.jQueryInterface $.fn[NAME].Constructor = Button diff --git a/js/src/carousel/carousel.js b/js/src/carousel/carousel.js index 0bac655ea0..40984fe80f 100644 --- a/js/src/carousel/carousel.js +++ b/js/src/carousel/carousel.js @@ -6,7 +6,7 @@ */ import { - jQuery as $, + getjQuery, TRANSITION_END, emulateTransitionEnd, getElementFromSelector, @@ -615,6 +615,8 @@ EventHandler.on(window, Event.LOAD_DATA_API, () => { } }) +const $ = getjQuery() + /** * ------------------------------------------------------------------------ * jQuery @@ -622,7 +624,7 @@ EventHandler.on(window, Event.LOAD_DATA_API, () => { * add .carousel to jQuery only if jQuery is present */ /* istanbul ignore if */ -if (typeof $ !== 'undefined') { +if ($) { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Carousel.jQueryInterface $.fn[NAME].Constructor = Carousel diff --git a/js/src/collapse/collapse.js b/js/src/collapse/collapse.js index 7990857763..4de7b52822 100644 --- a/js/src/collapse/collapse.js +++ b/js/src/collapse/collapse.js @@ -6,7 +6,7 @@ */ import { - jQuery as $, + getjQuery, TRANSITION_END, emulateTransitionEnd, getSelectorFromElement, @@ -419,6 +419,8 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function ( }) }) +const $ = getjQuery() + /** * ------------------------------------------------------------------------ * jQuery @@ -426,7 +428,7 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function ( * add .collapse to jQuery only if jQuery is present */ /* istanbul ignore if */ -if (typeof $ !== 'undefined') { +if ($) { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Collapse.jQueryInterface $.fn[NAME].Constructor = Collapse diff --git a/js/src/dom/event-handler.js b/js/src/dom/event-handler.js index 3310b41abd..71b3a643b8 100644 --- a/js/src/dom/event-handler.js +++ b/js/src/dom/event-handler.js @@ -5,7 +5,7 @@ * -------------------------------------------------------------------------- */ -import { jQuery as $ } from '../util/index' +import { getjQuery } from '../util/index' import { createCustomEvent, defaultPreventedPreservedOnDispatch } from './polyfill' /** @@ -14,6 +14,7 @@ import { createCustomEvent, defaultPreventedPreservedOnDispatch } from './polyfi * ------------------------------------------------------------------------ */ +const $ = getjQuery() const namespaceRegex = /[^.]*(?=\..*)\.|.*/ const stripNameRegex = /\..*/ const keyEventRegex = /^key/ @@ -293,7 +294,7 @@ const EventHandler = { let defaultPrevented = false let evt = null - if (inNamespace && typeof $ !== 'undefined') { + if (inNamespace && $) { jQueryEvent = $.Event(event, args) $(element).trigger(jQueryEvent) diff --git a/js/src/dropdown/dropdown.js b/js/src/dropdown/dropdown.js index 7f5264d050..2c30ba740a 100644 --- a/js/src/dropdown/dropdown.js +++ b/js/src/dropdown/dropdown.js @@ -6,7 +6,7 @@ */ import { - jQuery as $, + getjQuery, getElementFromSelector, isElement, makeArray, @@ -526,6 +526,8 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function ( EventHandler .on(document, Event.CLICK_DATA_API, Selector.FORM_CHILD, e => e.stopPropagation()) +const $ = getjQuery() + /** * ------------------------------------------------------------------------ * jQuery @@ -533,7 +535,7 @@ EventHandler * add .dropdown to jQuery only if jQuery is present */ /* istanbul ignore if */ -if (typeof $ !== 'undefined') { +if ($) { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Dropdown.jQueryInterface $.fn[NAME].Constructor = Dropdown diff --git a/js/src/modal/modal.js b/js/src/modal/modal.js index fd24b7768f..4864cad9d0 100644 --- a/js/src/modal/modal.js +++ b/js/src/modal/modal.js @@ -6,7 +6,7 @@ */ import { - jQuery as $, + getjQuery, TRANSITION_END, emulateTransitionEnd, getElementFromSelector, @@ -582,6 +582,8 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function ( data.show(this) }) +const $ = getjQuery() + /** * ------------------------------------------------------------------------ * jQuery @@ -589,7 +591,7 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function ( * add .modal to jQuery only if jQuery is present */ /* istanbul ignore if */ -if (typeof $ !== 'undefined') { +if ($) { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Modal.jQueryInterface $.fn[NAME].Constructor = Modal diff --git a/js/src/popover/popover.js b/js/src/popover/popover.js index ce92e0d559..5da7ffe562 100644 --- a/js/src/popover/popover.js +++ b/js/src/popover/popover.js @@ -5,7 +5,7 @@ * -------------------------------------------------------------------------- */ -import { jQuery as $ } from '../util/index' +import { getjQuery } from '../util/index' import Data from '../dom/data' import SelectorEngine from '../dom/selector-engine' import Tooltip from '../tooltip/tooltip' @@ -173,13 +173,15 @@ class Popover extends Tooltip { } } +const $ = getjQuery() + /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ */ /* istanbul ignore if */ -if (typeof $ !== 'undefined') { +if ($) { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Popover.jQueryInterface $.fn[NAME].Constructor = Popover diff --git a/js/src/scrollspy/scrollspy.js b/js/src/scrollspy/scrollspy.js index b3b87a3b23..fa52a12890 100644 --- a/js/src/scrollspy/scrollspy.js +++ b/js/src/scrollspy/scrollspy.js @@ -6,7 +6,7 @@ */ import { - jQuery as $, + getjQuery, getSelectorFromElement, getUID, makeArray, @@ -336,13 +336,15 @@ EventHandler.on(window, Event.LOAD_DATA_API, () => { .forEach(spy => new ScrollSpy(spy, Manipulator.getDataAttributes(spy))) }) +const $ = getjQuery() + /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ */ /* istanbul ignore if */ -if (typeof $ !== 'undefined') { +if ($) { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = ScrollSpy.jQueryInterface $.fn[NAME].Constructor = ScrollSpy diff --git a/js/src/tab/tab.js b/js/src/tab/tab.js index 2d4b8e30c4..b2374fe919 100644 --- a/js/src/tab/tab.js +++ b/js/src/tab/tab.js @@ -6,7 +6,7 @@ */ import { - jQuery as $, + getjQuery, TRANSITION_END, emulateTransitionEnd, getElementFromSelector, @@ -242,6 +242,8 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function ( data.show() }) +const $ = getjQuery() + /** * ------------------------------------------------------------------------ * jQuery @@ -249,7 +251,7 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function ( * add .tab to jQuery only if jQuery is present */ /* istanbul ignore if */ -if (typeof $ !== 'undefined') { +if ($) { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Tab.jQueryInterface $.fn[NAME].Constructor = Tab diff --git a/js/src/toast/toast.js b/js/src/toast/toast.js index 51a7c8b353..4de7db1cd1 100644 --- a/js/src/toast/toast.js +++ b/js/src/toast/toast.js @@ -6,7 +6,7 @@ */ import { - jQuery as $, + getjQuery, TRANSITION_END, emulateTransitionEnd, getTransitionDurationFromElement, @@ -222,6 +222,8 @@ class Toast { } } +const $ = getjQuery() + /** * ------------------------------------------------------------------------ * jQuery @@ -229,7 +231,7 @@ class Toast { * add .toast to jQuery only if jQuery is present */ /* istanbul ignore if */ -if (typeof $ !== 'undefined') { +if ($) { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Toast.jQueryInterface $.fn[NAME].Constructor = Toast diff --git a/js/src/tooltip/tooltip.js b/js/src/tooltip/tooltip.js index 7575bb89db..33f0173a3f 100644 --- a/js/src/tooltip/tooltip.js +++ b/js/src/tooltip/tooltip.js @@ -6,7 +6,7 @@ */ import { - jQuery as $, + getjQuery, TRANSITION_END, emulateTransitionEnd, findShadowRoot, @@ -798,6 +798,8 @@ class Tooltip { } } +const $ = getjQuery() + /** * ------------------------------------------------------------------------ * jQuery @@ -805,7 +807,7 @@ class Tooltip { * add .tooltip to jQuery only if jQuery is present */ /* istanbul ignore if */ -if (typeof $ !== 'undefined') { +if ($) { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Tooltip.jQueryInterface $.fn[NAME].Constructor = Tooltip diff --git a/js/src/util/index.js b/js/src/util/index.js index 537b391dcc..746ee608bc 100644 --- a/js/src/util/index.js +++ b/js/src/util/index.js @@ -8,7 +8,6 @@ const MAX_UID = 1000000 const MILLISECONDS_MULTIPLIER = 1000 const TRANSITION_END = 'transitionend' -const { jQuery } = window // Shoutout AngusCroll (https://goo.gl/pxwQGp) const toType = obj => ({}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase()) @@ -176,8 +175,18 @@ const noop = () => function () {} const reflow = element => element.offsetHeight +const getjQuery = () => { + const { jQuery } = window + + if (jQuery && !document.body.hasAttribute('data-no-jquery')) { + return jQuery + } + + return null +} + export { - jQuery, + getjQuery, TRANSITION_END, getUID, getSelectorFromElement, diff --git a/js/src/util/index.spec.js b/js/src/util/index.spec.js index b667c270ea..9512c2fe0b 100644 --- a/js/src/util/index.spec.js +++ b/js/src/util/index.spec.js @@ -346,4 +346,37 @@ describe('Util', () => { expect(Util.reflow(div)).toEqual(0) }) }) + + describe('getjQuery', () => { + const fakejQuery = { trigger() {} } + + beforeEach(() => { + Object.defineProperty(window, 'jQuery', { + value: fakejQuery, + writable: true + }) + }) + + afterEach(() => { + window.jQuery = undefined + }) + + it('should return jQuery object when present', () => { + expect(Util.getjQuery()).toEqual(fakejQuery) + }) + + it('should not return jQuery object when present if data-no-jquery', () => { + document.body.setAttribute('data-no-jquery', '') + + expect(window.jQuery).toEqual(fakejQuery) + expect(Util.getjQuery()).toEqual(null) + + document.body.removeAttribute('data-no-jquery') + }) + + it('should not return jQuery if not present', () => { + window.jQuery = undefined + expect(Util.getjQuery()).toEqual(null) + }) + }) }) diff --git a/site/content/docs/4.3/getting-started/javascript.md b/site/content/docs/4.3/getting-started/javascript.md index 36dcd76b71..bb7dab105a 100644 --- a/site/content/docs/4.3/getting-started/javascript.md +++ b/site/content/docs/4.3/getting-started/javascript.md @@ -67,7 +67,7 @@ myModal.addEventListener('show.bs.modal', function (e) { {{< callout warning >}} ## jQuery events -Bootstrap will detect jQuery only if `jQuery` is present in the `window` object. If jQuery is found, Bootstrap will emit events thanks to jQuery's event system. So if you want to listen to Bootstrap's events, you'll have to use the jQuery methods (`.on`, `.one`). +Bootstrap will detect jQuery if `jQuery` is present in the `window` object and no `data-no-jquery` attribute on ``. If jQuery is found, Bootstrap will emit events thanks to jQuery's event system. So if you want to listen to Bootstrap's events, you'll have to use the jQuery methods (`.on`, `.one`) instead of `addEventListener`. {{< highlight js >}} $('#myTab a').on('shown.bs.tab', function () {