From 5eddb0b0fdfd7215d5764c5315ce7f0be4ca3d83 Mon Sep 17 00:00:00 2001 From: Rob Ruana Date: Sun, 27 Nov 2016 16:20:33 -0800 Subject: [PATCH] Closes #21055: Prevents ScrollSpy from clearing active item when Safari rubberbands (#21056) When the rubberband effect causes Safari to scroll past the top of the page, the value of scrollTop becomes negative. If the offset of the first ScrollSpy target is 0 - essentially if the target is at the top of the page - then ScrollSpy should not clear the active item. Conceptually, the first item should remain active when rubberbanding past the top of the page. This commit fixes issue #21055 by verifying the first scrollspy target is not at the top of the page before clearing the active nav-item. --- js/src/scrollspy.js | 2 +- js/tests/unit/scrollspy.js | 44 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index 9b39acd362..9cb1438ca7 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -221,7 +221,7 @@ const ScrollSpy = (($) => { return } - if (this._activeTarget && scrollTop < this._offsets[0]) { + if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { this._activeTarget = null this._clear() return diff --git a/js/tests/unit/scrollspy.js b/js/tests/unit/scrollspy.js index a349b5337e..877ec67a2a 100644 --- a/js/tests/unit/scrollspy.js +++ b/js/tests/unit/scrollspy.js @@ -287,6 +287,50 @@ $(function () { .scrollTop(201) }) + QUnit.test('should NOT clear selection if above the first section and first section is at the top', function (assert) { + assert.expect(4) + var done = assert.async() + + var sectionHTML = '' + + '' + $(sectionHTML).appendTo('#qunit-fixture') + + var negativeHeight = -10 + var startOfSectionTwo = 101 + + var scrollspyHTML = '
' + + '
' + + '
' + + '
' + + '
' + + '
' + var $scrollspy = $(scrollspyHTML).appendTo('#qunit-fixture') + + $scrollspy + .bootstrapScrollspy({ + target: '#navigation', + offset: $scrollspy.position().top + }) + .one('scroll', function () { + assert.strictEqual($('.active').length, 1, '"active" class on only one element present') + assert.strictEqual($('.active').is('#two-link'), true, '"active" class on second section') + $scrollspy + .one('scroll', function () { + assert.strictEqual($('.active').length, 1, '"active" class on only one element present') + assert.strictEqual($('.active').is('#one-link'), true, '"active" class on first section') + done() + }) + .scrollTop(negativeHeight) + }) + .scrollTop(startOfSectionTwo) + }) + QUnit.test('should correctly select navigation element on backward scrolling when each target section height is 100%', function (assert) { assert.expect(5) var navbarHtml =