/** * DHCP Lease Manager — client-side logic. * Uses Zoraxy's $.cjax() for CSRF-safe AJAX (jQuery is available from parent frame). */ // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function showToast(message, type) { var toast = document.getElementById('toast'); toast.textContent = message; toast.className = 'toast ' + (type || ''); void toast.offsetWidth; toast.classList.remove('hidden'); setTimeout(function () { toast.classList.add('hidden'); }, 3000); } // --------------------------------------------------------------------------- // Render // --------------------------------------------------------------------------- function renderLeases(data) { var tbody = document.getElementById('leases-body'); var leases = data.leases || []; document.getElementById('active-count').textContent = data.active_count; document.getElementById('pinned-count').textContent = data.pinned_count; if (leases.length === 0) { tbody.innerHTML = 'No active leases'; return; } var rows = leases.map(function (lease) { var isPermanent = lease.status === 'permanent'; return ( '' + '' + esc(lease.hostname || '--') + '' + '' + esc(lease.ip) + '' + '' + esc(lease.mac) + '' + '' + '' + esc(lease.status) + '' + '' + '' + (isPermanent ? '' : '' ) + '' + '' ); }).join(''); tbody.innerHTML = rows; } function esc(s) { if (!s) return ''; return s.replace(/&/g, '&').replace(//g, '>'); } function escAttr(s) { if (!s) return ''; return s.replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, '''); } // --------------------------------------------------------------------------- // Actions (using $.cjax = Zoraxy's CSRF-safe AJAX wrapper) // --------------------------------------------------------------------------- function loadLeases() { $.get('./api/leases', function (data) { renderLeases(data); }).fail(function () { showToast('Failed to load leases', 'error'); }); } function pinLease(mac, ip, hostname) { $.cjax({ url: './api/pin', type: 'POST', dataType: 'json', data: { mac: mac, ip: ip, hostname: hostname || '' }, success: function () { showToast('Pinned ' + (hostname || mac), 'success'); loadLeases(); }, error: function (xhr) { var msg = 'Pin failed'; try { var r = JSON.parse(xhr.responseText); msg = r.message || r.error || msg; } catch(e) {} showToast(msg, 'error'); } }); } function unpinLease(mac, ip, hostname) { $.cjax({ url: './api/unpin', type: 'POST', dataType: 'json', data: { mac: mac, ip: ip, hostname: hostname || '' }, success: function () { showToast('Unpinned ' + (hostname || mac), 'success'); loadLeases(); }, error: function (xhr) { var msg = 'Unpin failed'; try { var r = JSON.parse(xhr.responseText); msg = r.message || r.error || msg; } catch(e) {} showToast(msg, 'error'); } }); } function reloadDnsmasq() { var btn = document.getElementById('reload-btn'); btn.disabled = true; btn.textContent = 'Reloading...'; $.cjax({ url: './api/reload', type: 'POST', dataType: 'json', data: {}, success: function (data) { if (data.success) { showToast('dnsmasq reloaded', 'success'); } else { showToast(data.message || 'Reload failed', 'error'); } loadLeases(); }, error: function (xhr) { var msg = 'Reload failed'; try { var r = JSON.parse(xhr.responseText); msg = r.message || r.error || msg; } catch(e) {} showToast(msg, 'error'); }, complete: function () { btn.disabled = false; btn.textContent = 'Reload dnsmasq'; } }); } // --------------------------------------------------------------------------- // Event delegation // --------------------------------------------------------------------------- document.getElementById('leases-body').addEventListener('click', function (e) { var btn = e.target.closest('button[data-action]'); if (!btn) return; var action = btn.dataset.action; var mac = btn.dataset.mac; var ip = btn.dataset.ip; var hostname = btn.dataset.hostname; if (action === 'pin') { pinLease(mac, ip, hostname); } else if (action === 'unpin') { unpinLease(mac, ip, hostname); } }); document.getElementById('reload-btn').addEventListener('click', reloadDnsmasq); // --------------------------------------------------------------------------- // Init // --------------------------------------------------------------------------- loadLeases();