diff --git a/toolkit/components/reader/AboutReader.sys.mjs b/toolkit/components/reader/AboutReader.sys.mjs index 2faff52e6ce5..6b1c28c22830 100644 --- a/toolkit/components/reader/AboutReader.sys.mjs +++ b/toolkit/components/reader/AboutReader.sys.mjs @@ -7,6 +7,7 @@ import { ReaderMode } from "resource://gre/modules/ReaderMode.sys.mjs"; import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; const lazy = {}; +let gScrollPositions = new Map(); ChromeUtils.defineESModuleGetters(lazy, { AsyncPrefs: "resource://gre/modules/AsyncPrefs.sys.mjs", @@ -419,6 +420,7 @@ AboutReader.prototype = { case "pagehide": this._closeDropdowns(); + this._saveScrollPosition(); this._actor.readerModeHidden(); this.clearActor(); @@ -1016,6 +1018,7 @@ AboutReader.prototype = { this._doc.body.classList.add("loaded"); this._goToReference(articleUri.ref); + this._getScrollPosition(); Services.obs.notifyObservers(this._win, "AboutReader:Ready"); @@ -1276,4 +1279,41 @@ AboutReader.prototype = { } } }, + + _scrollToSavedPosition(pos) { + this._win.scrollTo({ + top: pos, + left: 0, + behavior: "auto", + }); + gScrollPositions.delete(this._win.location.href); + }, + + /* + * Save reader view vertical scroll position + */ + _saveScrollPosition() { + let scrollTop = this._doc.documentElement.scrollTop; + gScrollPositions.set(this._win.location.href, scrollTop); + }, + + /* + * Scroll reader view to a saved position + */ + _getScrollPosition() { + let scrollPosition = gScrollPositions.get(this._win.location.href); + if (scrollPosition !== undefined) { + if (this._doc.readyState == "complete") { + this._scrollToSavedPosition(scrollPosition); + } else { + this._win.addEventListener( + "load", + () => { + this._scrollToSavedPosition(scrollPosition); + }, + { once: true } + ); + } + } + }, }; diff --git a/toolkit/components/reader/test/browser.toml b/toolkit/components/reader/test/browser.toml index e3816c733b8a..9382e6d60f27 100644 --- a/toolkit/components/reader/test/browser.toml +++ b/toolkit/components/reader/test/browser.toml @@ -12,6 +12,9 @@ support-files = [ "setSameSiteCookie.html^headers^", ] +["browser_bug1780350_readerModeSaveScroll.js"] +support-files = ["readerModeArticleContainsLink.html"] + ["browser_drag_url_readerMode.js"] support-files = ["readerModeArticle.html"] diff --git a/toolkit/components/reader/test/browser_bug1780350_readerModeSaveScroll.js b/toolkit/components/reader/test/browser_bug1780350_readerModeSaveScroll.js new file mode 100644 index 000000000000..76add5511eda --- /dev/null +++ b/toolkit/components/reader/test/browser_bug1780350_readerModeSaveScroll.js @@ -0,0 +1,70 @@ +/* eslint-disable @microsoft/sdl/no-insecure-url */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const TEST_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); + +// This test verifies that when a link is clicked from +// within reader view, when navigating back to reader view +// the previous scroll position of the page is restored. +add_task(async function test_save_scroll_position() { + await BrowserTestUtils.withNewTab( + TEST_PATH + "readerModeArticleContainsLink.html", + async function (browser) { + let pageShownPromise = BrowserTestUtils.waitForContentEvent( + browser, + "AboutReaderContentReady" + ); + let browserLoadedPromise = BrowserTestUtils.browserLoaded(browser); + let readerButton = document.getElementById("reader-mode-button"); + readerButton.click(); + await Promise.all([pageShownPromise, browserLoadedPromise]); + let scrollEventPromise = BrowserTestUtils.waitForContentEvent( + browser, + "scroll", + true + ); + // Set scroll position in reader to 200px down. + await SpecialPowers.spawn(browser, [], async function () { + content.document.documentElement.scrollTop = 200; + }); + await scrollEventPromise; + + // Click linked page and check that scroll pos resets. + await SpecialPowers.spawn(browser, [], async function () { + let linkElement = content.document.getElementById("link"); + linkElement.click(); + }); + await BrowserTestUtils.browserLoaded(browser); + await SpecialPowers.spawn(browser, [], async function () { + is( + content.document.documentElement.scrollTop, + 0, + "vertical scroll position should reset to zero when navigating to linked page." + ); + content.window.history.back(); + }); + + // Navigate back to reader and check that scroll position is restored. + await BrowserTestUtils.browserLoaded(browser); + scrollEventPromise = BrowserTestUtils.waitForContentEvent( + browser, + "scroll", + true + ); + await scrollEventPromise; + await SpecialPowers.spawn(browser, [], async function () { + let doc = content.document; + is( + doc.documentElement.scrollTop, + 200, + "should restore saved scroll position when navigating back from link." + ); + }); + } + ); +}); diff --git a/toolkit/components/reader/test/readerModeArticleContainsLink.html b/toolkit/components/reader/test/readerModeArticleContainsLink.html new file mode 100644 index 000000000000..871349adcdcb --- /dev/null +++ b/toolkit/components/reader/test/readerModeArticleContainsLink.html @@ -0,0 +1,20 @@ + + +
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.
+Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.
+Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.
+ +Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.
+Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.
+