style/security: эмодзи→SVG, safeUrl в ассистенте, prefs в localStorage (Спринт3)
- Убраны эмодзи (правило: только inline SVG .ic): classes.html 🃏→layers, collection-rb.html ⭐→star, pet.html 😋/😢→текст (textContent не держит SVG). - assistant.js: safeUrl() на динамических href (FAQ/поиск/RAG/правила) — блокирует javascript:/data:, пропускает /… и https://…. - LS.prefs: персистентность через localStorage (раньше sync был отключён, настройки терялись при перезагрузке). Грузим синхронно + flush на pagehide. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -960,28 +960,17 @@ async function biochemSavePathwayProgress(pathway,step,completed){ return req('P
|
||||
const _prefsCache = {};
|
||||
let _prefsDirty = false;
|
||||
let _prefsTimer = null;
|
||||
const _PREFS_LS_KEY = 'ls_prefs';
|
||||
|
||||
// SYNC DISABLED (debug mode) — раскомментировать для включения синхронизации
|
||||
async function _prefsLoad() { /* disabled */ }
|
||||
function _prefsFlush() { /* disabled */ }
|
||||
|
||||
// async function _prefsLoad() {
|
||||
// if (!isLoggedIn()) return;
|
||||
// try {
|
||||
// const data = await apiFetch('/api/preferences', { method: 'GET' });
|
||||
// Object.assign(_prefsCache, data);
|
||||
// } catch (e) {}
|
||||
// }
|
||||
//
|
||||
// function _prefsFlush() {
|
||||
// if (!_prefsDirty) return;
|
||||
// _prefsDirty = false;
|
||||
// if (!isLoggedIn()) return;
|
||||
// apiFetch('/api/preferences', {
|
||||
// method: 'PATCH',
|
||||
// body: JSON.stringify(_prefsCache),
|
||||
// }).catch(() => {});
|
||||
// }
|
||||
// Персистентность настроек — в localStorage (per-device). Раньше sync был отключён,
|
||||
// и настройки молча терялись при перезагрузке. Грузим синхронно сразу при загрузке api.js.
|
||||
try { const raw = localStorage.getItem(_PREFS_LS_KEY); if (raw) Object.assign(_prefsCache, JSON.parse(raw)); } catch (e) {}
|
||||
async function _prefsLoad() { try { const raw = localStorage.getItem(_PREFS_LS_KEY); if (raw) Object.assign(_prefsCache, JSON.parse(raw)); } catch (e) {} }
|
||||
function _prefsFlush() {
|
||||
if (!_prefsDirty) return;
|
||||
_prefsDirty = false;
|
||||
try { localStorage.setItem(_PREFS_LS_KEY, JSON.stringify(_prefsCache)); } catch (e) {}
|
||||
}
|
||||
|
||||
const lsPrefs = {
|
||||
get(key, def) {
|
||||
@@ -1442,6 +1431,7 @@ function connectSSE(onEvent) {
|
||||
window.addEventListener('pagehide', () => {
|
||||
if (_sseShared) { _sseShared.close(); _sseShared = null; }
|
||||
_sseListeners.clear();
|
||||
try { lsPrefs.flush(); } catch (e) {}
|
||||
});
|
||||
|
||||
/* ── assignment templates ─────────────────────────────────────────────────── */
|
||||
|
||||
Reference in New Issue
Block a user