aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/twbs/bootstrap/js/src/scrollspy.js
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/twbs/bootstrap/js/src/scrollspy.js')
-rw-r--r--vendor/twbs/bootstrap/js/src/scrollspy.js203
1 files changed, 87 insertions, 116 deletions
diff --git a/vendor/twbs/bootstrap/js/src/scrollspy.js b/vendor/twbs/bootstrap/js/src/scrollspy.js
index 351df0649..825b07fbc 100644
--- a/vendor/twbs/bootstrap/js/src/scrollspy.js
+++ b/vendor/twbs/bootstrap/js/src/scrollspy.js
@@ -1,12 +1,20 @@
/**
* --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): scrollspy.js
+ * Bootstrap (v5.1.3): scrollspy.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
-import $ from 'jquery'
-import Util from './util'
+import {
+ defineJQueryPlugin,
+ getElement,
+ getSelectorFromElement,
+ typeCheckConfig
+} from './util/index'
+import EventHandler from './dom/event-handler'
+import Manipulator from './dom/manipulator'
+import SelectorEngine from './dom/selector-engine'
+import BaseComponent from './base-component'
/**
* ------------------------------------------------------------------------
@@ -15,11 +23,9 @@ import Util from './util'
*/
const NAME = 'scrollspy'
-const VERSION = '4.6.0'
const DATA_KEY = 'bs.scrollspy'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
-const JQUERY_NO_CONFLICT = $.fn[NAME]
const Default = {
offset: 10,
@@ -40,13 +46,13 @@ const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'
const CLASS_NAME_ACTIVE = 'active'
-const SELECTOR_DATA_SPY = '[data-spy="scroll"]'
+const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]'
const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'
const SELECTOR_NAV_LINKS = '.nav-link'
const SELECTOR_NAV_ITEMS = '.nav-item'
const SELECTOR_LIST_ITEMS = '.list-group-item'
+const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}, .${CLASS_NAME_DROPDOWN_ITEM}`
const SELECTOR_DROPDOWN = '.dropdown'
-const SELECTOR_DROPDOWN_ITEMS = '.dropdown-item'
const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'
const METHOD_OFFSET = 'offset'
@@ -58,20 +64,17 @@ const METHOD_POSITION = 'position'
* ------------------------------------------------------------------------
*/
-class ScrollSpy {
+class ScrollSpy extends BaseComponent {
constructor(element, config) {
- this._element = element
- this._scrollElement = element.tagName === 'BODY' ? window : element
+ super(element)
+ this._scrollElement = this._element.tagName === 'BODY' ? window : this._element
this._config = this._getConfig(config)
- this._selector = `${this._config.target} ${SELECTOR_NAV_LINKS},` +
- `${this._config.target} ${SELECTOR_LIST_ITEMS},` +
- `${this._config.target} ${SELECTOR_DROPDOWN_ITEMS}`
this._offsets = []
this._targets = []
this._activeTarget = null
this._scrollHeight = 0
- $(this._scrollElement).on(EVENT_SCROLL, event => this._process(event))
+ EventHandler.on(this._scrollElement, EVENT_SCROLL, () => this._process())
this.refresh()
this._process()
@@ -79,55 +82,51 @@ class ScrollSpy {
// Getters
- static get VERSION() {
- return VERSION
- }
-
static get Default() {
return Default
}
+ static get NAME() {
+ return NAME
+ }
+
// Public
refresh() {
const autoMethod = this._scrollElement === this._scrollElement.window ?
- METHOD_OFFSET : METHOD_POSITION
+ METHOD_OFFSET :
+ METHOD_POSITION
const offsetMethod = this._config.method === 'auto' ?
- autoMethod : this._config.method
+ autoMethod :
+ this._config.method
const offsetBase = offsetMethod === METHOD_POSITION ?
- this._getScrollTop() : 0
+ this._getScrollTop() :
+ 0
this._offsets = []
this._targets = []
-
this._scrollHeight = this._getScrollHeight()
- const targets = [].slice.call(document.querySelectorAll(this._selector))
+ const targets = SelectorEngine.find(SELECTOR_LINK_ITEMS, this._config.target)
- targets
- .map(element => {
- let target
- const targetSelector = Util.getSelectorFromElement(element)
+ targets.map(element => {
+ const targetSelector = getSelectorFromElement(element)
+ const target = targetSelector ? SelectorEngine.findOne(targetSelector) : null
- if (targetSelector) {
- target = document.querySelector(targetSelector)
- }
-
- if (target) {
- const targetBCR = target.getBoundingClientRect()
- if (targetBCR.width || targetBCR.height) {
- // TODO (fat): remove sketch reliance on jQuery position/offset
- return [
- $(target)[offsetMethod]().top + offsetBase,
- targetSelector
- ]
- }
+ if (target) {
+ const targetBCR = target.getBoundingClientRect()
+ if (targetBCR.width || targetBCR.height) {
+ return [
+ Manipulator[offsetMethod](target).top + offsetBase,
+ targetSelector
+ ]
}
+ }
- return null
- })
+ return null
+ })
.filter(item => item)
.sort((a, b) => a[0] - b[0])
.forEach(item => {
@@ -137,17 +136,8 @@ class ScrollSpy {
}
dispose() {
- $.removeData(this._element, DATA_KEY)
- $(this._scrollElement).off(EVENT_KEY)
-
- this._element = null
- this._scrollElement = null
- this._config = null
- this._selector = null
- this._offsets = null
- this._targets = null
- this._activeTarget = null
- this._scrollHeight = null
+ EventHandler.off(this._scrollElement, EVENT_KEY)
+ super.dispose()
}
// Private
@@ -155,27 +145,21 @@ class ScrollSpy {
_getConfig(config) {
config = {
...Default,
+ ...Manipulator.getDataAttributes(this._element),
...(typeof config === 'object' && config ? config : {})
}
- if (typeof config.target !== 'string' && Util.isElement(config.target)) {
- let id = $(config.target).attr('id')
- if (!id) {
- id = Util.getUID(NAME)
- $(config.target).attr('id', id)
- }
+ config.target = getElement(config.target) || document.documentElement
- config.target = `#${id}`
- }
-
- Util.typeCheckConfig(NAME, config, DefaultType)
+ typeCheckConfig(NAME, config, DefaultType)
return config
}
_getScrollTop() {
return this._scrollElement === window ?
- this._scrollElement.pageYOffset : this._scrollElement.scrollTop
+ this._scrollElement.pageYOffset :
+ this._scrollElement.scrollTop
}
_getScrollHeight() {
@@ -187,7 +171,8 @@ class ScrollSpy {
_getOffsetHeight() {
return this._scrollElement === window ?
- window.innerHeight : this._scrollElement.getBoundingClientRect().height
+ window.innerHeight :
+ this._scrollElement.getBoundingClientRect().height
}
_process() {
@@ -218,8 +203,7 @@ class ScrollSpy {
for (let i = this._offsets.length; i--;) {
const isActiveTarget = this._activeTarget !== this._targets[i] &&
scrollTop >= this._offsets[i] &&
- (typeof this._offsets[i + 1] === 'undefined' ||
- scrollTop < this._offsets[i + 1])
+ (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1])
if (isActiveTarget) {
this._activate(this._targets[i])
@@ -232,62 +216,58 @@ class ScrollSpy {
this._clear()
- const queries = this._selector
- .split(',')
- .map(selector => `${selector}[data-target="${target}"],${selector}[href="${target}"]`)
+ const queries = SELECTOR_LINK_ITEMS.split(',')
+ .map(selector => `${selector}[data-bs-target="${target}"],${selector}[href="${target}"]`)
- const $link = $([].slice.call(document.querySelectorAll(queries.join(','))))
+ const link = SelectorEngine.findOne(queries.join(','), this._config.target)
- if ($link.hasClass(CLASS_NAME_DROPDOWN_ITEM)) {
- $link.closest(SELECTOR_DROPDOWN)
- .find(SELECTOR_DROPDOWN_TOGGLE)
- .addClass(CLASS_NAME_ACTIVE)
- $link.addClass(CLASS_NAME_ACTIVE)
+ link.classList.add(CLASS_NAME_ACTIVE)
+ if (link.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {
+ SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, link.closest(SELECTOR_DROPDOWN))
+ .classList.add(CLASS_NAME_ACTIVE)
} else {
- // Set triggered link as active
- $link.addClass(CLASS_NAME_ACTIVE)
- // Set triggered links parents as active
- // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
- $link.parents(SELECTOR_NAV_LIST_GROUP)
- .prev(`${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`)
- .addClass(CLASS_NAME_ACTIVE)
- // Handle special case when .nav-link is inside .nav-item
- $link.parents(SELECTOR_NAV_LIST_GROUP)
- .prev(SELECTOR_NAV_ITEMS)
- .children(SELECTOR_NAV_LINKS)
- .addClass(CLASS_NAME_ACTIVE)
+ SelectorEngine.parents(link, SELECTOR_NAV_LIST_GROUP)
+ .forEach(listGroup => {
+ // Set triggered links parents as active
+ // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
+ SelectorEngine.prev(listGroup, `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`)
+ .forEach(item => item.classList.add(CLASS_NAME_ACTIVE))
+
+ // Handle special case when .nav-link is inside .nav-item
+ SelectorEngine.prev(listGroup, SELECTOR_NAV_ITEMS)
+ .forEach(navItem => {
+ SelectorEngine.children(navItem, SELECTOR_NAV_LINKS)
+ .forEach(item => item.classList.add(CLASS_NAME_ACTIVE))
+ })
+ })
}
- $(this._scrollElement).trigger(EVENT_ACTIVATE, {
+ EventHandler.trigger(this._scrollElement, EVENT_ACTIVATE, {
relatedTarget: target
})
}
_clear() {
- [].slice.call(document.querySelectorAll(this._selector))
+ SelectorEngine.find(SELECTOR_LINK_ITEMS, this._config.target)
.filter(node => node.classList.contains(CLASS_NAME_ACTIVE))
.forEach(node => node.classList.remove(CLASS_NAME_ACTIVE))
}
// Static
- static _jQueryInterface(config) {
+ static jQueryInterface(config) {
return this.each(function () {
- let data = $(this).data(DATA_KEY)
- const _config = typeof config === 'object' && config
+ const data = ScrollSpy.getOrCreateInstance(this, config)
- if (!data) {
- data = new ScrollSpy(this, _config)
- $(this).data(DATA_KEY, data)
+ if (typeof config !== 'string') {
+ return
}
- if (typeof config === 'string') {
- if (typeof data[config] === 'undefined') {
- throw new TypeError(`No method named "${config}"`)
- }
-
- data[config]()
+ if (typeof data[config] === 'undefined') {
+ throw new TypeError(`No method named "${config}"`)
}
+
+ data[config]()
})
}
}
@@ -298,27 +278,18 @@ class ScrollSpy {
* ------------------------------------------------------------------------
*/
-$(window).on(EVENT_LOAD_DATA_API, () => {
- const scrollSpys = [].slice.call(document.querySelectorAll(SELECTOR_DATA_SPY))
- const scrollSpysLength = scrollSpys.length
-
- for (let i = scrollSpysLength; i--;) {
- const $spy = $(scrollSpys[i])
- ScrollSpy._jQueryInterface.call($spy, $spy.data())
- }
+EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
+ SelectorEngine.find(SELECTOR_DATA_SPY)
+ .forEach(spy => new ScrollSpy(spy))
})
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
+ * add .ScrollSpy to jQuery only if jQuery is present
*/
-$.fn[NAME] = ScrollSpy._jQueryInterface
-$.fn[NAME].Constructor = ScrollSpy
-$.fn[NAME].noConflict = () => {
- $.fn[NAME] = JQUERY_NO_CONFLICT
- return ScrollSpy._jQueryInterface
-}
+defineJQueryPlugin(ScrollSpy)
export default ScrollSpy