From bc64828b22030a1280c65cb7d1f91e5647c49791 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Sat, 30 May 2026 10:10:33 +0300 Subject: [PATCH] =?UTF-8?q?feat(phys9=20flagships):=20F3=20=D1=82=D0=B0?= =?UTF-8?q?=D1=85=D0=BE=D0=BC=D0=B5=D1=82=D1=80+=D1=81=D0=BF=D0=B8=D0=B4?= =?UTF-8?q?=D0=BE=D0=BC=D0=B5=D1=82=D1=80=20+=20F4=20=D0=BE=D1=80=D0=B1?= =?UTF-8?q?=D0=B8=D1=82=D0=B0=20(Wave=20A=20=D0=BF=D1=80=D0=BE=D0=B4=D0=BE?= =?UTF-8?q?=D0=BB=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit F3. Тахометр + спидометр + одометр (§11 в ch1): - Canvas 640×400 с 3 аналоговыми приборами вверху (тахометр a, спидометр v, одометр Δx mod 1000) - Графики v(t) и a(t) внизу с горизонтальной цель-линией - Кнопки «Газ»/«Тормоз» удержанием, «Отпустить» — coast-режим (лёгкое торможение от трения) - Slider'ы: a_газа, |a_тормоз|, цель скорости (по умолчанию 16.7 м/с) - Рекорд скорости в localStorage - Feedback при достижении цели F4. Орбитальный конструктор (§17 в ch2): - Canvas 640×480 (космос со звёздами) - Планета (Земля) в центре, спутник запускается с r=200 - Slider'ы: M, v₀, угол α - Кнопки: Запустить/Сброс/«Круговая орбита» (вычисляет v=√(M/r)) - Физика: F=GM/r² (G=1), Эйлер 8 шагов/кадр - Trail орбиты до 1500 точек - Классификация: падение/круговая/эллипс/убегание - Период T через переход через ось x - Feedback при крайних случаях Подключение: - ch1: phys9_flag_F3_dashboard.js + хук на p11 - ch2: phys9-flagships.css + base + F4 + хук на p17 Co-Authored-By: Claude Opus 4.7 --- .../js/flagships/phys9_flag_F3_dashboard.js | 210 ++++++++++++++++ frontend/js/flagships/phys9_flag_F4_orbit.js | 230 ++++++++++++++++++ frontend/textbooks/physics_9_ch1.html | 2 +- frontend/textbooks/physics_9_ch2.html | 3 +- 4 files changed, 443 insertions(+), 2 deletions(-) create mode 100644 frontend/js/flagships/phys9_flag_F3_dashboard.js create mode 100644 frontend/js/flagships/phys9_flag_F4_orbit.js diff --git a/frontend/js/flagships/phys9_flag_F3_dashboard.js b/frontend/js/flagships/phys9_flag_F3_dashboard.js new file mode 100644 index 0000000..9069042 --- /dev/null +++ b/frontend/js/flagships/phys9_flag_F3_dashboard.js @@ -0,0 +1,210 @@ +// F3. Тахометр + спидометр + одометр (§11-13) — игра в автогонщика. +(function(){ +'use strict'; +const B = () => window.PHYS9_FLAG_BASE; +const C = () => window.PHYS9_COLORS || {}; + +function init(secId){ + if (!B()) return false; + const body = '' + + '
' + + '' + + '' + + '' + + '
' + + '' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '
Время0 с
' + + '
$v$ (спидометр)0 м/с
' + + '
$a$ (тахометр)0 м/с²
' + + '
$\\Delta x$ (одометр)0 м
' + + '
Рекорд скорости0 м/с
' + + '
' + + '
'; + + const card = B().makeCard(secId, + 'F3. Тахометр + спидометр + одометр', + 'Управляй автомобилем кнопками. Тахометр (a), спидометр (v) и одометр (Δx) — связаны. Разгонись до цели и затормози.', + body); + if (!card) return false; + + const cv = document.getElementById('F3-cv'); + const ctx = cv.getContext('2d'); + const W = cv.width, H = cv.height; + + let st = { t: 0, v: 0, x: 0, a: 0, mode: 'coast', history: [], targetHit: false }; + + function readSliders(){ + document.getElementById('F3-gv').textContent = (+document.getElementById('F3-g').value).toFixed(1); + document.getElementById('F3-bv').textContent = (+document.getElementById('F3-b').value).toFixed(1); + document.getElementById('F3-tv').textContent = (+document.getElementById('F3-t').value).toFixed(1); + } + + function reset(){ + st = { t: 0, v: 0, x: 0, a: 0, mode: 'coast', history: [], targetHit: false }; + document.getElementById('F3-fb').className = 'flag-feedback'; + } + + function tick(dt){ + const gas = +document.getElementById('F3-g').value; + const brake = +document.getElementById('F3-b').value; + const target = +document.getElementById('F3-t').value; + if (st.mode === 'gas') st.a = gas; + else if (st.mode === 'brake') st.a = st.v > 0.1 ? -brake : 0; + else /* coast */ st.a = st.v > 0.05 ? -0.5 : 0; /* лёгкое торможение от трения */ + st.v = Math.max(0, st.v + st.a * dt); + st.x += st.v * dt; + st.t += dt; + st.history.push({ t: st.t, v: st.v, a: st.a }); + if (st.history.length > 600) st.history.shift(); + /* Цель достигнута? */ + if (!st.targetHit && Math.abs(st.v - target) < 0.5){ + st.targetHit = true; + const fb = document.getElementById('F3-fb'); + fb.className = 'flag-feedback ok show'; + fb.innerHTML = '✓ Цель достигнута! Скорость '+st.v.toFixed(1)+' м/с (~'+(st.v*3.6).toFixed(0)+' км/ч). Теперь затормози.'; + } + /* Рекорд */ + const rec = B().saveRecord('F3_max_v', st.v); + document.getElementById('F3-rec').textContent = rec.toFixed(1) + ' м/с'; + /* UI */ + document.getElementById('F3-t-st').textContent = st.t.toFixed(1) + ' с'; + document.getElementById('F3-v').textContent = st.v.toFixed(1) + ' м/с'; + document.getElementById('F3-a').textContent = st.a.toFixed(1) + ' м/с²'; + document.getElementById('F3-x').textContent = st.x.toFixed(1) + ' м'; + draw(); + } + + function drawGauge(cx, cy, r, val, min, max, label, unit, color){ + const col = C(); + /* фон */ + ctx.fillStyle = col.bgSubtle || '#f8fafc'; + ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI*2); ctx.fill(); + ctx.strokeStyle = col.axis || '#1e293b'; + ctx.lineWidth = 2; + ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI*2); ctx.stroke(); + /* шкала */ + const a0 = Math.PI*0.75, a1 = Math.PI*2.25; + ctx.strokeStyle = col.text || '#0f172a'; + ctx.lineWidth = 2; + for (let i = 0; i <= 10; i++){ + const a = a0 + (a1 - a0) * (i/10); + const x1 = cx + (r-10) * Math.cos(a), y1 = cy + (r-10) * Math.sin(a); + const x2 = cx + r * Math.cos(a), y2 = cy + r * Math.sin(a); + ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); + } + /* стрелка */ + const norm = Math.max(0, Math.min(1, (val - min)/(max - min))); + const a = a0 + (a1 - a0) * norm; + const tipX = cx + (r-15) * Math.cos(a), tipY = cy + (r-15) * Math.sin(a); + ctx.strokeStyle = color; + ctx.lineWidth = 4; + ctx.lineCap = 'round'; + ctx.beginPath(); ctx.moveTo(cx, cy); ctx.lineTo(tipX, tipY); ctx.stroke(); + ctx.fillStyle = color; + ctx.beginPath(); ctx.arc(cx, cy, 5, 0, Math.PI*2); ctx.fill(); + /* подписи */ + ctx.fillStyle = col.text || '#0f172a'; + ctx.font = 'bold 11px Inter,sans-serif'; + ctx.textAlign = 'center'; + ctx.fillText(label, cx, cy - r - 6); + ctx.font = 'bold 18px Inter,sans-serif'; + ctx.fillText(val.toFixed(1), cx, cy + r/2); + ctx.font = '11px Inter,sans-serif'; + ctx.fillText(unit, cx, cy + r/2 + 14); + ctx.textAlign = 'left'; + } + + function draw(){ + const col = C(); + ctx.fillStyle = col.bg || '#fafafa'; + ctx.fillRect(0, 0, W, H); + /* 3 прибора в верху */ + drawGauge(110, 80, 55, st.a, -10, 8, 'ТАХОМЕТР (a)', 'м/с²', col.acceleration || '#ea580c'); + drawGauge(320, 80, 55, st.v, 0, 35, 'СПИДОМЕТР (v)', 'м/с', col.velocity || '#0891b2'); + drawGauge(530, 80, 55, st.x % 1000, 0, 1000, 'ОДОМЕТР (Δx)', 'м', col.displacement || '#2563eb'); + /* график v(t) и a(t) внизу */ + const gx = 20, gy = 180, gw = W - 40, gh = 180; + ctx.fillStyle = col.bgSubtle || '#f8fafc'; + ctx.fillRect(gx, gy, gw, gh); + ctx.strokeStyle = col.axis || '#1e293b'; + ctx.lineWidth = 1.5; + ctx.beginPath(); + ctx.moveTo(gx, gy + gh/2); ctx.lineTo(gx + gw, gy + gh/2); /* ось t для a */ + ctx.moveTo(gx, gy + gh); ctx.lineTo(gx + gw, gy + gh); /* ось t для v */ + ctx.stroke(); + /* сетка */ + ctx.strokeStyle = col.grid || '#e5e7eb'; + ctx.lineWidth = 1; + const tMax = Math.max(20, st.t); + for (let i = 0; i <= 10; i++){ + const px = gx + (i/10)*gw; + ctx.beginPath(); ctx.moveTo(px, gy); ctx.lineTo(px, gy+gh); ctx.stroke(); + } + /* подписи */ + ctx.fillStyle = col.textMuted || '#64748b'; + ctx.font = '10px Inter,sans-serif'; + ctx.fillText('v(t)', gx + 4, gy + gh - 4); + ctx.fillText('a(t)', gx + 4, gy + gh/2 - 4); + ctx.fillText('t, с', gx + gw - 24, gy + gh + 12); + /* линии */ + if (st.history.length > 1){ + ctx.strokeStyle = col.velocity || '#0891b2'; + ctx.lineWidth = 2.5; + ctx.beginPath(); + for (let i = 0; i < st.history.length; i++){ + const p = st.history[i]; + const px = gx + (p.t / tMax) * gw; + const py = gy + gh - (p.v / 35) * (gh/2); + if (i === 0) ctx.moveTo(px, py); else ctx.lineTo(px, py); + } + ctx.stroke(); + ctx.strokeStyle = col.acceleration || '#ea580c'; + ctx.beginPath(); + for (let i = 0; i < st.history.length; i++){ + const p = st.history[i]; + const px = gx + (p.t / tMax) * gw; + const py = gy + gh/2 - (p.a / 12) * (gh/4); + if (i === 0) ctx.moveTo(px, py); else ctx.lineTo(px, py); + } + ctx.stroke(); + } + /* цель скорости — горизонталь */ + const target = +document.getElementById('F3-t').value; + ctx.strokeStyle = '#fbbf24'; + ctx.setLineDash([6, 4]); + ctx.lineWidth = 2; + const targetY = gy + gh - (target / 35) * (gh/2); + ctx.beginPath(); ctx.moveTo(gx, targetY); ctx.lineTo(gx + gw, targetY); ctx.stroke(); + ctx.setLineDash([]); + ctx.fillStyle = '#92400e'; + ctx.font = 'bold 11px Inter,sans-serif'; + ctx.fillText('★ цель '+target.toFixed(1)+' м/с', gx + gw - 110, targetY - 4); + } + + document.getElementById('F3-gas').addEventListener('mousedown', ()=>{ st.mode = 'gas'; }); + document.getElementById('F3-gas').addEventListener('mouseup', ()=>{ st.mode = 'coast'; }); + document.getElementById('F3-brake').addEventListener('mousedown', ()=>{ st.mode = 'brake'; }); + document.getElementById('F3-brake').addEventListener('mouseup', ()=>{ st.mode = 'coast'; }); + document.getElementById('F3-coast').addEventListener('click', ()=>{ st.mode = 'coast'; }); + document.getElementById('F3-reset').addEventListener('click', reset); + ['F3-g','F3-b','F3-t'].forEach(id => document.getElementById(id).addEventListener('input', readSliders)); + + readSliders(); + draw(); + B().startLoop('F3', cv, tick); + return true; +} + +if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F3', { init: init, cleanup: function(){} }); +else document.addEventListener('DOMContentLoaded', ()=>{ + if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F3', { init: init, cleanup: function(){} }); +}); + +})(); diff --git a/frontend/js/flagships/phys9_flag_F4_orbit.js b/frontend/js/flagships/phys9_flag_F4_orbit.js new file mode 100644 index 0000000..bc1bd19 --- /dev/null +++ b/frontend/js/flagships/phys9_flag_F4_orbit.js @@ -0,0 +1,230 @@ +// F4. Орбитальный конструктор (§17-18) — запусти спутник, увидь орбиту. +(function(){ +'use strict'; +const B = () => window.PHYS9_FLAG_BASE; +const C = () => window.PHYS9_COLORS || {}; + +function init(secId){ + if (!B()) return false; + const body = '' + + '
' + + '' + + '' + + '' + + '
' + + '' + + '
' + + '' + + '' + + '' + + '
' + + '
' + + '
Тип орбиты
' + + '
$T$ (период, если эллипс)
' + + '
$|r|$ от центра200 px
' + + '
$|v|$120 px/с
' + + '
' + + '
'; + + const card = B().makeCard(secId, + 'F4. Орбитальный конструктор', + 'Запусти спутник с разной начальной скоростью. Слишком мало — упадёт. Точно — круговая. Чуть больше — эллипс. Слишком много — улетит навсегда.', + body); + if (!card) return false; + + const cv = document.getElementById('F4-cv'); + const ctx = cv.getContext('2d'); + const W = cv.width, H = cv.height; + const cx = W/2, cy = H/2; + const planetR = 30; + const startR = 200; /* начальное расстояние от центра */ + + let st = { + x: cx + startR, y: cy, + vx: 0, vy: -120, + trail: [], + running: false, + crashed: false, + escaped: false, + /* для определения периода — фиксируем угол при старте */ + lastAngle: 0, + revolutions: 0, + tStart: 0, + t: 0 + }; + + function readSliders(){ + document.getElementById('F4-Mv').textContent = (+document.getElementById('F4-M').value).toFixed(0); + document.getElementById('F4-v0v').textContent = (+document.getElementById('F4-v0').value).toFixed(0); + document.getElementById('F4-anv').textContent = (+document.getElementById('F4-an').value).toFixed(0); + } + + function reset(){ + const v0 = +document.getElementById('F4-v0').value; + const an = +document.getElementById('F4-an').value; + st.x = cx + startR; st.y = cy; + st.vx = v0 * Math.cos(an*Math.PI/180); + st.vy = -v0 * Math.sin(an*Math.PI/180); + st.trail = []; + st.crashed = false; st.escaped = false; + st.running = false; + st.t = 0; st.revolutions = 0; st.tStart = 0; + st.lastAngle = Math.atan2(st.y - cy, st.x - cx); + document.getElementById('F4-fb').className = 'flag-feedback'; + document.getElementById('F4-go').textContent = 'Запустить'; + draw(); + } + + function setCircular(){ + /* для круговой v = sqrt(G*M/r) — у нас G=1, M из slider'a */ + const M = +document.getElementById('F4-M').value; + const vCirc = Math.sqrt(M / startR); + document.getElementById('F4-v0').value = Math.round(vCirc); + document.getElementById('F4-an').value = 90; + readSliders(); + reset(); + } + + function tick(dt){ + if (!st.running || st.crashed || st.escaped) { draw(); return; } + /* Гравитация: F = G*M*m/r², a = G*M/r² к центру */ + const M = +document.getElementById('F4-M').value; + /* RK4 was bы лучше но Эйлер с малым шагом норм */ + const N = 8; + const ddt = dt / N; + for (let i = 0; i < N; i++){ + const dx = cx - st.x, dy = cy - st.y; + const r2 = dx*dx + dy*dy; + const r = Math.sqrt(r2); + if (r < planetR){ st.crashed = true; break; } + if (r > 2000){ st.escaped = true; break; } + const aMag = M / r2; + const ax = aMag * dx / r, ay = aMag * dy / r; + st.vx += ax * ddt; + st.vy += ay * ddt; + st.x += st.vx * ddt; + st.y += st.vy * ddt; + st.t += ddt; + /* trail */ + if (i === N-1) st.trail.push({ x: st.x, y: st.y }); + if (st.trail.length > 1500) st.trail.shift(); + /* определение периода — переход через ось x */ + const ang = Math.atan2(st.y - cy, st.x - cx); + if (st.lastAngle > Math.PI*0.9 && ang < -Math.PI*0.9 || st.lastAngle < -Math.PI*0.9 && ang > Math.PI*0.9){ + /* skip — wrap */ + } else if (st.lastAngle < 0 && ang >= 0){ + st.revolutions++; + if (st.revolutions === 1) st.tStart = st.t; + } + st.lastAngle = ang; + } + const fb = document.getElementById('F4-fb'); + if (st.crashed){ + st.running = false; + document.getElementById('F4-go').textContent = 'Запустить'; + fb.className = 'flag-feedback fail show'; + fb.innerHTML = '✗ Спутник упал на планету! Нужна бо́льшая начальная скорость.'; + } else if (st.escaped){ + st.running = false; + document.getElementById('F4-go').textContent = 'Запустить'; + fb.className = 'flag-feedback warn show'; + fb.innerHTML = 'Спутник улетел! Это вторая космическая (~$\\sqrt 2 v_{круг}$). Уменьши скорость.'; + } + /* статистика */ + const dx = st.x - cx, dy = st.y - cy; + const r = Math.sqrt(dx*dx + dy*dy); + const v = Math.sqrt(st.vx*st.vx + st.vy*st.vy); + document.getElementById('F4-r').textContent = r.toFixed(0) + ' px'; + document.getElementById('F4-v').textContent = v.toFixed(0) + ' px/с'; + /* классификация */ + const Mclassify = +document.getElementById('F4-M').value; + const vCirc = Math.sqrt(Mclassify / startR); + const ratio = +document.getElementById('F4-v0').value / vCirc; + let type; + if (st.crashed) type = '✗ падение'; + else if (st.escaped) type = '↗ убегание'; + else if (Math.abs(ratio - 1) < 0.05) type = '○ круговая'; + else if (ratio < 0.95) type = '⬭ эллипс (ближе к планете)'; + else if (ratio < 1.41) type = '⬮ эллипс (дальше)'; + else type = '↗ убегание'; + document.getElementById('F4-type').textContent = type; + if (st.revolutions >= 2 && st.tStart > 0){ + const T = (st.t - st.tStart) / (st.revolutions - 1); + document.getElementById('F4-T').textContent = T.toFixed(2) + ' с'; + } + draw(); + } + + function draw(){ + const col = C(); + ctx.fillStyle = col.bg || '#fafafa'; + ctx.fillRect(0, 0, W, H); + /* звёзды для красоты */ + ctx.fillStyle = col.textMuted || '#94a3b8'; + for (let i = 0; i < 60; i++){ + const sx = (i * 37 + 17) % W; + const sy = (i * 61 + 23) % H; + ctx.fillRect(sx, sy, 1, 1); + } + /* планета (Земля) */ + ctx.fillStyle = col.forceGravity || '#2563eb'; + ctx.beginPath(); ctx.arc(cx, cy, planetR, 0, Math.PI*2); ctx.fill(); + ctx.strokeStyle = '#fff'; + ctx.lineWidth = 1.5; + ctx.stroke(); + ctx.fillStyle = '#fff'; + ctx.font = 'bold 12px Inter,sans-serif'; + ctx.textAlign = 'center'; + ctx.fillText('M', cx, cy + 4); + ctx.textAlign = 'left'; + /* trail */ + if (st.trail.length > 1){ + ctx.strokeStyle = col.velocity || '#0891b2'; + ctx.lineWidth = 1.8; + ctx.beginPath(); + ctx.moveTo(st.trail[0].x, st.trail[0].y); + for (let i = 1; i < st.trail.length; i++) ctx.lineTo(st.trail[i].x, st.trail[i].y); + ctx.stroke(); + } + /* спутник */ + ctx.fillStyle = st.crashed ? col.fail : (col.acceleration || '#ea580c'); + ctx.beginPath(); ctx.arc(st.x, st.y, 7, 0, Math.PI*2); ctx.fill(); + ctx.strokeStyle = '#fff'; ctx.lineWidth = 1.2; ctx.stroke(); + /* вектор v */ + if (st.running || st.t === 0){ + const v = Math.sqrt(st.vx*st.vx + st.vy*st.vy); + const k = v > 0 ? 40 / v : 0; + B().arrow(ctx, st.x, st.y, st.x + st.vx*k, st.y + st.vy*k, col.velocity || '#0891b2', 2); + } + } + + document.getElementById('F4-go').addEventListener('click', ()=>{ + if (st.crashed || st.escaped) reset(); + if (!st.running) { + reset(); + st.running = true; + document.getElementById('F4-go').textContent = 'Пауза'; + } else { + st.running = false; + document.getElementById('F4-go').textContent = 'Запустить'; + } + }); + document.getElementById('F4-reset').addEventListener('click', reset); + document.getElementById('F4-circle').addEventListener('click', setCircular); + ['F4-M','F4-v0','F4-an'].forEach(id => document.getElementById(id).addEventListener('input', ()=>{ + readSliders(); + if (!st.running) reset(); + })); + + readSliders(); + reset(); + B().startLoop('F4', cv, tick); + return true; +} + +if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F4', { init: init, cleanup: function(){} }); +else document.addEventListener('DOMContentLoaded', ()=>{ + if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F4', { init: init, cleanup: function(){} }); +}); + +})(); diff --git a/frontend/textbooks/physics_9_ch1.html b/frontend/textbooks/physics_9_ch1.html index 52b1e76..d995959 100644 --- a/frontend/textbooks/physics_9_ch1.html +++ b/frontend/textbooks/physics_9_ch1.html @@ -806,7 +806,7 @@ function _injectTasks(id){ var body = document.getElementById(id + '-body'); if(!body || body.querySelector('.legacy-tasks')) return; body.insertAdjacentHTML('beforeend', _makeTaskBlock(id)); - setTimeout(function(){ try { if(window.renderTask) window.renderTask(id); if(window.renderNav) window.renderNav(id); } catch(e){} try { if(window.PHYS9_FINALS_INIT && /^final\d+$/.test(id)) window.PHYS9_FINALS_INIT(id); } catch(e){ console.warn("phys9 final init:", e.message); } try { if(window.PHYS9_CH1_WIDGETS && window.PHYS9_CH1_WIDGETS[id]) window.PHYS9_CH1_WIDGETS[id](); } catch(e){ console.warn('phys9 widget init:', e.message); } try { if(window.PHYS9_FLAG_BASE){ if(id==='p5') window.PHYS9_FLAG_BASE.mount('F1','p5'); else if(id==='p9') window.PHYS9_FLAG_BASE.mount('F2','p9'); } } catch(e){ console.warn('phys9 flag init:', e.message); } }, 60); + setTimeout(function(){ try { if(window.renderTask) window.renderTask(id); if(window.renderNav) window.renderNav(id); } catch(e){} try { if(window.PHYS9_FINALS_INIT && /^final\d+$/.test(id)) window.PHYS9_FINALS_INIT(id); } catch(e){ console.warn("phys9 final init:", e.message); } try { if(window.PHYS9_CH1_WIDGETS && window.PHYS9_CH1_WIDGETS[id]) window.PHYS9_CH1_WIDGETS[id](); } catch(e){ console.warn('phys9 widget init:', e.message); } try { if(window.PHYS9_FLAG_BASE){ if(id==='p5') window.PHYS9_FLAG_BASE.mount('F1','p5'); else if(id==='p9') window.PHYS9_FLAG_BASE.mount('F2','p9'); else if(id==='p11') window.PHYS9_FLAG_BASE.mount('F3','p11'); } } catch(e){ console.warn('phys9 flag init:', e.message); } }, 60); } var _origEnsureBuilt = ensureBuilt; ensureBuilt = function(id){ _origEnsureBuilt(id); _injectTasks(id); }; diff --git a/frontend/textbooks/physics_9_ch2.html b/frontend/textbooks/physics_9_ch2.html index 7e01b8a..409ee91 100644 --- a/frontend/textbooks/physics_9_ch2.html +++ b/frontend/textbooks/physics_9_ch2.html @@ -9,6 +9,7 @@ + @@ -789,7 +790,7 @@ function _injectTasks(id){ var body = document.getElementById(id + '-body'); if(!body || body.querySelector('.legacy-tasks')) return; body.insertAdjacentHTML('beforeend', _makeTaskBlock(id)); - setTimeout(function(){ try { if(window.renderTask) window.renderTask(id); if(window.renderNav) window.renderNav(id); } catch(e){} try { if(window.PHYS9_FINALS_INIT && /^final\d+$/.test(id)) window.PHYS9_FINALS_INIT(id); } catch(e){ console.warn("phys9 final init:", e.message); } try { if(window.PHYS9_CH2_WIDGETS && window.PHYS9_CH2_WIDGETS[id]) window.PHYS9_CH2_WIDGETS[id](); } catch(e){ console.warn('phys9 widget init:', e.message); } }, 60); + setTimeout(function(){ try { if(window.renderTask) window.renderTask(id); if(window.renderNav) window.renderNav(id); } catch(e){} try { if(window.PHYS9_FINALS_INIT && /^final\d+$/.test(id)) window.PHYS9_FINALS_INIT(id); } catch(e){ console.warn("phys9 final init:", e.message); } try { if(window.PHYS9_CH2_WIDGETS && window.PHYS9_CH2_WIDGETS[id]) window.PHYS9_CH2_WIDGETS[id](); } catch(e){ console.warn('phys9 widget init:', e.message); } try { if(window.PHYS9_FLAG_BASE){ if(id==='p17') window.PHYS9_FLAG_BASE.mount('F4','p17'); } } catch(e){ console.warn('phys9 flag init:', e.message); } }, 60); } var _origEnsureBuilt = ensureBuilt; ensureBuilt = function(id){ _origEnsureBuilt(id); _injectTasks(id); };