Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion photomap/frontend/static/css/control-and-search-panels.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@
}

#controlPanel button.back-nav-disabled,
#controlPanel button.back-nav-disabled:hover {
#controlPanel button.back-nav-disabled:hover,
#controlPanel button.slideshow-disabled,
#controlPanel button.slideshow-disabled:hover {
opacity: 0.25;
cursor: default;
}
Expand Down
4 changes: 3 additions & 1 deletion photomap/frontend/static/javascript/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,9 @@ export function showHidePanelText(hide) {

// Listen for slide changes to update UI
window.addEventListener("slideChanged", () => {
// nothing to do here yet, but could be used to update UI elements
// Refresh the play/pause button so it grays out when we land on the last
// slide in sequential mode (and re-activates when we navigate away).
updateSlideshowButtonIcon();
});

// Toggle grid/swiper views
Expand Down
22 changes: 22 additions & 0 deletions photomap/frontend/static/javascript/slideshow.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { saveSettingsToLocalStorage, state } from "./state.js";
import { slideState } from "./slide-state.js";
import { isUmapFullscreen, toggleUmapWindow } from "./umap.js";

// SVG icons used for the button/menu
Expand All @@ -15,6 +16,14 @@ export function slideShowRunning() {
return !!state.single_swiper?.swiper?.autoplay?.running;
}

// In sequential mode there is a genuine end of the list, so a stopped slideshow
// resting on the final slide has nowhere to advance to. resolveOffset(+1)
// reports null only at that end (wrap mode always resolves to a real index, and
// random mode has no end), so it cleanly captures the "last slide" case.
function atSequentialEnd() {
return state.mode !== "random" && slideState.resolveOffset(+1).globalIndex === null;
}

// public: update the icon displayed on the start/stop button according to state
export function updateSlideshowButtonIcon() {
const container = document.getElementById("slideshowIcon");
Expand Down Expand Up @@ -42,6 +51,13 @@ export function updateSlideshowButtonIcon() {
btn.title = `Start Slideshow (${modeLabel})`;
}
}

// Gray out and disable Play when stopped on the final slide in sequential
// mode — there is nothing left to play. Never disable the Pause button.
if (btn) {
const disabled = !isRunning && atSequentialEnd();
btn.classList.toggle("slideshow-disabled", disabled);
}
}

// small fullscreen/play indicator (moved from events.js)
Expand Down Expand Up @@ -92,6 +108,12 @@ export async function toggleSlideshowWithIndicator(e) {
e.stopPropagation();
}

// Ignore clicks while parked on the last sequential slide (button is grayed
// out): there is nothing to start.
if (!slideShowRunning() && atSequentialEnd()) {
return;
}

if (slideShowRunning()) {
// pause
try {
Expand Down
Loading