- drag & drop now saves in the background (700 ms debounce) without reloading: sections stay open, scroll position is kept; on failure it retries every 3 s, and navigator.sendBeacon flushes unsaved changes on page leave - removed the explicit save button (autosave only), status indicator shows «Изменения не сохранены… / Сохранение… / Порядок сохранён» - new global ui-state.js: restores open <details> and scroll position after any reload/redirect within the same page (applies to all pages, not just /learn) - auto-expand a collapsed chapter/section while hovering during drag
60 lines
2.3 KiB
JavaScript
60 lines
2.3 KiB
JavaScript
/* Состояние страницы при перезагрузке: открытые <details> и позиция прокрутки.
|
||
Нужно, чтобы после сохранения формы или перерисовки страница возвращалась
|
||
туда же, а не «схлопывала» разделы и не сбрасывала прокрутку в начало. */
|
||
(function () {
|
||
var KEY = 'lms-ui-state';
|
||
|
||
function keyOf(element, index) {
|
||
return element.getAttribute('data-chapter-id')
|
||
|| element.getAttribute('data-section-id')
|
||
|| element.id
|
||
|| ('details-' + index);
|
||
}
|
||
|
||
function currentUrl() {
|
||
return location.pathname + location.search;
|
||
}
|
||
|
||
function save() {
|
||
var open = [];
|
||
document.querySelectorAll('details').forEach(function (element, index) {
|
||
if (element.open) open.push(keyOf(element, index));
|
||
});
|
||
try {
|
||
sessionStorage.setItem(KEY, JSON.stringify({
|
||
url: currentUrl(),
|
||
y: window.scrollY || window.pageYOffset || 0,
|
||
open: open
|
||
}));
|
||
} catch (e) { /* приватный режим — просто пропускаем */ }
|
||
}
|
||
|
||
function restore() {
|
||
var raw;
|
||
try {
|
||
raw = sessionStorage.getItem(KEY);
|
||
if (raw) sessionStorage.removeItem(KEY);
|
||
} catch (e) { return; }
|
||
if (!raw) return;
|
||
|
||
var state;
|
||
try { state = JSON.parse(raw); } catch (e) { return; }
|
||
// состояние применяем только при возврате на ту же страницу (перезагрузка/redirect)
|
||
if (!state || state.url !== currentUrl()) return;
|
||
|
||
var open = state.open || [];
|
||
document.querySelectorAll('details').forEach(function (element, index) {
|
||
if (open.indexOf(keyOf(element, index)) >= 0) element.open = true;
|
||
});
|
||
|
||
if (typeof state.y === 'number' && state.y > 0) {
|
||
var y = state.y;
|
||
requestAnimationFrame(function () { window.scrollTo(0, y); });
|
||
setTimeout(function () { window.scrollTo(0, y); }, 80);
|
||
}
|
||
}
|
||
|
||
window.addEventListener('beforeunload', save);
|
||
document.addEventListener('DOMContentLoaded', restore);
|
||
})();
|