diff --git a/backend/tests/chemistry7-page.test.js b/backend/tests/chemistry7-page.test.js
index c2ead93..955788b 100644
--- a/backend/tests/chemistry7-page.test.js
+++ b/backend/tests/chemistry7-page.test.js
@@ -95,6 +95,19 @@ test('ch1 Волна 2: интерактивы §4–§6 монтируются
assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | '));
});
+test('ch1 Волна 3: интерактивы §7–§9 монтируются и считают', async () => {
+ const { doc, errors } = await loadDom('chemistry_7_ch1.html');
+ doc.defaultView.goTo('p7'); await wait(100);
+ assert.ok(doc.querySelector('#p7-out'), 'парсер формулы §7');
+ assert.match(doc.querySelector('#p7-out').textContent, /4/, 'H2SO4 → 4 атома O в разборе');
+ doc.defaultView.goTo('p8'); await wait(100);
+ assert.match(doc.querySelector('#p8-out').textContent, /100/, 'M_r(CaCO3)=100');
+ doc.defaultView.goTo('p9'); await wait(100);
+ assert.ok(doc.querySelector('#p9-bld #p9-a'), 'конструктор валентности §9');
+ assert.match(doc.querySelector('#p9-bout').textContent, /Al/, 'формула по валентности построена');
+ assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | '));
+});
+
test('ch1: переход к §9 и финалу строит заглушку без ошибок', async () => {
const { doc, errors } = await loadDom('chemistry_7_ch1.html');
doc.defaultView.goTo('p9'); await wait(80);
diff --git a/frontend/js/chem7_ch1_widgets.js b/frontend/js/chem7_ch1_widgets.js
index 3fdcf6a..ef6b5e6 100644
--- a/frontend/js/chem7_ch1_widgets.js
+++ b/frontend/js/chem7_ch1_widgets.js
@@ -235,9 +235,73 @@
}
}
+ /* ── Волна 3 ── */
+
+ /* §7 — разбор химической формулы на состав */
+ function mount_p7() {
+ var inp = $('p7-in'), out = $('p7-out'), go = $('p7-go'); if (!inp || inp._built) return; inp._built = 1;
+ function calc() {
+ var f = inp.value.trim(), cnt = C().elementCounts ? C().elementCounts(f) : null;
+ if (!cnt || !Object.keys(cnt).length) { out.className = 'out bad'; out.textContent = 'Не удалось разобрать формулу. Проверь символы элементов (например, H2SO4).'; return; }
+ var els = Object.keys(cnt), tot = els.reduce(function (s, e) { return s + cnt[e]; }, 0);
+ out.className = 'out ok';
+ out.innerHTML = '' + (C().formula ? C().formula(f) : f) + ' '
+ + 'Элементов: ' + els.length + ' (' + (els.length === 1 ? 'простое' : 'сложное') + ' вещество) '
+ + els.map(function (e) { return e + ': ' + cnt[e] + ' ' + (cnt[e] === 1 ? 'атом' : 'атома(ов)'); }).join(' ')
+ + ' Всего атомов в формуле: ' + tot + '';
+ }
+ go.addEventListener('click', calc);
+ inp.addEventListener('keydown', function (e) { if (e.key === 'Enter') calc(); });
+ document.querySelectorAll('.p7-ex').forEach(function (b) { b.addEventListener('click', function () { inp.value = b.dataset.f; calc(); }); });
+ calc();
+ }
+
+ /* §8 — калькулятор относительной молекулярной массы M_r */
+ function mount_p8() {
+ var inp = $('p8-in'), out = $('p8-out'), go = $('p8-go'); if (!inp || inp._built) return; inp._built = 1;
+ function calc() {
+ var f = inp.value.trim(), cnt = C().elementCounts ? C().elementCounts(f) : null, mr = C().molarMass ? C().molarMass(f) : NaN;
+ if (!cnt || isNaN(mr)) { out.className = 'out bad'; out.textContent = 'Не удалось разобрать формулу.'; return; }
+ out.className = 'out ok';
+ out.innerHTML = 'M_r(' + f + ') = ' + C().fmt(mr) + ' '
+ + Object.keys(cnt).map(function (e) { return e + ': A_r=' + (C().arOf ? C().arOf(e) : '?') + ' × ' + cnt[e]; }).join(' | ')
+ + ' Σ = ' + Object.keys(cnt).map(function (e) { return (C().arOf ? C().arOf(e) : '?') + '·' + cnt[e]; }).join(' + ') + ' = ' + C().fmt(mr) + '';
+ }
+ go.addEventListener('click', calc);
+ inp.addEventListener('keydown', function (e) { if (e.key === 'Enter') calc(); });
+ document.querySelectorAll('.p8-ex').forEach(function (b) { b.addEventListener('click', function () { inp.value = b.dataset.f; calc(); }); });
+ calc();
+ }
+
+ /* §9 — конструктор формулы по валентности (НОК индексов) */
+ function gcd(a, b) { return b ? gcd(b, a % b) : a; }
+ var VA = [ ['Na', 1], ['K', 1], ['H', 1], ['Mg', 2], ['Ca', 2], ['Zn', 2], ['Cu', 2], ['Al', 3], ['C', 4] ];
+ var VB = [ ['O', 2], ['Cl', 1], ['S', 2] ];
+ function mount_p9() {
+ var m = $('p9-bld'); if (!m || m._built) return; m._built = 1;
+ function optA(){ return VA.map(function(e,i){ return ''; }).join(''); }
+ function optB(){ return VB.map(function(e,i){ return ''; }).join(''); }
+ m.innerHTML = '
'
+ +'
';
+ function upd() {
+ var a = VA[+$('p9-a').value], b = VB[+$('p9-b').value];
+ var lcm = a[1] * b[1] / gcd(a[1], b[1]);
+ var ia = lcm / a[1], ib = lcm / b[1];
+ var raw = a[0] + (ia > 1 ? ia : '') + b[0] + (ib > 1 ? ib : '');
+ var out = $('p9-bout'); out.className = 'out ok';
+ out.innerHTML = 'Валентности: ' + a[0] + ' = ' + 'I'.repeat(a[1]).replace('IIII','IV') + ', ' + b[0] + ' = ' + 'I'.repeat(b[1]) + ' '
+ + 'Наименьшее общее кратное валентностей = ' + lcm + ' '
+ + 'Индексы: ' + a[0] + ' → ' + ia + ', ' + b[0] + ' → ' + ib + ' '
+ + 'Формула: ' + (C().formula ? C().formula(raw) : raw) + ' '
+ + 'Проверка: ' + ia + '·' + a[1] + ' = ' + ib + '·' + b[1] + ' = ' + lcm + ' единиц валентности — совпало.';
+ }
+ $('p9-a').addEventListener('change', upd); $('p9-b').addEventListener('change', upd); upd();
+ }
+
W.CHEM8_WIDGETS = Object.assign(W.CHEM8_WIDGETS || {}, {
p1: mount_p1, p2: mount_p2, pr1: mount_pr1, p3: mount_p3,
- p4: mount_p4, p5: mount_p5, p6: mount_p6
+ p4: mount_p4, p5: mount_p5, p6: mount_p6,
+ p7: mount_p7, p8: mount_p8, p9: mount_p9
});
W.FLAG_MOUNTS = Object.assign(W.FLAG_MOUNTS || {}, {});
})(window);
diff --git a/frontend/textbooks/chemistry_7_ch1.html b/frontend/textbooks/chemistry_7_ch1.html
index 1e48637..07caf6d 100644
--- a/frontend/textbooks/chemistry_7_ch1.html
+++ b/frontend/textbooks/chemistry_7_ch1.html
@@ -105,7 +105,8 @@ window.PARAS = [
window.ACH_LABELS = { start:'Начало главы 1!', p1_done:'§1 изучен!', p2_done:'§2 изучен!',
pr1_done:'Практическая работа 1 выполнена!', p3_done:'§3 изучен!',
- p4_done:'§4 изучен!', p5_done:'§5 изучен!', p6_done:'§6 изучен!', final1_tasks:'Глава 1 пройдена!' };
+ p4_done:'§4 изучен!', p5_done:'§5 изучен!', p6_done:'§6 изучен!',
+ p7_done:'§7 изучен!', p8_done:'§8 изучен!', p9_done:'§9 изучен!', final1_tasks:'Глава 1 пройдена!' };
window.SIDEBARS = {
p1:{ title:'Шпаргалка §1', rows:[['Вещество','то, из чего состоит тело'],['Тело','предмет из вещества'],['Свойства','цвет, запах, плотность, $t_{пл}$…']] },
p2:{ title:'Шпаргалка §2', rows:[['Чистое','постоянный состав'],['Смесь','2+ вещества'],['Разделение','по различию свойств']] },
@@ -113,7 +114,10 @@ window.SIDEBARS = {
p3:{ title:'Шпаргалка §3', rows:[['Атом','мельчайшая частица'],['Элемент','атомы с одинаковым $Z$'],['Символ','H, O, Fe, Cu…']] },
p4:{ title:'Шпаргалка §4', rows:[['$A_r$','во сколько раз тяжелее'],['Эталон','$1/12$ массы $^{12}$C'],['Пример','$A_r(\\text{O})=16$']] },
p5:{ title:'Шпаргалка §5', rows:[['Молекула','частица из атомов'],['Простое','1 элемент: $O_2$, $H_2$'],['Атомность','$O_2$, $O_3$']] },
- p6:{ title:'Шпаргалка §6', rows:[['Сложное','разные элементы'],['Примеры','$H_2O$, $CO_2$, $NH_3$'],['Состав','можно разложить']] }
+ p6:{ title:'Шпаргалка §6', rows:[['Сложное','разные элементы'],['Примеры','$H_2O$, $CO_2$, $NH_3$'],['Состав','можно разложить']] },
+ p7:{ title:'Шпаргалка §7', rows:[['Индекс','число атомов'],['Коэффициент','число молекул'],['Состав','качеств. + количеств.']] },
+ p8:{ title:'Шпаргалка §8', rows:[['$M_r$','$=\\sum A_r$'],['$M_r(H_2O)$','18'],['$M_r(H_2SO_4)$','98']] },
+ p9:{ title:'Шпаргалка §9', rows:[['Валентность','число связей'],['H — I, O — II',''],['Формула','по НОК валентностей']] }
};
window.TIPS = [
{ sec:'p1', html:'Тело — это предмет (гвоздь, стакан), а вещество — то, из чего он сделан (железо, стекло). Из одного вещества можно сделать много тел.' },
@@ -122,7 +126,10 @@ window.TIPS = [
{ sec:'p3', html:'Химический элемент определяется зарядом ядра (числом протонов) — это и есть порядковый номер $Z$.' },
{ sec:'p4', html:'$A_r$ показывает, во сколько раз масса атома больше $1/12$ массы атома углерода-12. $A_r(\\text{H})=1$, $A_r(\\text{O})=16$, $A_r(\\text{Fe})=56$.' },
{ sec:'p5', html:'Простое вещество — атомы одного элемента ($O_2$, $Fe$). Кислород $O_2$ и озон $O_3$ — разные простые вещества одного и того же элемента.' },
- { sec:'p6', html:'Сложное вещество образовано атомами разных элементов ($H_2O$ — водород и кислород) и может быть разложено на простые.' }
+ { sec:'p6', html:'Сложное вещество образовано атомами разных элементов ($H_2O$ — водород и кислород) и может быть разложено на простые.' },
+ { sec:'p7', html:'Индекс относится к атому/группе слева от него. В $H_2SO_4$: 2 атома H, 1 атом S, 4 атома O. Коэффициент (число перед формулой) — это число молекул.' },
+ { sec:'p8', html:'$M_r$ — сумма $A_r$ всех атомов формулы. $M_r(\\text{CO}_2)=12+2\\cdot16=44$.' },
+ { sec:'p9', html:'Кислород в соединениях имеет валентность II, водород — I. Зная их, можно определить валентность другого элемента и составить формулу по НОК.' }
];
/* ── задачи (тренажёр) ── */
@@ -162,6 +169,24 @@ window.POOLS = {
{q:'Сложное вещество образовано…',opts:['Атомами одного элемента','Атомами разных элементов','Только смесью','Одним атомом'],a:1,ex:'Сложное — разные элементы.'},
{q:'Какое из веществ — простое?',opts:['$\\text{H}_2\\text{O}$','$\\text{CO}_2$','$\\text{N}_2$','$\\text{NH}_3$'],a:2,ex:'$N_2$ — один элемент (азот).'},
{q:'Сколько разных химических элементов в молекуле метана $\\text{CH}_4$?',hint:'углерод и водород',unit:'',a:2,ex:'C и H — два элемента.'}
+ ],
+ p7:[
+ {q:'Что показывает индекс в химической формуле?',opts:['Число молекул','Число атомов элемента','Массу вещества','Заряд'],a:1,ex:'Индекс — число атомов элемента (или группы) в формуле.'},
+ {q:'Сколько атомов кислорода в формуле $\\text{H}_2\\text{SO}_4$?',hint:'индекс при O',unit:'',a:4,ex:'4 атома кислорода.'},
+ {q:'Сколько всего атомов в молекуле воды $\\text{H}_2\\text{O}$?',hint:'2 H + 1 O',unit:'',a:3,ex:'2 + 1 = 3 атома.'},
+ {q:'Число, стоящее перед формулой (коэффициент), показывает…',opts:['Число атомов','Число молекул','Валентность','Массу'],a:1,ex:'Коэффициент — число молекул вещества.'}
+ ],
+ p8:[
+ {q:'Чему равна $M_r(\\text{H}_2\\text{O})$?',hint:'$2\\cdot1+16$',unit:'',a:18,ex:'$M_r=18$.'},
+ {q:'Чему равна $M_r(\\text{CO}_2)$?',hint:'$12+2\\cdot16$',unit:'',a:44,ex:'$12+32=44$.'},
+ {q:'Чему равна $M_r(\\text{H}_2\\text{SO}_4)$?',hint:'$2+32+4\\cdot16$',unit:'',a:98,ex:'$2+32+64=98$.'},
+ {q:'Чему равна $M_r(\\text{CaCO}_3)$?',hint:'$40+12+3\\cdot16$',unit:'',a:100,ex:'$40+12+48=100$.'}
+ ],
+ p9:[
+ {q:'За единицу валентности принята валентность атома…',opts:['кислорода','водорода','углерода','железа'],a:1,ex:'Единица валентности — валентность водорода (I).'},
+ {q:'Какова валентность кислорода в соединениях?',hint:'постоянная',unit:'',a:2,ex:'Кислород почти всегда двухвалентен (II).'},
+ {q:'Какова валентность хлора в молекуле $\\text{HCl}$?',hint:'равна числу атомов H',unit:'',a:1,ex:'Хлор соединён с 1 атомом H → валентность I.'},
+ {q:'Какова формула оксида алюминия (Al — III, O — II)?',opts:['AlO','Al₂O₃','AlO₂','Al₃O₂'],a:1,ex:'НОК(3,2)=6 → индексы 2 и 3 → Al₂O₃.'}
]
};
@@ -290,6 +315,58 @@ function build_p6(){
wireReadBtn('p6');
}
+function build_p7(){
+ document.getElementById('p7-body').innerHTML =
+ '
§ 7 · Химия 7
Химическая формула
'
+ +'
$\\text{H}_2\\text{O}$
'
+ +'
Как с помощью формулы записывают, из каких атомов и в каком числе состоит вещество.
'
+ +'
индекскоэффициентсостав
'
+ +makeCard('theory','Что показывает формула','§7','
Химическая формула показывает состав вещества: качественный (из каких элементов) и количественный (сколько атомов каждого элемента).
'
+ +'
Индекс — маленькое число справа внизу: показывает число атомов элемента ($\\text{H}_2\\text{O}$ — 2 атома H, 1 атом O). Коэффициент — число перед формулой: показывает число молекул ($2\\text{H}_2\\text{O}$ — две молекулы воды).
')
+ +wgt('Разбор формулы на состав',''
+ +''
+ +'
Введи формулу и нажми «Разобрать».
')
+ +rememberBox(['Индекс — число атомов; стоит справа внизу.','Коэффициент — число молекул; стоит перед формулой.','Скобки: индекс умножает всё внутри — Ca(OH)₂ = 1 Ca, 2 O, 2 H.'])
+ +qList(['Чем индекс отличается от коэффициента?','Сколько атомов каждого элемента в $\\text{H}_3\\text{PO}_4$?','Что означает запись $3\\text{H}_2\\text{O}$?'])
+ +secNav('p6','p8')+readButton('p7');
+ wireReadBtn('p7');
+}
+
+function build_p8(){
+ document.getElementById('p8-body').innerHTML =
+ '
§ 8 · Химия 7
Относительная молекулярная масса
'
+ +'
$M_r=\\sum A_r$
'
+ +'
Как по формуле рассчитать, во сколько раз молекула тяжелее эталона.
Относительная молекулярная масса $M_r$ равна сумме относительных атомных масс всех атомов в формуле. Это безразмерная величина: она показывает, во сколько раз молекула тяжелее $\\tfrac{1}{12}$ массы атома углерода-12.
')
+ +wgt('Калькулятор $M_r$ по формуле',''
+ +''
+ +'
Введи формулу и нажми «Вычислить».
')
+ +rememberBox(['$M_r$ — сумма $A_r$ всех атомов формулы.','$M_r$ безразмерна.','Индекс умножает $A_r$ соответствующего элемента.'])
+ +qList(['Вычисли $M_r(\\text{Na}_2\\text{CO}_3)$.','Во сколько раз молекула воды тяжелее $\\tfrac{1}{12}$ атома углерода-12?','Вычисли $M_r(\\text{Fe}_2\\text{O}_3)$.'])
+ +secNav('p7','p9')+readButton('p8');
+ wireReadBtn('p8');
+}
+
+function build_p9(){
+ document.getElementById('p9-body').innerHTML =
+ '
§ 9 · Химия 7
Валентность
'
+ +'
H — I, O — II
'
+ +'
Сколько связей образует атом и как по валентности составить формулу вещества.
'
+ +'
валентностьНОК
'
+ +makeCard('theory','Что такое валентность','§9','
Валентность — способность атома соединяться с определённым числом атомов других элементов. За единицу валентности принята валентность атома водорода (I). В $\\text{HCl}$ хлор одновалентен, в $\\text{H}_2\\text{O}$ кислород двухвалентен, в $\\text{NH}_3$ азот трёхвалентен, в $\\text{CH}_4$ углерод четырёхвалентен.
')
+ +makeCard('rule','Составление формул по валентности','§9','
Кислород в соединениях обычно имеет валентность II, водород — I. Зная валентности, формулу составляют так, чтобы суммарное число единиц валентности обоих элементов совпало (по наименьшему общему кратному).
'
+ +'
Постоянные валентности: H — I; O — II; Na, K — I; Mg, Ca, Zn — II; Al — III.
')
+ +makeCard('example','Оксид алюминия',null,'
Al — III, O — II. НОК(3, 2) = 6. Индексы: Al → 6/3 = 2, O → 6/2 = 3.
Формула: $\\text{Al}_2\\text{O}_3$.
')
+ +wgt('Конструктор формулы по валентности','')
+ +rememberBox(['Валентность — число связей атома; единица — валентность водорода.','Кислород — II, водород — I (постоянные).','Формулу составляют по НОК валентностей.'])
+ +qList(['Определи валентность серы в $\\text{SO}_2$ (O — II).','Составь формулу соединения кальция (II) с кислородом.','Чему равна валентность азота в $\\text{NH}_3$?'])
+ +secNav('p8','p10')+readButton('p9');
+ wireReadBtn('p9');
+}
+
/* заглушки для ещё не наполненных § (фазы — следующие волны) */
(function(){
var P = window.PARAS, B = {};
@@ -319,6 +396,9 @@ window.BUILDERS.p3 = build_p3;
window.BUILDERS.p4 = build_p4;
window.BUILDERS.p5 = build_p5;
window.BUILDERS.p6 = build_p6;
+window.BUILDERS.p7 = build_p7;
+window.BUILDERS.p8 = build_p8;
+window.BUILDERS.p9 = build_p9;