Files
espresso_frame/server/app/static/frame_header.js
T
tfaour 37bd657299
Build and push server image / test (push) Successful in 49s
Build and push server image / build-and-push (push) Successful in 1m56s
Widget system Phase 2: full cutover to widget-based rendering
device.py's mode-keyed dispatch is replaced by a real compositor:
load a frame's widgets, compute pixel rects via app/grid.py, render
each through its widget module, and composite with render_panel.
Physical NEXT/BACK buttons now execute each frame's assigned
FrameButtonAction rows instead of one hardcoded per-mode action.

api_frames.py, manage.py, and common.py's build_manage_content are
repointed to read/write the frame's widget config rows instead of
the old Frame columns, and every settings page (Photos/Calendar/
Whiteboard tabs) now pre-fills its form from the same widget config
the write endpoints actually save to -- previously the read and
write sides would have silently diverged. The old mode selector and
photo-inlay checkbox are removed along with their now-inert wiring;
arbitrary widget placement subsumes what the fixed inlay split did.

Ships together with Phase 1 (per-type render/action modules) since
splitting the read/write cutover across deploys would have left
settings changes with no visible effect.
2026-07-24 09:26:28 -04:00

58 lines
1.9 KiB
JavaScript

// Page-header controls shared by every per-frame page (Photos/
// Configuration/Calendar/Whiteboard/Stats): the frame-name pencil-edit,
// living outside the tab structure since it applies regardless of which
// tab is open. Depends on window.FRAME_API (set per-page) 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_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_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();
});
})();