Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,38 @@ public void refreshPageContents() {
}


/**
* Issue #626: capture the current scroll position into a
* window-scoped variable so a follow-up content swap can restore it.
* Pair with {@link #restoreScrollPosition()} called once the new
* body HTML has been rendered.
*/
public void saveScrollPosition() {
runJavascript("window.__awfulSavedScroll = window.scrollY;");
}

/**
* Restore a previously captured scroll position. Safe to call before
* the DOM has finished settling, the JS uses requestAnimationFrame
* to retry until the document height covers the saved offset.
*/
public void restoreScrollPosition() {
runJavascript(
"(function(){" +
"var target = window.__awfulSavedScroll;" +
"if (target == null) { return; }" +
"function tryScroll() {" +
"if (document.documentElement.scrollHeight >= target) {" +
"window.scrollTo({top: target});" +
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

window.scrollTo({top: target}) uses the options-object overload, which isn’t supported on older Chromium-based Android WebViews (minSdk 24 can still be on an older WebView). If unsupported, this will throw and abort the restore. Prefer the legacy signature (scrollTo(0, target)) or feature-detect before using the options overload.

Suggested change
"window.scrollTo({top: target});" +
"window.scrollTo(0, target);" +

Copilot uses AI. Check for mistakes.
"} else {" +
"window.requestAnimationFrame(tryScroll);" +
"}" +
Comment on lines +195 to +200
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The height check is using document.documentElement.scrollHeight >= target, but target is a scrollTop value; the maximum reachable scrollTop is scrollHeight - clientHeight. This can cause (a) scrolling to happen too early and get clamped below target with no retries, or (b) the retry loop to run forever if the new document never becomes tall enough. Consider checking scrollHeight - clientHeight >= target and/or verifying window.scrollY reached target, with a bounded retry/fallback (e.g., scroll to bottom after N frames).

Suggested change
"function tryScroll() {" +
"if (document.documentElement.scrollHeight >= target) {" +
"window.scrollTo({top: target});" +
"} else {" +
"window.requestAnimationFrame(tryScroll);" +
"}" +
"var attempts = 0;" +
"var maxAttempts = 60;" +
"function tryScroll() {" +
"var doc = document.documentElement;" +
"var maxScrollTop = Math.max(0, doc.scrollHeight - doc.clientHeight);" +
"if (maxScrollTop >= target) {" +
"window.scrollTo({top: target});" +
"if (window.scrollY >= target || attempts >= maxAttempts) { return; }" +
"} else if (attempts >= maxAttempts) {" +
"window.scrollTo({top: maxScrollTop});" +
"return;" +
"}" +
"attempts++;" +
"window.requestAnimationFrame(tryScroll);" +

Copilot uses AI. Check for mistakes.
"}" +
"tryScroll();" +
"})();");
Comment on lines +193 to +203
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a successful restore, window.__awfulSavedScroll is left set. That makes subsequent restores (or other pages using the same WebView) potentially apply a stale offset unexpectedly. Clearing the saved value once it has been applied would make the helper safer to use.

Copilot uses AI. Check for mistakes.
}


/**
* Set and display the current HTML for the container body.
* <p>
Expand Down
Loading