From 0c8a4b2b82c2c32364df64fc2a5bf2c6c83d1740 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 8 Jun 2026 22:42:18 +0000 Subject: [PATCH] Presenter: auto-reconnect when the presenter window is refreshed The projector window already reconnected on refresh via its persistent window.name ("projector") and window.opener reference. The presenter window had neither, so refreshing it lost the link to the projector and required pressing Ctrl+P again. Name the presenter window "presenter" when entering presenter mode so that on reload it can identify itself and re-acquire the existing projector via a named-window lookup (open("", "projector")), which returns the existing window without reloading it. Both windows now reconnect automatically on refresh and re-link each other's references. --- presenter/README.md | 6 ++---- presenter/plugin.js | 45 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/presenter/README.md b/presenter/README.md index 4c3fba3..89ecee3 100644 --- a/presenter/README.md +++ b/presenter/README.md @@ -20,11 +20,9 @@ This will make the current window the Presenter view, and will open another wind You are meant to move the audience view to the projector screen, and interact with the presenter view yourself. Navigation in the two views is synced (including `.delayed` items). -If you refresh the presenter view, you need to press Ctrl + P again to reconnect with the audience view, -but it will reuse the same tab. -On the other hand, if you refresh the audience view, the presenter view will automatically reconnect. +Refreshing either window will automatically reconnect the two views, reusing the existing tabs. -To exit presenter view, simply refresh the window. +To exit presenter view, close the audience window, then refresh the presenter window. ## Limitations diff --git a/presenter/plugin.js b/presenter/plugin.js index a4b000c..948c95f 100644 --- a/presenter/plugin.js +++ b/presenter/plugin.js @@ -3,29 +3,58 @@ import { $$ } from "@inspirejs/core/util"; export const hasCSS = true; +// Set up this window as the presenter, connected to the given projector window +function connectToProjector (projector) { + Inspire.projector = projector; + + if (projector?.Inspire) { + // Make sure the projector points back to us (in case we were reloaded) + projector.Inspire.presenter = window; + } + + // Switch this one to presenter view + document.body.classList.add("presenter", "show-next"); + + // Are there
elements in the current slide? Open them + $$("details.notes", Inspire.currentSlide).forEach(d => (d.open = true)); +} + Inspire.hooks.add({ "init-end": me => { if (window.name === "projector" && window.opener && opener.Inspire) { - // Projector window was reloaded + // Projector window was (re)loaded: reconnect to the presenter document.body.classList.add("projector"); Inspire.presenter = opener; Inspire.presenter.Inspire.projector = window; } + else if (window.name === "presenter") { + // Presenter window was reloaded: try to reconnect to the projector. + // Passing an empty URL returns the existing window (if any) without + // reloading it. If none exists, the lookup yields a blank window (or + // is blocked and yields null), which we discard. + let projector = open("", "projector"); + + if (projector && projector !== window && projector.Inspire) { + connectToProjector(projector); + } + else { + // No projector to reconnect to; clean up and forget we were one + projector?.close(); + window.name = ""; + } + } }, keyup: env => { // Ctrl+P : Open Presenter view if (env.letter === "P") { + // Name this window so it can find the projector again after a refresh + window.name = "presenter"; + // Open new window for projector view - Inspire.projector = open(location, "projector"); + connectToProjector(open(location, "projector")); // Get the focus back window.focus(); - - // Switch this one to presenter view - document.body.classList.add("presenter", "show-next"); - - // Are there
elements in the current slide? Open them - $$("details.notes", Inspire.currentSlide).forEach(d => (d.open = true)); } }, slidechange: env => {