generated from Labyricorn/labyricorn-project-template
Step 6.2 Complete — Museum Gallery reference exhibit and Contract 5.3 spec
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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. */
|
||||
var bus = window.MuseumGallerySurfaceBus.createOwner(core);
|
||||
var priorOnEvent = core.onEvent;
|
||||
core.onEvent = function (event) {
|
||||
if (typeof priorOnEvent === 'function') priorOnEvent(event);
|
||||
sync();
|
||||
Shell.setText(subscriberCountEl, String(bus.attachedCount()));
|
||||
};
|
||||
|
||||
/* 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 };
|
||||
})();
|
||||
Reference in New Issue
Block a user