preserve scroll position when entering page editor
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
<script src="/_/modal.js"></script>
|
<script src="/_/modal.js"></script>
|
||||||
<script src="/_/global-shortcuts.js"></script>
|
<script src="/_/global-shortcuts.js"></script>
|
||||||
<script src="/_/history-nav.js"></script>
|
<script src="/_/history-nav.js"></script>
|
||||||
|
<script src="/_/scroll-sync.js" defer></script>
|
||||||
<script src="/_/search-suggest.js" defer></script>
|
<script src="/_/search-suggest.js" defer></script>
|
||||||
<script src="/_/tree-picker.js"></script>
|
<script src="/_/tree-picker.js"></script>
|
||||||
<script src="/_/companion.js" defer></script>
|
<script src="/_/companion.js" defer></script>
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// Roughly preserve reading position when entering the editor.
|
||||||
|
//
|
||||||
|
// While reading a page we record how far the center column is scrolled (as a
|
||||||
|
// fraction of its scrollable height, keyed by path). When the same path opens
|
||||||
|
// in the editor we restore that fraction, so you land near where you were
|
||||||
|
// reading instead of at the top. It is fraction-based — the rendered page and
|
||||||
|
// the raw-markdown editor have different heights — so the match is deliberately
|
||||||
|
// approximate. This only moves the viewport; the caret default (end of doc) is
|
||||||
|
// unchanged, so a click still decides where you actually edit.
|
||||||
|
(function () {
|
||||||
|
var center = document.querySelector('.center');
|
||||||
|
if (!center) return;
|
||||||
|
|
||||||
|
var key = 'scrollsync:' + location.pathname;
|
||||||
|
// Only restore a freshly-recorded position: a stale entry from earlier in
|
||||||
|
// the tab session would jump a direct ?edit open to the wrong place.
|
||||||
|
var MAX_AGE_MS = 5 * 60 * 1000;
|
||||||
|
var params = new URLSearchParams(location.search);
|
||||||
|
var inEditor = params.has('edit');
|
||||||
|
// Section / insert edits load only a slice of the document into the editor,
|
||||||
|
// so a whole-page reading fraction does not map onto them — restore only for
|
||||||
|
// a full-page ?edit.
|
||||||
|
var fullPageEdit = inEditor && !params.has('section') && !params.has('insert_before');
|
||||||
|
|
||||||
|
function maxScroll() { return Math.max(0, center.scrollHeight - center.clientHeight); }
|
||||||
|
|
||||||
|
if (inEditor) {
|
||||||
|
if (!fullPageEdit) return;
|
||||||
|
var raw = sessionStorage.getItem(key);
|
||||||
|
if (!raw) return;
|
||||||
|
var data;
|
||||||
|
try { data = JSON.parse(raw); } catch (e) { return; }
|
||||||
|
if (!data || typeof data.f !== 'number' || Date.now() - (data.t || 0) > MAX_AGE_MS) return;
|
||||||
|
// Wait for CodeMirror to mount and the column to reach full height, then
|
||||||
|
// map the fraction onto it. A double rAF after load lets CM's initial
|
||||||
|
// layout and focus scroll settle so ours wins.
|
||||||
|
window.addEventListener('load', function () {
|
||||||
|
requestAnimationFrame(function () {
|
||||||
|
requestAnimationFrame(function () {
|
||||||
|
center.scrollTop = data.f * maxScroll();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reading mode: keep the latest scroll fraction recorded (throttled to one
|
||||||
|
// write per frame) so it is ready the moment the editor opens.
|
||||||
|
var pending = false;
|
||||||
|
center.addEventListener('scroll', function () {
|
||||||
|
if (pending) return;
|
||||||
|
pending = true;
|
||||||
|
requestAnimationFrame(function () {
|
||||||
|
pending = false;
|
||||||
|
var m = maxScroll();
|
||||||
|
try {
|
||||||
|
sessionStorage.setItem(key, JSON.stringify({ f: m > 0 ? center.scrollTop / m : 0, t: Date.now() }));
|
||||||
|
} catch (e) {}
|
||||||
|
});
|
||||||
|
}, { passive: true });
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user