diff options
author | GeoSot <geo.sotis@gmail.com> | 2022-07-28 11:58:28 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-28 11:58:28 +0300 |
commit | db86607c088bd307aa21f4b4bd0258262262a4e4 (patch) | |
tree | 7acb80965491822be470802088d0ce85d4087e5c | |
parent | 90c50ab198a4ecffdda6a5ff10fe58cab2c816b2 (diff) |
ScrollSpy: make the threshold option configurable (#36750)
* feat(ScrollSpy): make the threshold option configurable
-rw-r--r-- | js/src/scrollspy.js | 22 | ||||
-rw-r--r-- | js/tests/unit/scrollspy.spec.js | 44 | ||||
-rw-r--r-- | site/content/docs/5.2/components/scrollspy.md | 2 |
3 files changed, 59 insertions, 9 deletions
diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index 102a2e1010..f4d6671013 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -40,14 +40,16 @@ const Default = { offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons rootMargin: '0px 0px -25%', smoothScroll: false, - target: null + target: null, + threshold: [0.1, 0.5, 1] } const DefaultType = { offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons rootMargin: 'string', smoothScroll: 'boolean', - target: 'element' + target: 'element', + threshold: 'array' } /** @@ -110,6 +112,13 @@ class ScrollSpy extends BaseComponent { // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case config.target = getElement(config.target) || document.body + // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only + config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin + + if (typeof config.threshold === 'string') { + config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value)) + } + return config } @@ -141,8 +150,8 @@ class ScrollSpy extends BaseComponent { _getNewObserver() { const options = { root: this._rootElement, - threshold: [0.1, 0.5, 1], - rootMargin: this._getRootMargin() + threshold: this._config.threshold, + rootMargin: this._config.rootMargin } return new IntersectionObserver(entries => this._observerCallback(entries), options) @@ -187,11 +196,6 @@ class ScrollSpy extends BaseComponent { } } - // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only - _getRootMargin() { - return this._config.offset ? `${this._config.offset}px 0px -30%` : this._config.rootMargin - } - _initializeTargetsAndObservables() { this._targetLinks = new Map() this._observableSections = new Map() diff --git a/js/tests/unit/scrollspy.spec.js b/js/tests/unit/scrollspy.spec.js index 2bdeb5830c..c7951e6ff1 100644 --- a/js/tests/unit/scrollspy.spec.js +++ b/js/tests/unit/scrollspy.spec.js @@ -126,6 +126,50 @@ describe('ScrollSpy', () => { expect(scrollSpy._rootElement).toBeNull() }) + it('should respect threshold option', () => { + fixtureEl.innerHTML = [ + '<ul id="navigation" class="navbar">', + ' <a class="nav-link active" id="one-link" href="#">One</a>' + + '</ul>', + '<div id="content">', + ' <div id="one-link">test</div>', + '</div>' + ].join('') + + const scrollSpy = new ScrollSpy('#content', { + target: '#navigation', + threshold: [1] + }) + + expect(scrollSpy._observer.thresholds).toEqual([1]) + }) + + it('should respect threshold option markup', () => { + fixtureEl.innerHTML = [ + '<ul id="navigation" class="navbar">', + ' <a class="nav-link active" id="one-link" href="#">One</a>' + + '</ul>', + '<div id="content" data-bs-threshold="0,0.2,1">', + ' <div id="one-link">test</div>', + '</div>' + ].join('') + + const scrollSpy = new ScrollSpy('#content', { + target: '#navigation' + }) + + // See https://stackoverflow.com/a/45592926 + const expectToBeCloseToArray = (actual, expected) => { + expect(actual.length).toBe(expected.length) + for (const x of actual) { + const i = actual.indexOf(x) + expect(x).withContext(`[${i}]`).toBeCloseTo(expected[i]) + } + } + + expectToBeCloseToArray(scrollSpy._observer.thresholds, [0, 0.2, 1]) + }) + it('should not take count to not visible sections', () => { fixtureEl.innerHTML = [ '<nav id="navigation" class="navbar">', diff --git a/site/content/docs/5.2/components/scrollspy.md b/site/content/docs/5.2/components/scrollspy.md index 5e329dc85a..b2461f0dae 100644 --- a/site/content/docs/5.2/components/scrollspy.md +++ b/site/content/docs/5.2/components/scrollspy.md @@ -380,6 +380,8 @@ const scrollSpy = new bootstrap.ScrollSpy(document.body, { | `rootMargin` | string | `0px 0px -40%` | Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/rootMargin) valid units, when calculating scroll position. | | `smoothScroll` | boolean | `false` | Enables smooth scrolling when a user clicks on a link that refers to ScrollSpy observables. | | `target` | string \| jQuery object \| DOM element | | Specifies element to apply Scrollspy plugin. | +| `threshold` | array | `[0.1, 0.5, 1]` | `IntersectionObserver` [threshold](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver#threshold) valid input, when calculating scroll position.| + {{< /bs-table >}} {{< callout warning >}} |