feat: Add initial WSPR live data querying scripts

This commit is contained in:
2026-04-01 12:22:45 -06:00
committed by Tanner Collin (aider)
parent c8b04b6a82
commit 517cf400b3
3 changed files with 635 additions and 0 deletions

257
js/Base.js Normal file
View File

@@ -0,0 +1,257 @@
/*
Copyright (c) 2023-forever Douglas Malnati. All rights reserved.
See the /faq/tos page for details.
(If this generated header is stamped on a file which is a 3rd party file or under a different license or copyright, then ignore this copyright statement and use that file's terms.)
*/
import * as utl from '/js/Utl.js';
import { Timeline } from '/js/Timeline.js';
// fold this functionality back into the original Event.js later
class Event
{
static handlerList = [];
AddHandler(handler)
{
Event.handlerList.push(handler);
}
Emit(evt)
{
if (typeof(evt) == "string")
{
evt = {
type: evt
};
}
for (const evtHandler of Event.handlerList)
{
if (evtHandler.OnEvent)
{
evtHandler.OnEvent(evt);
}
}
}
}
export class Base
extends Event
{
static globalDebugAnyway = false;
constructor(t)
{
super();
this.AddHandler(this);
// timeline
this.t = t ?? new Timeline();
//
// logging levels
//
// debug
this.debug = false;
// info
this.info = true;
}
// only to be called once, from main application, when everything is
// constructed and ready to go
Run()
{
urlStateProxy.OnPageLoad();
}
SetDebug(tf)
{
this.debug = tf;
}
SetGlobalDebug(tf)
{
Base.globalDebugAnyway = tf;
}
Debug(str)
{
if (this.debug || Base.globalDebugAnyway)
{
console.log(str);
}
}
DebugTable(val)
{
if (this.debug || Base.globalDebugAnyway)
{
console.table(val);
}
}
SetInfo(tf)
{
this.info = tf;
}
Info(str)
{
if (this.info)
{
console.log(str);
}
}
Err(from, str)
{
console.log(`ERR: ${from} - ${str}`);
}
}
// A class that does the work of helping components interact with the URL
// and the variables captured within the URL.
//
// Also manages browser history and gives the typical user experience of
// how history works, without page reloads.
class UrlStateProxy
extends Base
{
constructor()
{
super();
this.urlPrior = "";
window.addEventListener("popstate", (event) => {
this.DoUrlSet();
});
}
OnPageLoad()
{
this.DoUrlSet();
this.DoUrlGet();
}
DoUrlSet()
{
// capture current url and its search params, and parse
const url = new URL(window.location);
const params = new URLSearchParams(url.search);
// console.log(`window.location: ${window.location}`)
// console.log(`urlIn.origin: ${url.origin}`)
// console.log(`urlIn.pathname: ${url.pathname}`)
// console.log(`urlIn.search: ${url.search}`)
// console.log(`paramsIn : ${params.toString()}`);
// synchronously send to interested listeners
this.Emit({
type: "ON_URL_SET",
Get: (param, defaultValue) => {
return utl.GetSearchParam(param, defaultValue);
},
});
}
DoUrlGet()
{
// synchronously send to interested listeners
let paramsOut = new URLSearchParams(``);
let evt = {
type: "ON_URL_GET",
Set: (param, value) => {
paramsOut.set(param, value);
},
allowBlank: false,
};
this.Emit(evt);
const urlIn = new URL(window.location);
let paramsIn = new URLSearchParams(urlIn.search);
// filter out blank parameters unless requested not to
if (evt.allowBlank == false)
{
for (let [key, value] of Array.from(paramsOut.entries()))
{
if (value === "")
{
paramsOut.delete(key);
}
}
}
const urlOut = new URL(`${urlIn.origin}${urlIn.pathname}?${paramsOut.toString()}`);
// console.log("")
// console.log("")
// console.log(`old : ${urlIn.href}`);
// console.log(`params : ${paramsOut.toString()}`);
// console.log(`new : ${urlOut.href}`);
let paramsInSorted = new URLSearchParams(paramsIn.toString());
paramsInSorted.sort();
let pIn = paramsInSorted.toString();
let paramsOutSorted = new URLSearchParams(paramsOut.toString());
paramsOutSorted.sort();
let pOut = paramsOutSorted.toString();
let didNewHistoryEntry = false;
if (pIn != pOut)
{
// console.log("params are different, updating url and history")
// console.log(pIn)
// console.log(pOut)
history.pushState({}, "", urlOut.href);
didNewHistoryEntry = true;
}
return didNewHistoryEntry;
}
OnEvent(evt)
{
switch (evt.type) {
case "REQ_URL_GET": this.OnReqUrlGet(); break;
}
}
OnReqUrlGet()
{
// the purpose of this is to blow away the forward history when (say)
// a user clicks search, which triggers a URL re-evaluation.
let didNewHistoryEntry = this.DoUrlGet();
if (didNewHistoryEntry == false)
{
// force new history, request came in to re-evaluate, clearly
// a change has occurred.
history.pushState({}, "", window.location);
}
}
}
// global single instance
let urlStateProxy = new UrlStateProxy();