Clicking the small preview thumbnail now opens an enlarged version in a dialog (fresh render, same as the old click-to-refresh), closable via the X button or a backdrop click -- mirroring #widget-dialog's existing pattern.
111 lines
4.1 KiB
JavaScript
111 lines
4.1 KiB
JavaScript
// Page-header controls shared by every per-frame page (Layout/
|
|
// Configuration/Stats): the frame-name pencil-edit, living outside the
|
|
// tab structure since it applies regardless of which tab is open.
|
|
// Depends on window.FRAME_BASE_API (a stable frame-level base set by
|
|
// every page -- unlike window.FRAME_API, which the Layout page's
|
|
// widget dialogs repoint to a widget-scoped base while one is open) and
|
|
// common.js's showStatus/apiError.
|
|
|
|
(function () {
|
|
var view = document.getElementById('frame-name-view');
|
|
var editRow = document.getElementById('frame-name-edit-row');
|
|
var pencil = document.getElementById('frame-name-pencil');
|
|
var input = document.getElementById('frame-name-input');
|
|
var textEl = document.getElementById('frame-name-text');
|
|
var saveBtn = document.getElementById('frame-name-save');
|
|
var cancelBtn = document.getElementById('frame-name-cancel');
|
|
if (!view || !window.FRAME_BASE_API) return;
|
|
|
|
function openEdit() {
|
|
input.value = textEl.textContent.trim();
|
|
view.style.display = 'none';
|
|
editRow.style.display = 'inline-flex';
|
|
input.focus();
|
|
input.select();
|
|
}
|
|
function closeEdit() {
|
|
editRow.style.display = 'none';
|
|
view.style.display = 'inline-flex';
|
|
}
|
|
|
|
pencil.addEventListener('click', openEdit);
|
|
cancelBtn.addEventListener('click', closeEdit);
|
|
|
|
async function save() {
|
|
var name = input.value.trim();
|
|
if (!name || name === textEl.textContent.trim()) {
|
|
closeEdit();
|
|
return;
|
|
}
|
|
try {
|
|
const resp = await fetch(`${window.FRAME_BASE_API}/config`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: new URLSearchParams({ name }),
|
|
});
|
|
if (!resp.ok) throw new Error(await apiError(resp));
|
|
textEl.textContent = name;
|
|
closeEdit();
|
|
showStatus(true, 'Renamed.');
|
|
} catch (e) {
|
|
showStatus(false, e.message);
|
|
}
|
|
}
|
|
saveBtn.addEventListener('click', save);
|
|
input.addEventListener('keydown', function (e) {
|
|
if (e.key === 'Enter') save();
|
|
if (e.key === 'Escape') closeEdit();
|
|
});
|
|
})();
|
|
|
|
// Live "how it's displaying" thumbnail. A real composite render (same
|
|
// pipeline /frame/image uses), not a cached snapshot, so it's on a slow
|
|
// poll rather than something tighter like the 10s device-status poll --
|
|
// no need to hit Immich/calendar/whiteboard sources that often just for
|
|
// a header thumbnail. Click enlarges it in a dialog (which also fetches
|
|
// a fresh render); clicking the enlarged image refreshes it again.
|
|
(function () {
|
|
var thumb = document.getElementById('frame-preview-thumb');
|
|
var dialog = document.getElementById('frame-preview-dialog');
|
|
var bigImg = document.getElementById('frame-preview-dialog-img');
|
|
var closeBtn = document.getElementById('frame-preview-dialog-close');
|
|
if (!thumb || !window.FRAME_BASE_API) return;
|
|
|
|
function previewUrl() {
|
|
return `${window.FRAME_BASE_API}/preview?t=${Date.now()}`;
|
|
}
|
|
function refreshThumb() {
|
|
thumb.src = previewUrl();
|
|
}
|
|
// Opening the dialog (or clicking the big image inside it) fetches a
|
|
// fresh render and keeps the header thumb in sync, so this single path
|
|
// covers both "enlarge" and the old click-to-refresh behavior.
|
|
function refreshBig() {
|
|
var url = previewUrl();
|
|
bigImg.src = url;
|
|
thumb.src = url;
|
|
}
|
|
|
|
thumb.addEventListener('click', function () {
|
|
if (!dialog) { refreshThumb(); return; }
|
|
refreshBig();
|
|
dialog.showModal();
|
|
});
|
|
refreshThumb();
|
|
setInterval(refreshThumb, 60000);
|
|
|
|
if (dialog && bigImg && closeBtn) {
|
|
bigImg.addEventListener('click', refreshBig);
|
|
closeBtn.addEventListener('click', function () { dialog.close(); });
|
|
// Same backdrop-click-to-close trick as #widget-dialog: a click that
|
|
// lands on the dialog element itself (not its content box) means the
|
|
// backdrop was hit.
|
|
dialog.addEventListener('click', function (e) {
|
|
if (e.target !== dialog) return;
|
|
var rect = dialog.getBoundingClientRect();
|
|
var inside = e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom;
|
|
if (!inside) dialog.close();
|
|
});
|
|
}
|
|
})();
|