Update assets/js/offline-engine.js

This commit is contained in:
2026-06-16 10:56:29 +02:00
parent 1c5cd257b7
commit 939de60914
+80 -94
View File
@@ -1,91 +1,113 @@
import { getDB } from './db.js'; import { getDB } from './db.js';
function getStore(storeName, mode = 'readonly') { /**
* HELPERS
*/
function store(storeName, mode = 'readonly') {
const db = getDB(); const db = getDB();
const tx = db.transaction(storeName, mode); const tx = db.transaction(storeName, mode);
return tx.objectStore(storeName); return tx.objectStore(storeName);
} }
export async function saveWords(lang, list, words) { /**
* IMPORT WORD LIST FROM SERVER → INDEXEDDB
*/
export async function importList(lang, list) {
const store = getStore('words', 'readwrite'); const res = await fetch(`/api/list.php?lang=${lang}&list=${list}`);
const data = await res.json();
for (const word of words) { if (!data.words || !Array.isArray(data.words)) {
console.error("Import failed:", data);
return;
}
store.put({ const s = store('words', 'readwrite');
data.words.forEach(word => {
s.put({
key: `${lang}:${list}:${word.id}`, key: `${lang}:${list}:${word.id}`,
id: word.id,
lang, lang,
list, list,
...word question: word.question,
answer: word.answer,
correct: word.correct || 0,
wrong: word.wrong || 0,
nextReview: word.nextReview || null,
interval: word.interval || 1
}); });
} });
console.log(`Imported ${data.words.length} words`);
} }
/**
* GET WORDS
*/
export async function getWords(lang, list) { export async function getWords(lang, list) {
return new Promise((resolve) => { return new Promise((resolve) => {
const store = getStore('words'); const s = store('words');
const req = store.getAll(); const req = s.getAll();
req.onsuccess = () => { req.onsuccess = () => {
const result = req.result.filter( const filtered = req.result.filter(
w => w.lang === lang && w.list === list w => w.lang === lang && w.list === list
); );
resolve(result); resolve(filtered);
}; };
}); });
} }
/**
* GET NEXT WORD (SRS SIMPLE)
*/
export async function getNextWord(lang, list) { export async function getNextWord(lang, list) {
const words = await getWords(lang, list); const words = await getWords(lang, list);
if (!words.length) { if (!words.length) {
console.warn("No words in IndexedDB");
return null; return null;
} }
const today = new Date().toISOString().split('T')[0]; const today = new Date().toISOString().split('T')[0];
let due = words.filter(word => { let due = words.filter(w =>
return !word.nextReview || !w.nextReview || w.nextReview <= today
word.nextReview <= today; );
});
if (!due.length) { if (!due.length) {
due = words; due = words;
} }
const random = return due[Math.floor(Math.random() * due.length)];
Math.floor(Math.random() * due.length);
return due[random];
} }
export async function answerWord(word, answer) { /**
* ANSWER WORD
*/
export async function answerWord(word, input) {
const correct = const correct =
word.answer.trim().toLowerCase() === word.answer.trim().toLowerCase() ===
answer.trim().toLowerCase(); input.trim().toLowerCase();
const store = const s = store('words', 'readwrite');
getStore('words', 'readwrite');
const updated = { ...word }; const updated = { ...word };
if (correct) { if (correct) {
const days = updated.correct++;
updated.interval
? updated.interval * 2
: 1;
const days = updated.interval * 2;
updated.interval = days; updated.interval = days;
const d = new Date(); const d = new Date();
@@ -96,6 +118,8 @@ export async function answerWord(word, answer) {
} else { } else {
updated.wrong++;
updated.interval = 1; updated.interval = 1;
const d = new Date(); const d = new Date();
@@ -105,38 +129,29 @@ export async function answerWord(word, answer) {
d.toISOString().split('T')[0]; d.toISOString().split('T')[0];
} }
store.put(updated); s.put(updated);
await updateSessionStats(correct); updateSessionStats(correct);
await queueSync({ queueSync({
wordId: word.id, wordId: word.id,
lang: word.lang, lang: word.lang,
list: word.list, list: word.list,
correct, correct,
timestamp: Date.now() ts: Date.now()
}); });
return { return { correct };
correct
};
} }
async function queueSync(item) { /**
* SESSION STATS
*/
export function updateSessionStats(correct) {
const store = const s = store('session', 'readwrite');
getStore('sync_queue', 'readwrite');
store.add(item); const req = s.get('stats');
}
export async function updateSessionStats(correct) {
const store =
getStore('session', 'readwrite');
const req =
store.get('stats');
req.onsuccess = () => { req.onsuccess = () => {
@@ -150,13 +165,10 @@ export async function updateSessionStats(correct) {
}; };
} }
if (correct) { if (correct) stats.correct++;
stats.correct++; else stats.wrong++;
} else {
stats.wrong++;
}
store.put(stats); s.put(stats);
}; };
} }
@@ -164,51 +176,25 @@ export async function getSessionStats() {
return new Promise(resolve => { return new Promise(resolve => {
const store = const s = store('session');
getStore('session');
const req = const req = s.get('stats');
store.get('stats');
req.onsuccess = () => { req.onsuccess = () => {
resolve( resolve(req.result || {
req.result || { correct: 0,
correct: 0, wrong: 0
wrong: 0 });
}
);
}; };
}); });
} }
export async function resetSessionStats() { /**
* SYNC QUEUE
*/
function queueSync(item) {
const store = const s = store('sync_queue', 'readwrite');
getStore('session', 'readwrite'); s.add(item);
store.put({
key: 'stats',
correct: 0,
wrong: 0
});
}
import { saveWords } from './offline-engine.js';
export async function importList(lang, list) {
const res = await fetch(
`/api/list.php?lang=${lang}&list=${list}`
);
const data = await res.json();
if (!data.words) {
throw new Error('No words');
}
await saveWords(lang, list, data.words);
return data.words.length;
} }