feat(lab-content-engine): phase 5 — кнопка «В лабораторию» на карточке учебника

textbooks.html: батч-запрос /api/lab/links/all?kind=textbook при загрузке ->
labLinks byRef; на карточке учебника со связанными симуляциями добавлена кнопка
«В лабораторию» (deep-link /lab?sim=<id>, openLabSim со stopPropagation, чтобы
клик не открывал учебник). (Прошлый коммит метил не ту разметку карточки — фикс.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-30 17:28:25 +03:00
parent fb6175e4a2
commit 5a7724bdbb
+17 -1
View File
@@ -454,16 +454,28 @@
return String(s || '').replace(/[&<>"']/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c]));
}
let labLinks = {}; // { textbook_slug: [{id,title,cat}] } — связанные симуляции (Фаза 5)
async function loadTextbooks() {
try {
const r = await LS.api('/api/textbooks');
const [r, labRes] = await Promise.all([
LS.api('/api/textbooks'),
LS.api('/api/lab/links/all?kind=textbook').catch(() => ({ byRef: {} })),
]);
textbooks = r.textbooks || [];
labLinks = (labRes && labRes.byRef) || {};
render();
} catch (e) {
document.getElementById('tb-grid').innerHTML = `<div class="tb-empty">Не удалось загрузить: ${esc(e.message)}</div>`;
}
}
/* Фаза 5: открыть связанную симуляцию из карточки учебника (не уходя в учебник). */
function openLabSim(simId, ev) {
if (ev) ev.stopPropagation();
location.href = '/lab?sim=' + encodeURIComponent(simId);
}
window.openLabSim = openLabSim;
function render() {
const grid = document.getElementById('tb-grid');
if (!textbooks.length) {
@@ -509,6 +521,10 @@
${isTeacher ? `<button class="tb-btn tb-assign-btn" onclick="openAssignModal('${t.slug}', '${esc(t.title)}')" title="Назначить чтение как ДЗ">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v20M2 12h20"/></svg>
</button>` : ''}
${(labLinks[t.slug] && labLinks[t.slug].length) ? `<button class="tb-btn tb-lab-btn" onclick="openLabSim('${esc(labLinks[t.slug][0].id)}', event)" title="Открыть связанную симуляцию в лаборатории">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3h6m-4.5 0v5.5l-4 7.5a1 1 0 0 0 .9 1.5h8.2a1 1 0 0 0 .9-1.5l-4-7.5V3"/></svg>
В лабораторию${labLinks[t.slug].length > 1 ? ' (' + labLinks[t.slug].length + ')' : ''}
</button>` : ''}
</div>
</div>
</article>`;