92 lines
3.0 KiB
JavaScript
92 lines
3.0 KiB
JavaScript
const status = document.querySelector('#status');
|
|
const buttons = [...document.querySelectorAll('.group-button')];
|
|
const apiPrefix = document.body.dataset.apiPrefix;
|
|
|
|
function apiFetch(path, options = {}) {
|
|
return fetch(path, options);
|
|
}
|
|
|
|
function showStatus(message, persistent = false) {
|
|
status.textContent = message;
|
|
status.classList.add('visible');
|
|
if (!persistent) window.setTimeout(() => status.classList.remove('visible'), 1800);
|
|
}
|
|
|
|
async function refresh() {
|
|
try {
|
|
const response = await apiFetch(`${apiPrefix}/groups`, { cache: 'no-store' });
|
|
const body = await response.json();
|
|
if (!response.ok) throw new Error(body.error || 'Could not check the bridge');
|
|
const states = new Map(body.groups.map(group => [group.id, group]));
|
|
buttons.forEach(button => {
|
|
const group = states.get(button.dataset.id);
|
|
button.classList.toggle('is-on', group?.on === true);
|
|
button.querySelector('small').textContent = group?.scene || '';
|
|
});
|
|
status.classList.remove('visible');
|
|
} catch (error) {
|
|
showStatus(error.message, true);
|
|
}
|
|
}
|
|
|
|
async function activateNextScene(button) {
|
|
button.disabled = true;
|
|
try {
|
|
const response = await apiFetch(`${apiPrefix}/groups/${button.dataset.id}/next-scene`, { method: 'POST' });
|
|
const body = await response.json();
|
|
if (!response.ok) throw new Error(body.error || 'Could not control the bridge');
|
|
showStatus(`${button.querySelector('span').textContent}: ${body.scene}`);
|
|
button.querySelector('small').textContent = body.scene;
|
|
window.setTimeout(refresh, 350);
|
|
} catch (error) {
|
|
showStatus(error.message, true);
|
|
} finally {
|
|
button.disabled = false;
|
|
}
|
|
}
|
|
|
|
async function turnOff(button) {
|
|
button.disabled = true;
|
|
try {
|
|
const response = await apiFetch(`${apiPrefix}/groups/${button.dataset.id}/off`, { method: 'POST' });
|
|
const body = await response.json();
|
|
if (!response.ok) throw new Error(body.error || 'Could not turn off the lights');
|
|
button.classList.remove('is-on');
|
|
button.querySelector('small').textContent = 'Lights off';
|
|
showStatus(`${button.querySelector('span').textContent}: off`);
|
|
window.setTimeout(refresh, 350);
|
|
} catch (error) {
|
|
showStatus(error.message, true);
|
|
} finally {
|
|
button.disabled = false;
|
|
}
|
|
}
|
|
|
|
buttons.forEach(button => {
|
|
let pressTimer;
|
|
let longPressHandled = false;
|
|
|
|
const clearPressTimer = () => window.clearTimeout(pressTimer);
|
|
button.addEventListener('pointerdown', () => {
|
|
longPressHandled = false;
|
|
pressTimer = window.setTimeout(() => {
|
|
longPressHandled = true;
|
|
turnOff(button);
|
|
}, 650);
|
|
});
|
|
button.addEventListener('pointerup', clearPressTimer);
|
|
button.addEventListener('pointercancel', clearPressTimer);
|
|
button.addEventListener('pointerleave', clearPressTimer);
|
|
button.addEventListener('click', event => {
|
|
if (longPressHandled) {
|
|
event.preventDefault();
|
|
longPressHandled = false;
|
|
return;
|
|
}
|
|
activateNextScene(button);
|
|
});
|
|
});
|
|
|
|
refresh();
|
|
window.setInterval(refresh, 15000);
|