{% block title %}{% endblock %} {% block style %}{% endblock %} {# Must precede the two widgets below: both hand their popup to it on construction. #} {# After viewerSidebar (whose class it instantiates) and before layerManager (which mounts it). Both only have to be PRESENT -- the mount happens when a card is built -- but the order is what says so. #} {# Before the plugin assets at the bottom of this block: a layer section's own script may ask PlexoraLayerSections whether it is one. #} {# Before navbarControls.js and not deferred against it in any meaningful way: it installs one document-level keydown listener and paints the keys into the menu on DOMContentLoaded, so it only has to be present, not ordered against anything. #} {# Before browsePicker, which falls back to it when the machine running the server has no desktop for a native dialog to appear on -- the ordinary state of a compute node. Both are deferred, so both are parsed before either runs; the order is for readers. #} {# Before every field that mounts one. The switch is drawn on every launch now: there is always a second machine to mean something by "Remote" -- either the server is elsewhere, or a saved SSH connection could be -- and placePicker is what asks which one. remoteState comes first and everything else here reads from it: it owns the one poll that four surfaces used to run three of. It costs nothing on a page that never subscribes -- there is no timer until somebody does. #} {# The connection log, shared by the modal and the Settings page's cards. Before both of them: they call into it as they build. #} {# And what a connection says when it fails, shared by the same two surfaces for the same reason. Before both of them; before views/settingsPage.js too, which settings.html loads at the end of its own body, well after everything here. #} {# The navbar's connection icon. Deferred like the rest, which still runs it after pageBoot.js below (a normal script beats every deferred one), so PlexoraPage.register exists by the time this file's last line runs. It needs popoverPortal.js, loaded above with the other widgets. #} {# Says so before a scheduled job ends, from whichever page the user is on. After connectionModal.js, which its one button opens; passive, so it costs nothing while a connection sits settled. #} {# Local/Remote for every file button that has no switch of its own, which is all of them outside the core import forms. After placePicker.js and connectionModal.js, which it opens, and before toolLoader.js — a plugin's upload arrow must not be able to fire before the click delegate is on `document`. #} {# "Which file, and which machine is it on?" as one row, for the dialogs that ask it. After placePicker, connectionModal, fileLocation and dataLocation, all of which it calls into, and after browsePicker, whose attachBrowseButton it wires to its Browse button. #} {# THE slider, and the number box beside it. Every range input in Plexora is one of these, so it loads with the rest of the shell rather than with any one panel -- and before gradientRange.js and toolLoader.js, both of which build with it. #} {# The colour bar with two handles over it, and the palettes behind the button beside it. Core's because two plugins draw it -- Cell Explorer's numeric columns and the transcript density map -- and a control the user learns once should not be two implementations. Before toolLoader, like every other widget a plugin panel builds with. #} {# Core's own short-question dialog (ask / tell / choose / prompt). In base.html and not on the one page that uses it today, because a modal that only existed on one page would be one more thing every other page had to reach for `window.confirm` for -- and because the app shell disables a page's stylesheet when it leaves, so its CSS is in main.css and the two have to be loaded on the same terms. #} {# The bottom-right notice: something happened and nothing is waiting on you. On every page for the same reason confirmDialog is -- it is a core affordance whose CSS is in main.css, and a notice that only existed on one page would send every other page back to `window.alert`. Costs nothing until something calls show(): there is no host element until then. #} {# The dataset picker, on exactly the same terms: the open-project page's Move to… button and the import form's Dataset line ask the same question, and the import form does not load openProject.css. #} {# The `?` in the import dialog's header: what the importer accepts, as cards rather than prose. Before importSample.js, which is the only thing that opens it, and on the same terms as everything above -- it is a of its own and its CSS is in main.css. #} {# Import Sample, on the same terms as the two above: the library page's primary button, the viewer's "+ Add Layer" and the requirements modal's layer row all open it, and none of those three shares a stylesheet. After datasetPicker.js, whose picker is this dialog's Dataset row. #} {# Not deferred: every page controller below calls PlexoraPage.register at the top level of its own file, so the registry has to exist before any of them is parsed -- including the ones a routed page loads later. #} {# Deferred, because it looks for the viewer's own root element (#container) to decide whether this document has anything worth preserving -- and that element is in the content block, below. #} {# Assets of the plugin this page opened with, plus those of every plugin that is a LAYER section on this sample -- page_routes folds the two lists together, because both end up as the same tags here. Declared by the plugin (Plugin.scripts/styles) and cache-busted from its version, so core names no plugin and the eager path here cannot drift out of sync with the lazy path in tool_routes.py -- which is exactly what happened when these two {% endfor %} {# `data-plexora-datasource` is how appRouter.js decides whether this document has a live viewer worth preserving. Empty on every page that is not one, and that emptiness is the router's own off switch -- see limit 1 in its header. #} {% block content %}{% endblock %} {# Where an internal navigation renders when the router handles it instead of the browser. Empty and hidden on every ordinary page load -- it only ever holds a page fetched as a fragment while the viewer above waits, hidden but alive, for the user to come back to it. #}