'use strict'; /* * LabRegistry — единый реестр симуляций лаборатории (контент-движок). * * Цель: симуляции описываются декларативным манифестом и сами себя регистрируют, * вместо захардкоженных массивов (SIMS), if-цепочек (openSim) и объектов (THEORY). * * Манифест: * { * id: 'pendulum', // уникальный, без ':arg' * cat: 'phys', // math | phys | chem | bio | game * title: 'Маятник', * desc: 'Колебания, период…', * preview: string | function(), // SVG-разметка карточки (функция вычисляется лениво) * theory: { title, sections[] },// объект для панели теории (как в THEORY) * bodyId: 'sim-pendulum', // (опц.) id тела; mount() — для ленивого создания DOM (Фаза 2) * mount: function(host){}, // (опц.) ленивое монтирование тела * open: function(ctx){}, // ctx = { id, arg } — открыть/инициализировать * stop: function(){}, // (опц.) остановить анимации (не разрушая) * destroy: function(){}, // (опц.) полностью закрыть; по умолчанию == stop * subject, grade, topics // (опц.) курикулумные поля (Фаза 5) * } * * Загружается ПЕРВЫМ среди labs-скриптов, чтобы window.LabRegistry существовал * к моменту исполнения тел остальных модулей. */ (function () { var _list = []; // манифесты в порядке регистрации var _byId = {}; // id -> манифест var _active = null; // текущая открытая симуляция function _baseId(id) { return id == null ? id : String(id).split(':')[0]; } function register(m) { if (!m || !m.id) return null; if (Object.prototype.hasOwnProperty.call(_byId, m.id)) { // перерегистрация: заменить на месте, сохранив позицию for (var i = 0; i < _list.length; i++) { if (_list[i].id === m.id) { _list[i] = m; break; } } } else { _list.push(m); } _byId[m.id] = m; return m; } function get(id) { var b = _baseId(id); return Object.prototype.hasOwnProperty.call(_byId, b) ? _byId[b] : null; } function has(id) { return !!get(id); } function all() { return _list.slice(); } function setActive(m) { _active = m || null; } function stopActive() { if (_active && typeof _active.stop === 'function') { try { _active.stop(); } catch (e) { /* noop */ } } } function destroyActive() { if (_active) { if (typeof _active.destroy === 'function') { try { _active.destroy(); } catch (e) { /* noop */ } } else if (typeof _active.stop === 'function') { try { _active.stop(); } catch (e) { /* noop */ } } } _active = null; } function active() { return _active; } // Разрешить preview (строка или функция) в готовую разметку. function resolvePreview(m) { if (!m) return ''; var p = m.preview; if (typeof p === 'function') { try { return p() || ''; } catch (e) { return ''; } } return p || ''; } window.LabRegistry = { register: register, get: get, has: has, all: all, setActive: setActive, stopActive: stopActive, destroyActive: destroyActive, active: active, resolvePreview: resolvePreview }; })();