feat(flashcards): картинки в массовом импорте «Добавить список»

- модалка в 2 шага: текст -> предпросмотр карточек, к каждой стороне
  можно прикрепить картинку перед импортом
- addCardsBulk принимает front_image/back_image (через safeImg) и теперь
  санитизит front/back (stripTags) — раньше bulk пропускал теги
- общий ensureImgPicker() переиспользуется редактором и предпросмотром

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-02 13:14:13 +03:00
parent da5e95bdaf
commit 51e5dc29e1
2 changed files with 139 additions and 24 deletions
@@ -125,12 +125,16 @@ function addCardsBulk(req, res) {
if (!Array.isArray(cards) || !cards.length) return res.status(400).json({ error: 'cards[] required' });
const maxIdx = db.prepare(`SELECT MAX(order_idx) AS m FROM flashcard_cards WHERE deck_id = ?`)
.get(deck.id)?.m ?? -1;
const stmt = db.prepare(`INSERT INTO flashcard_cards (deck_id, front, back, order_idx) VALUES (?,?,?,?)`);
const stmt = db.prepare(`INSERT INTO flashcard_cards (deck_id, front, back, front_image, back_image, order_idx) VALUES (?,?,?,?,?,?)`);
const inserted = [];
const ins = db.transaction(() => {
cards.forEach((c, i) => {
const r = stmt.run(deck.id, c.front || '', c.back || '', maxIdx + 1 + i);
inserted.push({ id: r.lastInsertRowid, front: c.front, back: c.back });
const front = stripTags((c.front || '').slice(0, 5000));
const back = stripTags((c.back || '').slice(0, 5000));
const fImg = safeImg(c.front_image);
const bImg = safeImg(c.back_image);
const r = stmt.run(deck.id, front, back, fImg, bImg, maxIdx + 1 + i);
inserted.push({ id: r.lastInsertRowid, front, back, front_image: fImg, back_image: bImg });
});
});
ins();