// src/plugins/sat-scheduler.ts var satSchedulerWindow = window; (function() { "use strict"; const dom = { enabled: document.getElementById("scheduler-sat-enabled"), pretune: document.getElementById("scheduler-sat-pretune"), body: document.getElementById("scheduler-sat-body"), tbody: document.getElementById("scheduler-sat-tbody"), addBtn: document.getElementById("scheduler-sat-add-btn"), passStatus: document.getElementById("scheduler-sat-pass-status"), formWrap: document.getElementById("sch-sat-form-wrap"), formTitle: document.getElementById("sch-sat-form-title"), form: document.getElementById("sch-sat-form"), formCancel: document.getElementById("sch-sat-form-cancel"), preset: document.getElementById("scheduler-sat-preset"), name: document.getElementById("scheduler-sat-name"), norad: document.getElementById("scheduler-sat-norad"), bookmark: document.getElementById("scheduler-sat-bookmark"), minEl: document.getElementById("scheduler-sat-min-el"), priority: document.getElementById("scheduler-sat-priority"), centerHz: document.getElementById("scheduler-sat-center-hz") }; let editIdx = null; let eventsWired = false; function getBridge() { return satSchedulerWindow.trx?.modules?.scheduler ?? null; } function getConfig() { const b = getBridge(); return b?.getConfig() ?? null; } function getStatus() { const b = getBridge(); return b?.getStatus() ?? null; } function getBookmarks() { const b = getBridge(); return b?.getBookmarks() ?? []; } function markDirty() { getBridge()?.markDirty(); } function bmName(id) { const bm = getBookmarks().find(function(b) { return b.id === id; }); return bm ? bm.name : id; } function escHtml(s) { return s.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); } function formatFreq(hz) { if (hz >= 1e6) return (hz / 1e6).toFixed(3) + " MHz"; if (hz >= 1e3) return (hz / 1e3).toFixed(1) + " kHz"; return `${String(hz)} Hz`; } function getSatelliteEntries() { const config = getConfig(); return config && config.satellites && Array.isArray(config.satellites.entries) ? config.satellites.entries : []; } function ensureSatelliteConfig() { const config = getConfig(); if (!config) return { enabled: false, pretune_secs: 60, entries: [] }; if (!config.satellites) config.satellites = { enabled: false, pretune_secs: 60, entries: [] }; return config.satellites; } function collectSatelliteConfig() { const enabled = dom.enabled ? dom.enabled.checked : false; const pretune = dom.pretune ? parseInt(dom.pretune.value, 10) : 60; return { enabled, pretune_secs: isNaN(pretune) || pretune < 0 ? 60 : pretune, entries: getSatelliteEntries() }; } function renderSection() { const config = getConfig(); const satCfg = config?.satellites; const enabled = satCfg?.enabled ?? false; if (dom.enabled) dom.enabled.checked = enabled; if (dom.pretune) dom.pretune.value = String(satCfg?.pretune_secs ?? 60); if (dom.body) dom.body.style.display = enabled ? "" : "none"; renderEntries(); renderPassStatus(); } function renderEntries() { if (!dom.tbody) return; const entries = getSatelliteEntries(); const frag = document.createDocumentFragment(); entries.forEach(function(entry, idx) { const tr = document.createElement("tr"); const tdSat = document.createElement("td"); tdSat.textContent = entry.satellite || ""; tr.appendChild(tdSat); const tdNorad = document.createElement("td"); tdNorad.textContent = String(entry.norad_id || ""); tr.appendChild(tdNorad); const tdBm = document.createElement("td"); tdBm.textContent = bmName(entry.bookmark_id); tr.appendChild(tdBm); const tdEl = document.createElement("td"); tdEl.textContent = `${String(entry.min_elevation_deg)}°`; tr.appendChild(tdEl); const tdPrio = document.createElement("td"); tdPrio.textContent = String(entry.priority || 0); tr.appendChild(tdPrio); const tdActions = document.createElement("td"); const editBtn = document.createElement("button"); editBtn.className = "sch-write"; editBtn.type = "button"; editBtn.textContent = "Edit"; editBtn.addEventListener("click", function() { openForm(entry, idx); }); tdActions.appendChild(editBtn); const removeBtn = document.createElement("button"); removeBtn.className = "sch-write"; removeBtn.type = "button"; removeBtn.textContent = "Remove"; removeBtn.addEventListener("click", function() { removeEntry(idx); }); tdActions.appendChild(removeBtn); tr.appendChild(tdActions); frag.appendChild(tr); }); dom.tbody.replaceChildren(frag); } function renderPassStatus() { if (!dom.passStatus) return; const entries = getSatelliteEntries(); if (entries.length === 0) { dom.passStatus.innerHTML = ""; return; } const status = getStatus(); if (status && status.active_satellite) { dom.passStatus.innerHTML = 'PASS ACTIVE: ' + escHtml(status.active_satellite) + ""; } else { dom.passStatus.innerHTML = 'No satellite pass active. Predictions available in the SAT tab.'; } } function renderBookmarkSelect(selectedId) { const bookmarkSelect = dom.bookmark; if (!bookmarkSelect) return; bookmarkSelect.innerHTML = ''; getBookmarks().forEach(function(bm) { const opt = document.createElement("option"); opt.value = bm.id; opt.textContent = bm.name + " (" + formatFreq(bm.freq_hz) + " " + bm.mode + ")"; if (bm.id === selectedId) opt.selected = true; bookmarkSelect.appendChild(opt); }); } function removeEntry(idx) { const sat = ensureSatelliteConfig(); sat.entries.splice(idx, 1); renderEntries(); markDirty(); } function openForm(entry, idx) { editIdx = idx != null ? idx : null; if (dom.formTitle) dom.formTitle.textContent = entry ? "Edit Satellite" : "Add Satellite"; if (dom.preset) dom.preset.value = ""; if (dom.name) dom.name.value = entry ? entry.satellite || "" : ""; if (dom.norad) dom.norad.value = entry ? String(entry.norad_id || "") : ""; if (dom.minEl) dom.minEl.value = String(entry?.min_elevation_deg ?? 5); if (dom.priority) dom.priority.value = String(entry?.priority ?? 0); if (dom.centerHz) dom.centerHz.value = entry?.center_hz ? String(entry.center_hz) : ""; renderBookmarkSelect(entry ? entry.bookmark_id : null); if (dom.formWrap) { dom.formWrap.style.display = "flex"; if (dom.name) dom.name.focus(); } } function closeForm() { if (dom.formWrap) dom.formWrap.style.display = "none"; editIdx = null; } function onFormSubmit(e) { e.preventDefault(); const satellite = dom.name ? dom.name.value.trim() : ""; const noradId = dom.norad ? parseInt(dom.norad.value, 10) : NaN; const bmId = dom.bookmark ? dom.bookmark.value : ""; if (!satellite) { satSchedulerWindow.trxUi?.notify("Enter a satellite name.", { kind: "error" }); dom.name?.focus(); return; } if (isNaN(noradId) || noradId <= 0) { satSchedulerWindow.trxUi?.notify("Enter a valid NORAD catalog number.", { kind: "error" }); dom.norad?.focus(); return; } if (!bmId) { satSchedulerWindow.trxUi?.notify("Select a bookmark.", { kind: "error" }); dom.bookmark?.focus(); return; } const minEl = dom.minEl ? parseFloat(dom.minEl.value) : 5; const prio = dom.priority ? parseInt(dom.priority.value, 10) : 0; const centerHzRaw = dom.centerHz ? parseInt(dom.centerHz.value, 10) : NaN; const sat = ensureSatelliteConfig(); const existing = editIdx !== null ? sat.entries[editIdx] : void 0; const entryData = { id: existing?.id ?? `sat_${Date.now().toString(36)}`, satellite, norad_id: noradId, bookmark_id: bmId, min_elevation_deg: isNaN(minEl) ? 5 : minEl, priority: isNaN(prio) ? 0 : prio, center_hz: !isNaN(centerHzRaw) && centerHzRaw > 0 ? centerHzRaw : null, bookmark_ids: [] }; if (editIdx !== null) { sat.entries[editIdx] = entryData; } else { sat.entries.push(entryData); } closeForm(); renderEntries(); markDirty(); } function onPresetChange() { if (!dom.preset || !dom.preset.value) return; const parts = dom.preset.value.split("|"); if (dom.name) dom.name.value = parts[0] || ""; if (dom.norad) dom.norad.value = parts[1] || ""; } function wireEvents() { if (eventsWired) return; eventsWired = true; if (dom.enabled) { const enabledInput = dom.enabled; dom.enabled.addEventListener("change", function() { if (dom.body) dom.body.style.display = enabledInput.checked ? "" : "none"; markDirty(); }); } if (dom.pretune) { dom.pretune.addEventListener("input", function() { markDirty(); }); } if (dom.addBtn) dom.addBtn.addEventListener("click", function() { openForm(null, null); }); if (dom.form) dom.form.addEventListener("submit", onFormSubmit); if (dom.formCancel) dom.formCancel.addEventListener("click", closeForm); if (dom.preset) dom.preset.addEventListener("change", onPresetChange); } satSchedulerWindow.satScheduler = { wireEvents, renderSection, renderPassStatus, collectSatelliteConfig }; if (getBridge()) { wireEvents(); renderSection(); } })();