/* * Museum Gallery — Control Room boot. * * This is the ONLY document in this exhibit that constructs an Exhibit * State Core. Every other surface (artifact.html, info-wall.html) attaches * to the Core this document creates, over the exhibit-internal bus in * surface-bus.js -- see README.md. * * This document remains fully standalone: nothing below requires any other * surface to be open, and nothing below requires XZBT-NGN. The optional * HostTransport at the bottom lets an NGN attach later, exactly like every * other reference exhibit -- it changes nothing about ordinary operation * when no host ever connects. */ (function () { 'use strict'; var Shell = window.XZBTShell; var el = Shell.el; var gallery = new window.MuseumGalleryExhibit.Gallery(); var core = window.MuseumGalleryContract.create(gallery); var announcer = new Shell.Announcer({ node: el('announcement'), idleText: 'Control Room standing by.' }); var artifactSelect = el('artifact-select'); var artifactDescriptor = core.catalog.get('artifact.selected'); artifactDescriptor.options.forEach(function (opt) { var option = document.createElement('option'); option.value = opt.value; option.textContent = opt.label; artifactSelect.appendChild(option); }); var lightingRange = el('lighting-range'); var rotationRange = el('rotation-range'); var labelsButton = el('labels-button'); var subscriberCountEl = el('subscriber-count'); function sync() { var values = core.stateSnapshot().values; Shell.setText(el('artifact-name'), window.MuseumGalleryExhibit.ARTIFACT_LABELS[values['artifact.selected']]); artifactSelect.value = values['artifact.selected']; Shell.setText(el('lighting-readout'), Shell.formatPercent(values['lighting.level'])); Shell.setText(el('lighting-panel-readout'), Shell.formatPercent(values['lighting.level'])); lightingRange.value = values['lighting.level']; Shell.setText(el('rotation-readout'), values['rotation.speed'].toFixed(1) + 'x'); Shell.setText(el('rotation-panel-readout'), values['rotation.speed'].toFixed(1) + 'x'); rotationRange.value = values['rotation.speed']; Shell.setText(el('labels-readout'), values['labels.enabled'] ? 'ON' : 'OFF'); labelsButton.setAttribute('aria-pressed', values['labels.enabled'] ? 'true' : 'false'); } sync(); /* Every native control here calls the SAME core.applyMutation/invokeAction * chokepoint a contract set/invoke (from NGN) or a bus-relayed mutation * (from a non-primary surface) would call. There is exactly one path. */ artifactSelect.addEventListener('change', function () { core.applyMutation('artifact.selected', artifactSelect.value, 'ui'); }); lightingRange.addEventListener('input', function () { core.applyMutation('lighting.level', parseFloat(lightingRange.value), 'ui'); }); rotationRange.addEventListener('input', function () { core.applyMutation('rotation.speed', parseFloat(rotationRange.value), 'ui'); }); labelsButton.addEventListener('click', function () { var current = core.stateSnapshot().values['labels.enabled']; core.applyMutation('labels.enabled', !current, 'ui'); }); el('flash-button').addEventListener('click', function () { core.invokeAction('action.spotlight-flash', {}, 'ui'); announcer.flash('Spotlight flashed.'); }); /* The bus owner forwards every core event (however it originated -- this * document's own controls, or a mutate request relayed from another * surface) to attached surfaces, and answers their attach requests with a * fresh snapshot read straight from this Core -- never a second * computation. */ function updateSubscriberCount(count) { Shell.setText(subscriberCountEl, String(count)); } var bus = window.MuseumGallerySurfaceBus.createOwner(core, { onConnectionChange: updateSubscriberCount }); updateSubscriberCount(bus.attachedCount()); var priorOnEvent = core.onEvent; core.onEvent = function (event) { if (typeof priorOnEvent === 'function') priorOnEvent(event); sync(); }; /* Optional NGN attachment -- same optional transport every reference * exhibit includes. Museum Gallery Phase 6.2 does not exercise this path; * see the verification document's known-limitations section. */ var transport = new window.XZBTHostTransport({ core: core, onMessage: function () { el('contract-status').textContent = 'host attached'; } }); window.__museumGalleryDebug = { core: core, gallery: gallery, bus: bus, transport: transport, sync: sync }; })();