/* chem7_ch1_widgets.js — интерактивы главы 1 «Первоначальные химические понятия» (Химия 7). * Монтируются движком chem8_engine.js: window.CHEM8_WIDGETS[id] / window.FLAG_MOUNTS[id]. * Используют window.Chem8 (chem8_svg.js): molarMass, elementCounts, arOf, fmt, equationBalancer. * Без эмоджи; KaTeX-рендер — через window.chem8RenderMath. */ (function (W) { 'use strict'; function C() { return W.Chem8 || {}; } function $(id) { return document.getElementById(id); } function esc(s){ return String(s).replace(/&/g,'&').replace(//g,'>'); } /* ── общий мини-классификатор: чипы → 2 корзины ──────────────────── */ function classifier(mount, opts) { if (!mount || mount._built) return; mount._built = 1; var items = opts.items.slice(); // {t, b} t=подпись, b=индекс корзины var buckets = opts.buckets; // [name0, name1] var placed = {}; // idx -> bucket var pool = items.map(function (it, i) { return i; }); function colorOf(ok){ return ok ? '#059669' : '#dc2626'; } function render() { var chips = pool.map(function (i) { return ''; }).join('') || 'Все карточки распределены.'; var cols = buckets.map(function (name, bi) { var inb = Object.keys(placed).filter(function (k) { return placed[k] === bi; }); var cells = inb.map(function (k) { var ok = items[k].b === bi; return '
' + esc(items[k].t) + (ok ? ' ✓' : ' ✗') + '
'; }).join('') || '
перетащите сюда…
'; return '
' + esc(name) + '
' + cells + '
'; }).join(''); mount.innerHTML = '
' + chips + '
' + cols + '
' + '
Кликни карточку, затем — корзину. Зелёный — верно, красный — ошибка.
'; bind(); } var sel = null; function bind() { mount.querySelectorAll('.c7-chip').forEach(function (b) { b.addEventListener('click', function () { mount.querySelectorAll('.c7-chip').forEach(function (x) { x.style.outline = ''; }); sel = +b.dataset.i; b.style.outline = '2px solid var(--pri)'; }); }); mount.querySelectorAll('.c7-bucket').forEach(function (col) { col.addEventListener('click', function () { if (sel == null) return; placed[sel] = +col.dataset.b; pool = pool.filter(function (x) { return x !== sel; }); sel = null; render(); }); }); } render(); } /* §1 — классификатор «тело / вещество» */ function mount_p1() { var m = $('p1-cls'); if (!m) return; classifier(m, { buckets: ['Физическое тело', 'Вещество'], items: [ { t: 'стакан', b: 0 }, { t: 'вода', b: 1 }, { t: 'гвоздь', b: 0 }, { t: 'железо', b: 1 }, { t: 'ложка', b: 0 }, { t: 'сахар', b: 1 }, { t: 'медь', b: 1 }, { t: 'линейка', b: 0 } ] }); } /* §2 / ПР1 — разделитель смесей: выбери метод для смеси */ var MIX = [ { mix: 'Песок и вода', method: 'Фильтрование', why: 'Песок не растворяется — задерживается фильтром, вода проходит.' }, { mix: 'Соль и вода', method: 'Выпаривание', why: 'Вода испаряется, соль остаётся на дне.' }, { mix: 'Железные опилки и сера', method: 'Магнит', why: 'Железо притягивается магнитом, сера — нет.' }, { mix: 'Вода и растительное масло', method: 'Отстаивание (делительная воронка)', why: 'Масло легче воды и не смешивается — слои разделяют.' }, { mix: 'Спирт и вода', method: 'Перегонка (дистилляция)', why: 'У спирта и воды разные температуры кипения.' } ]; var METHODS = ['Фильтрование', 'Выпаривание', 'Магнит', 'Отстаивание (делительная воронка)', 'Перегонка (дистилляция)']; function mount_sep(mountId) { var m = $(mountId); if (!m || m._built) return; m._built = 1; var idx = 0; function render() { var cur = MIX[idx]; m.innerHTML = '
' + '
Каким способом разделить смесь «' + esc(cur.mix) + '»?
' + '
' + METHODS.map(function (mt) { return ''; }).join('') + '
' + '
Выбери способ разделения.
'; $(mountId + '-pick').addEventListener('change', function (e) { idx = +e.target.value; m._built = 0; render(); }); var out = $(mountId + '-out'); m.querySelectorAll('.c7-m').forEach(function (b) { b.addEventListener('click', function () { var ok = b.dataset.m === cur.method; out.className = 'out ' + (ok ? 'ok' : 'bad'); out.innerHTML = ok ? 'Верно! ' + esc(cur.method) + '. ' + esc(cur.why) : 'Не подходит. Подумай, чем различаются вещества в смеси (растворимость, магнитные свойства, температура кипения, плотность).'; }); }); } render(); } function mount_p2() { mount_sep('p2-sep'); } function mount_pr1() { mount_sep('pr1-sep'); } /* §3 — каталог элементов + тренажёр «символ ↔ название» */ var EL = { H: [1, 'Водород'], He: [2, 'Гелий'], Li: [3, 'Литий'], C: [6, 'Углерод'], N: [7, 'Азот'], O: [8, 'Кислород'], F: [9, 'Фтор'], Na: [11, 'Натрий'], Mg: [12, 'Магний'], Al: [13, 'Алюминий'], Si: [14, 'Кремний'], P: [15, 'Фосфор'], S: [16, 'Сера'], Cl: [17, 'Хлор'], K: [19, 'Калий'], Ca: [20, 'Кальций'], Fe: [26, 'Железо'], Cu: [29, 'Медь'], Zn: [30, 'Цинк'], Ag: [47, 'Серебро'] }; function mount_p3() { var grid = $('p3-el'), info = $('p3-elinfo'); if (grid && !grid._built) { grid._built = 1; Object.keys(EL).forEach(function (s) { var ar = C().arOf ? C().arOf(s) : ''; var c = document.createElement('div'); c.className = 'el-cell'; c.innerHTML = '' + EL[s][0] + '' + s + '' + ar + ''; c.addEventListener('click', function () { grid.querySelectorAll('.el-cell').forEach(function (x) { x.classList.remove('on'); }); c.classList.add('on'); if (info) info.innerHTML = '' + EL[s][1] + ' (' + s + ') · порядковый номер Z = ' + EL[s][0] + ' · A_r = ' + ar; }); grid.appendChild(c); }); } /* drill: дан символ → выбери название */ var d = $('p3-drill'); if (d && !d._built) { d._built = 1; var keys = Object.keys(EL), order = keys.slice(), qi = 0, score = 0, total = 0; function nextQ() { var sym = order[qi % order.length]; var correct = EL[sym][1]; var opts = [correct]; while (opts.length < 4) { var r = EL[keys[(qi * 7 + opts.length * 13 + 3) % keys.length]][1]; if (opts.indexOf(r) < 0) opts.push(r); } // детерминированная перестановка opts = opts.sort(function (a, b) { return ((a.length + qi) % 3) - ((b.length + qi) % 3); }); d.innerHTML = '
Какому элементу соответствует символ ' + sym + '?
' + '
' + opts.map(function (o) { return ''; }).join('') + '
' + '
Счёт: ' + score + ' из ' + total + '
'; var out = $('p3-drill-out'); d.querySelectorAll('.c7-d').forEach(function (b) { b.addEventListener('click', function () { total++; var ok = b.dataset.o === correct; if (ok) score++; out.className = 'out ' + (ok ? 'ok' : 'bad'); out.innerHTML = (ok ? 'Верно! ' : 'Нет. ') + sym + ' — это ' + correct + '. Счёт: ' + score + ' из ' + total; qi++; setTimeout(nextQ, 850); }); }); } nextQ(); } } W.CHEM8_WIDGETS = Object.assign(W.CHEM8_WIDGETS || {}, { p1: mount_p1, p2: mount_p2, pr1: mount_pr1, p3: mount_p3 }); W.FLAG_MOUNTS = Object.assign(W.FLAG_MOUNTS || {}, {}); })(window);