Dash-math_Database / assets /session_state.js
Mochi0622's picture
initial deploy
e66cfb4
Raw
History Blame Contribute Delete
6.02 kB
/**
* session_state.js
* 事件驅動版,不做定時掃描,只在互動時儲存。
*/
(function () {
"use strict";
var STORE_KEY = "dash_math_page_state";
function loadState() {
try { return JSON.parse(sessionStorage.getItem(STORE_KEY) || "{}"); }
catch (e) { return {}; }
}
function saveState(s) {
try { sessionStorage.setItem(STORE_KEY, JSON.stringify(s)); }
catch (e) {}
}
function getPathname() { return window.location.pathname || "/"; }
function saveProp(key, value) {
var s = loadState(), p = getPathname();
if (!s[p]) s[p] = {};
s[p][key] = value;
saveState(s);
}
function saveNested(group, key, value) {
var s = loadState(), p = getPathname();
if (!s[p]) s[p] = {};
if (!s[p][group]) s[p][group] = {};
s[p][group][key] = value;
saveState(s);
}
function getPs() {
var s = loadState(), p = getPathname();
return s[p] || {};
}
// ── 恢復 ──────────────────────────────────────────────────────────────
var _restoring = false;
function restoreState() {
var ps = getPs();
_restoring = true;
// Section
if (ps.section) {
var b = document.querySelector('[data-sid="' + ps.section + '"]');
if (b) b.click();
}
// 填空題
var inputs = ps.quiz_inputs || {};
Object.keys(inputs).forEach(function (qid) {
var val = inputs[qid];
if (!val) return;
// 用 querySelectorAll 找包含此 qid 的 input
document.querySelectorAll("input").forEach(function (el) {
var w = el.closest("[id]");
if (!w || w.id.indexOf(qid) === -1 || w.id.indexOf("quiz-input") === -1) return;
var setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
setter.call(el, val);
el.dispatchEvent(new Event("input", { bubbles: true }));
});
});
// 解法展開
var solutions = ps.solutions || {};
Object.keys(solutions).forEach(function (key) {
if (!solutions[key]) return;
document.querySelectorAll("button").forEach(function (btn) {
if (btn.id && btn.id.indexOf(key) > -1 && btn.id.indexOf("solution-toggle") > -1) {
btn.click();
}
});
});
setTimeout(function () { _restoring = false; }, 800);
}
// ── 掛載監聽 ─────────────────────────────────────────────────────────
var _attached = new Set();
function attachListeners() {
// Section 按鈕
document.querySelectorAll("[data-sid]").forEach(function (btn) {
var sid = btn.getAttribute("data-sid");
if (_attached.has("s:" + sid)) return;
_attached.add("s:" + sid);
btn.addEventListener("click", function () {
if (!_restoring) saveProp("section", sid);
});
});
// 填空題 input
document.querySelectorAll("input").forEach(function (el) {
if (_attached.has(el)) return;
var w = el.closest("[id]");
if (!w || !w.id || w.id.indexOf("quiz-input") === -1) return;
var m = w.id.match(/"qid":"([^"]+)"/);
if (!m) return;
var qid = m[1];
_attached.add(el);
el.addEventListener("change", function () {
if (!_restoring) saveNested("quiz_inputs", qid, el.value);
});
});
// 解法 toggle 按鈕
document.querySelectorAll("button").forEach(function (btn) {
if (_attached.has(btn)) return;
if (!btn.id || btn.id.indexOf("solution-toggle") === -1) return;
var m = btn.id.match(/"key":"([^"]+)"/);
if (!m) return;
var key = m[1];
_attached.add(btn);
btn.addEventListener("click", function () {
if (_restoring) return;
// 延遲判斷是否展開
setTimeout(function () {
var col = document.querySelector('[id*="' + key + '"][id*="solution-collapse"]');
var opened = col ? col.offsetHeight > 10 : false;
saveNested("solutions", key, opened);
}, 400);
});
});
}
// ── 換頁偵測 ─────────────────────────────────────────────────────────
var _lastPath = null, _timer = null;
function checkPath() {
var cur = getPathname();
if (cur !== _lastPath) {
_lastPath = cur;
_attached.clear();
clearTimeout(_timer);
_timer = setTimeout(function () {
attachListeners();
restoreState();
}, 900);
} else {
attachListeners();
}
}
// MutationObserver:只做 debounce checkPath,不掃描整個 DOM
var _mutTimer = null;
var obs = new MutationObserver(function () {
clearTimeout(_mutTimer);
_mutTimer = setTimeout(checkPath, 200);
});
function init() {
_lastPath = getPathname();
obs.observe(document.body, { childList: true, subtree: false }); // subtree:false 減少觸發
setTimeout(function () {
attachListeners();
restoreState();
}, 1000);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();