{# The one place the viewer's ground colour is not the app's. A
transmitted-light image IS its white background, and the dark
shell behind it reads as a shadow the scanner never recorded. #}
{# The calibration pencil. Parked here and moved into
OpenSeadragon's container by views/scaleCalibration.js, which
then keeps it beside the scale bar -- see that file. #}
{% include "_scale_calibration_float.html" %}
Channels
{% if data.active_tool_panels.tool_panel_legacy_slot %}
{% include data.active_tool_panels.tool_panel_legacy_slot %}
{% endif %}
{# What takes the centre spinner down. The spinner is in this page's own markup
and visible from first paint, so this has to be loaded before main.js builds
the viewer and calls watch() on it -- deferred scripts run in document order,
which is the whole reason it sits above rather than in base.html with the
other services. Viewer-only: no other page has the element. #}
{# Grab/grabbing on the OSD canvas. Deferred and unconditional within this
branch: it installs three document-level listeners that cost nothing until
a press lands inside a `.openseadragon-canvas`, which only this page has --
either viewer's. #}
{# Before main.js and deferred like it, so it is defined by the time init()
sees a pending mask job. Loaded here rather than in base.html because the
pending state belongs to a viewer looking at the project whose mask is
converting -- every other page would carry a listener with nothing to
listen for. #}
{# Brightfield display adjustments. Deferred like main.js and loaded
unconditionally: it does nothing at all when its sliders are absent, and
gating the tag on image_kind would put a second thing in this page that has
to agree with the staged markup above. It runs after main.js has built the
base image layer's card, which is where those sliders will be by then. #}
{# Here rather than base.html for the same reason: the only things that open it
are the channel list and a registered layer's channel panel, and both are the
viewer's. Only has to exist by the time the user clicks one of those upload
buttons, so deferred is ample. #}
{# What the last sample arranged, on its way into this one. BEFORE main.js
and deferred like it, so the snapshot is on hand by the time init() builds
the channel slots -- the sidebar reads it while deciding which channels to
turn on, which is the earliest any of it is wanted. Viewer-only: nothing
else has an arrangement to carry. #}
{# Previous / Next for a sample that belongs to a dataset. Deliberately
independent of main.js: a sample whose image will not open has no viewer at
all, and this is the way out of it. It mounts off its own fetch and asks
the viewer for nothing. #}
{# Why the canvas is empty, when it is. Before main.js, which calls it from
the boot path the moment a load comes back without an image. #}
{% else %}
{# The home page when nothing is registered yet.
One vertical run of four things, in the order they are needed: which
machine, which image, the typed way in, and the way out to the full import.
The one gesture -- pick an image, land in the viewer -- is what this page
is for, and it is the page's own control rather than a button that opens
the import dialog: a modal covering an otherwise empty page is a step, not
a shortcut. What it is NOT any more is a second importer. The Load button
POSTs to `/import/sample`, the same route the dialog submits to, so a
Xenium run dropped here brings its transcripts and its table with it
instead of being refused for not being one image. See
views/quickViewLanding.js.
The footer is the way to everything that needs a decision -- several
samples in one folder, a name, a dataset, a question answered. That is the
dialog, and it is one link rather than the page's headline act. #}
Plexora
{# Which machine the image is on, asked ONCE for the whole page.
Everywhere else this switch sits inside the row of the one field it
governs; here it governs two controls -- the File/Folder pair and
the path box -- so it stands above them both, and asking twice on a
page whose whole job is one image is what that avoids.
services/dataLocation.js renders the [L|R] chip and the place button
into `#quick_view_where_control`. The label and the caption beside
it are this page's own: two bare letters standing alone explain
nothing without a word next to them, and on a form the word they do
not need is supplied by the box they sit against. #}
Image location
{# Local only. On Remote the switch's own place button stands here
instead and names the machine -- and unlike this caption it is
clickable, which is how the machine is changed without toggling
back through Local and losing the box on the way. #}
{# Where the share reports itself -- "Sharing…", "Ready on hpc", "Not
connected yet". Under the switch rather than under the path row,
because it is news about the machine and not about the file. #}
{# The page's primary action, built by views/quickViewLanding.js out of
the shared File/Folder control (services/browsePicker.js) so the
format hints under each word are defined in exactly one place.
Always both halves, on every platform. An OME-Zarr image is a folder
and an OME-TIFF is a file; which one you have is a fact about your
format, and the example line under each word answers it rather than
asking. This used to be one target that opened the question as a
popup afterwards -- on the machines that could not answer it in one
dialog, which is every machine but a Mac. #}
{# No Browse beside it any more: the pair above IS this page's
file browser, and a second route to the same dialog made the
big obvious target look like the slower of the two. #}
{# A live region that is always in the DOM and empty when it has
nothing to say (`:empty` hides it), rather than one toggled with
`hidden`: a region that appears and gains its text in the same tick
is the shape screen readers miss. Same idiom as
`.data-location-status` above it. #}
{# The three ways out, where the wizard link used to be and for the
same reason: this page takes one pick and opens it, and anything
that needs a decision first -- or that is not an import at all --
belongs somewhere else. One paragraph and ` `s rather than a
block each, so this stays the single muted line the design has under
the status and not a second section competing with the pair above.
First, the import dialog. `id="sample-import-home"` is what binds
it: views/importSample.js binds every "Import Sample..." on every
surface by id, so this needs no controller of its own. A