diff --git a/frontend/js/labs/_pilots.js b/frontend/js/labs/_pilots.js deleted file mode 100644 index e897b8e..0000000 --- a/frontend/js/labs/_pilots.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; -/* - * Пилотная регистрация в LabRegistry (Фаза 0 контент-движка). - * - * Доказывает паритет: каталог/открытие/теория этих 3 симуляций идут через реестр. - * Загружается ПОСЛЕДНИМ среди labs-скриптов, поэтому P_* (lab-glue.js), - * THEORY (lab-init.js) и _openXxx (graph/quadratic/pendulum.js) уже определены. - * preview задан функцией (ленивое вычисление в renderSims) — безопасно к порядку. - * - * В Фазе 1 регистрация переедет в сами sim-файлы, а этот файл будет удалён. - */ -(function () { - if (!window.LabRegistry) return; - var R = window.LabRegistry; - - R.register({ - id: 'graph', cat: 'math', - title: 'График функции', desc: 'Постройте и исследуйте графики функций', - preview: function () { return (typeof P_GRAPH !== 'undefined') ? P_GRAPH : ''; }, - theory: (typeof THEORY !== 'undefined') ? THEORY.graph : null, - open: function () { _openGraph(); }, - stop: function () { /* нет анимационного цикла */ }, - destroy: function () { /* нет ресурсов для освобождения */ } - }); - - R.register({ - id: 'quadratic', cat: 'math', - title: 'Квадратное уравнение', desc: 'Дискриминант, корни, теорема Виета', - preview: function () { return (typeof P_QUADRATIC !== 'undefined') ? P_QUADRATIC : ''; }, - theory: (typeof THEORY !== 'undefined') ? THEORY.quadratic : null, - open: function () { _openQuadratic(); }, - stop: function () { /* нет анимационного цикла */ }, - destroy: function () { /* нет ресурсов для освобождения */ } - }); - - R.register({ - id: 'pendulum', cat: 'phys', - title: 'Маятник', desc: 'Колебания, период, затухание', - preview: function () { return (typeof P_PENDULUM !== 'undefined') ? P_PENDULUM : ''; }, - theory: (typeof THEORY !== 'undefined') ? THEORY.pendulum : null, - open: function () { _openPendulum(); }, - stop: function () { if (typeof pendSim !== 'undefined' && pendSim && pendSim.stop) pendSim.stop(); }, - destroy: function () { if (typeof pendSim !== 'undefined' && pendSim && pendSim.stop) pendSim.stop(); } - }); -})(); diff --git a/frontend/js/labs/_register-all.js b/frontend/js/labs/_register-all.js new file mode 100644 index 0000000..a31b376 --- /dev/null +++ b/frontend/js/labs/_register-all.js @@ -0,0 +1,99 @@ +'use strict'; +/* + * Контент-движок, Фаза 1 — data-driven регистрация ВСЕХ симуляций в LabRegistry. + * + * Вместо ручного переписывания 40 манифестов модуль строит их из единых источников: + * - метаданные (id/cat/title/desc) и preview — из массива SIMS (lab-glue.js); + * - теория — из объекта THEORY (lab-init.js); + * - поведение open(ctx) — из карты OPEN ниже (обёртки над глобальными _openXxx). + * Это структурно гарантирует паритет с прежним каталогом и диспетчеризацией. + * + * Подключается ПОСЛЕДНИМ среди labs-скриптов (defer), поэтому SIMS, THEORY и все + * _openXxx уже определены. Останов/закрытие симуляций по-прежнему выполняет + * «дробовик» _pauseAllSims()/closeSim() (точный паритет) — поэтому stop/destroy + * в манифестах не задаются на этом этапе. + * + * После регистрации if-цепочка в openSim() становится мёртвой и удалена. + * + * В Фазе 1 заменил пилотный _pilots.js. SIMS/THEORY остаются источниками данных + * (SIMS → БД в Фазе 4, THEORY сворачивается в манифесты позже). + */ +(function () { + if (!window.LabRegistry) return; + if (typeof SIMS === 'undefined') return; + var R = window.LabRegistry; + var T = (typeof THEORY !== 'undefined') ? THEORY : {}; + + // id -> open(ctx). ctx.arg — параметр deep-link (после двоеточия): stereo:cube и т.п. + var OPEN = { + graph: function (c) { _openGraph(); }, + projectile: function (c) { _openProjectile(); }, + collision: function (c) { _openCollision(); }, + triangle: function (c) { _openTriangle(); }, + trigcircle: function (c) { _openTrigCircle(); }, + emfield: function (c) { _openEMField(c.arg || 'E'); }, + molphys: function (c) { _openMolPhys(c.arg); }, + circuit: function (c) { _openCircuit(); }, + chemistry: function (c) { _openChemistry(c.arg); }, + dynamics: function (c) { _openDynamics(c.arg); }, + crystal: function (c) { _openCrystal(); }, + orbitals: function (c) { _openOrbitals(); }, + stereo: function (c) { _openStereo(c.arg); }, + chemsandbox: function (c) { _openChemSandbox(); }, + celldivision: function (c) { _openCellDivision(); }, + photosynthesis: function (c) { _openPhotosynthesis(); }, + angrybirds: function (c) { _openAngryBirds(); }, + quadratic: function (c) { _openQuadratic(); }, + normaldist: function (c) { _openNormalDist(); }, + graphtransform: function (c) { _openGraphTransform(); }, + pendulum: function (c) { _openPendulum(); }, + equilibrium: function (c) { _openEquilibrium(); }, + opticsbench: function (c) { _openOpticsBench(c.arg || 'lens'); }, + isoprocess: function (c) { _openIsoprocess(); }, + titration: function (c) { _openTitration(); }, + probability: function (c) { _openProbability(); }, + bohratom: function (c) { _openBohrAtom(); }, + electrolysis: function (c) { _openElectrolysis(); }, + race: function (c) { _openRace(); }, + waves: function (c) { _openWaves(); }, + hydrostatics: function (c) { _openHydro(c.arg); }, + radioactive: function (c) { _openRadioactive(); }, + geometry: function (c) { _openGeometry(); }, + logic: function (c) { _openLogic(); }, + heatengine: function (c) { _openHeatEngine(); }, + stoichiometry: function (c) { _openStoich(); }, + qualanalysis: function (c) { _openQualAnalysis(); }, + periodic: function (c) { _openPeriodic(); }, + organic: function (c) { _openOrganic(); }, + solutions: function (c) { _openSolutions(); } + }; + + SIMS.forEach(function (s) { + if (!s.id) return; // "Скоро" — карточка без id + var open = OPEN[s.id]; + if (!open) { // подстраховка: незамапленный id оставляем legacy-пути + if (window.console) console.warn('[LabRegistry] нет open() для', s.id); + return; + } + R.register({ + id: s.id, + cat: s.cat, + title: s.title, + desc: s.desc, + preview: s.preview, // уже готовая SVG-строка (P_* вычислены в SIMS) + theory: T[s.id] || null, + open: open + // stop/destroy: глобальный «дробовик» _pauseAllSims()/closeSim() — паритет + }); + }); + + // Алиасы deep-link → канонический id[:arg]. Диспетчер openSim() нормализует их + // перед обращением к реестру (карточек у алиасов нет — только прямые ссылки). + window.LAB_SIM_ALIASES = { + magnetic: 'emfield:B', + coulomb: 'emfield:E', + thinlens: 'opticsbench:lens', + mirrors: 'opticsbench:mirror', + refraction: 'opticsbench:refraction' + }; +})(); diff --git a/frontend/js/labs/lab-init.js b/frontend/js/labs/lab-init.js index 597aaa0..1986a83 100644 --- a/frontend/js/labs/lab-init.js +++ b/frontend/js/labs/lab-init.js @@ -106,68 +106,22 @@ // load theory for this sim loadTheory(id.includes(':') ? id.split(':')[0] : id); - // Контент-движок: мигрированные симуляции открываются через реестр. - if (window.LabRegistry && window.LabRegistry.has(id)) { - const _m = window.LabRegistry.get(id); - const _arg = id.includes(':') ? id.split(':')[1] : undefined; + // ── Контент-движок (Фаза 1): диспетчеризация через реестр ── + // Все каталожные симуляции зарегистрированы в _register-all.js. + // Алиасы deep-link (magnetic/coulomb/thinlens/mirrors/refraction) нормализуем + // в канонический id[:arg] перед обращением к реестру. + var _aliases = window.LAB_SIM_ALIASES || {}; + var _cid = _aliases[id.split(':')[0]] || id; + if (window.LabRegistry && window.LabRegistry.has(_cid)) { + const _m = window.LabRegistry.get(_cid); + const _arg = _cid.includes(':') ? _cid.split(':')[1] : undefined; window.LabRegistry.setActive(_m); - try { _m.open({ id: id, arg: _arg }); } catch (e) { console.error('[LabRegistry] open failed:', id, e); } + try { _m.open({ id: _cid, arg: _arg }); } + catch (e) { console.error('[LabRegistry] open failed:', _cid, e); } if (window.lucide) lucide.createIcons(); return; } - - if (id === 'graph') _openGraph(); - if (id === 'projectile') _openProjectile(); - if (id === 'collision') _openCollision(); - if (id === 'triangle') _openTriangle(); - if (id === 'trigcircle') _openTrigCircle(); - if (id === 'magnetic') _openEMField('B'); // backward compat: #magnetic → emfield B-mode - if (id === 'coulomb') _openEMField('E'); // backward compat: #coulomb → emfield E-mode - if (id === 'emfield') _openEMField('E'); - if (id.startsWith('emfield:')) { _openEMField(id.split(':')[1]); } - if (id === 'molphys') _openMolPhys(); - if (id.startsWith('molphys:')) { _openMolPhys(id.split(':')[1]); } - if (id === 'circuit') _openCircuit(); - if (id === 'chemistry') _openChemistry(); - if (id.startsWith('chemistry:')) { _openChemistry(id.split(':')[1]); } - if (id === 'dynamics') _openDynamics(); - if (id.startsWith('dynamics:')) { _openDynamics(id.split(':')[1]); } - if (id === 'crystal') _openCrystal(); - if (id === 'orbitals') _openOrbitals(); - if (id === 'stereo') _openStereo(); - if (id.startsWith('stereo:')) { _openStereo(id.split(':')[1]); } - if (id === 'chemsandbox') _openChemSandbox(); - if (id === 'celldivision') _openCellDivision(); - if (id === 'photosynthesis') _openPhotosynthesis(); - if (id === 'angrybirds') _openAngryBirds(); - if (id === 'quadratic') _openQuadratic(); - if (id === 'normaldist') _openNormalDist(); - if (id === 'graphtransform') _openGraphTransform(); - if (id === 'pendulum') _openPendulum(); - if (id === 'equilibrium') _openEquilibrium(); - if (id === 'opticsbench') _openOpticsBench('lens'); - if (id.startsWith('opticsbench:')) _openOpticsBench(id.split(':')[1]); - if (id === 'thinlens') _openOpticsBench('lens'); // backward compat - if (id === 'mirrors') _openOpticsBench('mirror'); // backward compat - if (id === 'refraction') _openOpticsBench('refraction'); // backward compat - if (id === 'isoprocess') _openIsoprocess(); - if (id === 'titration') _openTitration(); - if (id === 'probability') _openProbability(); - if (id === 'bohratom') _openBohrAtom(); - if (id === 'electrolysis') _openElectrolysis(); - if (id === 'race') _openRace(); - if (id === 'waves') _openWaves(); - if (id === 'hydrostatics') _openHydro(); - if (id.startsWith('hydrostatics:')) _openHydro(id.split(':')[1]); - if (id === 'radioactive') _openRadioactive(); - if (id === 'geometry') _openGeometry(); - if (id === 'logic') _openLogic(); - if (id === 'heatengine') _openHeatEngine(); - if (id === 'stoichiometry') _openStoich(); - if (id === 'qualanalysis') _openQualAnalysis(); - if (id === 'periodic') _openPeriodic(); - if (id === 'organic') _openOrganic(); - if (id === 'solutions') _openSolutions(); + if (window.console) console.warn('[LabRegistry] неизвестная симуляция:', id); } function _simShow(elId) {