diff --git a/backend/tests/chemistry7-page.test.js b/backend/tests/chemistry7-page.test.js index 2789b82..e16db67 100644 --- a/backend/tests/chemistry7-page.test.js +++ b/backend/tests/chemistry7-page.test.js @@ -225,13 +225,16 @@ test('ch3 Волна 2: §21 + ЛО4 + §22 + ПР3 + финал главы мо test('ch4: вся глава 4 (§23–§26 + ЛО5 + ПР4 + финал) монтируется', async () => { const { doc, errors } = await loadDom('chemistry_7_ch4.html'); assert.ok(doc.querySelector('#p23-water #p23-pick'), 'разложение/реакции воды §23'); + assert.ok(doc.querySelector('#p23-bub-h div'), 'пузырьки электролиза 2:1 §23'); doc.defaultView.goTo('p24'); await wait(100); assert.ok(doc.querySelector('#p24-bld #p24-m'), 'конструктор оснований §24'); assert.ok(doc.querySelector('#p24-ind #p24-ind-sel'), 'индикаторы щёлочи §24'); + assert.ok(doc.querySelector('#p24-ind-drop div'), 'анимация индикатора §24'); doc.defaultView.goTo('lo5'); await wait(100); assert.ok(doc.querySelector('#lo5-ind #lo5-ind-sel'), 'индикаторы ЛО5'); doc.defaultView.goTo('p25'); await wait(100); assert.ok(doc.querySelector('#p25-neu #p25-neu-go'), 'нейтрализация §25'); + assert.ok(doc.querySelector('#p25-neu-cup div'), 'анимация раствора §25'); doc.defaultView.goTo('pr4'); await wait(100); assert.ok(doc.querySelector('#pr4-neu #pr4-neu-go'), 'нейтрализация ПР4'); doc.defaultView.goTo('p26'); await wait(100); diff --git a/frontend/js/chem7_ch4_widgets.js b/frontend/js/chem7_ch4_widgets.js index 42dcb65..b85b14c 100644 --- a/frontend/js/chem7_ch4_widgets.js +++ b/frontend/js/chem7_ch4_widgets.js @@ -36,15 +36,23 @@ } function mount_p23() { var m = $('p23-water'); if (!m || m._built) return; m._built = 1; - var idx = 0; + var idx = 0, anims = []; + function stopAnim(){ anims.forEach(function(a){ try { a.stop(); } catch(e){} }); anims = []; } function render(){ + stopAnim(); var r = WRX[idx]; - m.innerHTML = (idx===0 ? decompSvg() : '') + m.innerHTML = (idx===0 ? decompSvg() + + '
H₂ — 2 объёма
' + + '
O₂ — 1 объём
' : '') + '
' + '
'+ceq(r.eq,{cond:r.cond})+'
' + '
'+esc(r.note)+'
'; - $('p23-pick').addEventListener('change', function(e){ idx=+e.target.value; m._built=0; render(); }); + if (idx===0 && W.Chem7Anim) { + anims.push(W.Chem7Anim.bubbleField($('p23-bub-h'), { color:'rgba(96,165,250,.9)', count:18, h:84, bg:'linear-gradient(180deg,#dbeafe,transparent)' })); + anims.push(W.Chem7Anim.bubbleField($('p23-bub-o'), { color:'rgba(248,113,113,.9)', count:9, h:84, bg:'linear-gradient(180deg,#fee2e2,transparent)' })); + } + $('p23-pick').addEventListener('change', function(e){ idx=+e.target.value; render(); }); } render(); } @@ -57,14 +65,17 @@ }; function alkIndicator(mountId) { var m = $(mountId); if (!m || m._built) return; m._built = 1; - var ind = 'Фенолфталеин'; + var ind = 'Фенолфталеин', anim = null; function render(){ + if (anim) { anim.stop(); anim = null; } var c = ALK_IND[ind]; m.innerHTML = '
' + + '
' + '
В нейтральной среде: ' + strip(c.neutral[0]) + ' '+c.neutral[1]+'
' + 'В щёлочи: ' + strip(c.alk[0]) + ' '+c.alk[1]+'
'; - $(mountId+'-sel').addEventListener('change', function(e){ ind=e.target.value; m._built=0; render(); }); + if (W.Chem7Anim) anim = W.Chem7Anim.colorBlock($(mountId+'-drop'), c.neutral[0], c.alk[0], ind + ' в щёлочи → ' + c.alk[1], 900); + $(mountId+'-sel').addEventListener('change', function(e){ ind=e.target.value; render(); }); } render(); } @@ -94,16 +105,19 @@ /* §25 / ПР4 — нейтрализация (фенолфталеин малиновый → бесцветный) */ function mount_neutral(mountId) { var m = $(mountId); if (!m || m._built) return; m._built = 1; - var done = false; - function beaker(color){ return ''; } + var done = false, anim = null; function render(){ - m.innerHTML = '
' + beaker(done?'#f8fafc':'#db2777') - + '
'+(done + if (anim) { anim.stop(); anim = null; } + m.innerHTML = '
' + + '
'+(done ? 'Раствор стал бесцветным — кислота нейтрализовала щёлочь. Реакция завершена.' - : 'В щёлочи с фенолфталеином раствор малиновый. Добавляй кислоту по каплям.')+'
' + : 'В щёлочи с фенолфталеином раствор малиновый. Добавляй кислоту по каплям.')+'
' + '
' + (done ? '
'+ceq('HCl + NaOH = NaCl + H2O')+'
Кислота + основание → соль + вода. Это реакция нейтрализации.
' : ''); - $(mountId+'-go').addEventListener('click', function(){ done=!done; m._built=0; render(); }); + if (W.Chem7Anim) anim = done + ? W.Chem7Anim.colorBlock($(mountId+'-cup'), '#db2777', '#f8fafc', 'малиновый → бесцветный', 1600) + : W.Chem7Anim.colorBlock($(mountId+'-cup'), '#db2777', '#db2777', 'щёлочь + фенолфталеин', 1); + $(mountId+'-go').addEventListener('click', function(){ done=!done; render(); }); } render(); } diff --git a/frontend/textbooks/chemistry_7_ch4.html b/frontend/textbooks/chemistry_7_ch4.html index 7b79c64..b75c506 100644 --- a/frontend/textbooks/chemistry_7_ch4.html +++ b/frontend/textbooks/chemistry_7_ch4.html @@ -23,6 +23,7 @@ html.dark{--bg:#0a1222;--border:#1e3a5f;--pri-soft:rgba(37,99,235,.18);--sec-acc +