Neale Pickett
·
2023-03-11
portal.mjs
1import * as Stat from "./stat.mjs"
2
3const Millisecond = 1
4const Second = 1000 * Millisecond
5const Minute = 60 * Second
6
7class StatApp {
8 constructor(parent) {
9 this.parent= parent
10 this.stat = new Stat.Stat()
11 this.chart = new Stat.PieChart(parent, this.stat)
12
13 setInterval(()=>this.update(), 2 * Second)
14 setTimeout(()=>this.update(), 500 * Millisecond)
15 this.update()
16 }
17
18 async update() {
19 // Use non-standard checkVisibility method to avoid a pointless update
20 if (this.parent.checkVisibility && !this.parent.checkVisibility()) {
21 return
22 }
23 await this.stat.update()
24 this.chart.update()
25 }
26}
27
28let frames = {}
29function activate(event, element) {
30 event.preventDefault()
31
32 let parent = element.parentElement
33 for (let e of parent.getElementsByClassName("active")) {
34 e.classList.remove("active")
35 }
36 element.classList.add("active")
37 let href = element.href
38 let app = document.querySelector("#app")
39
40 let frame = frames[href]
41 if (frame) {
42 frame.dispatchEvent(new Event("load"))
43 } else {
44 frame = app.appendChild(document.createElement("iframe"))
45 frame.addEventListener("load", e => frameLoaded(frame))
46 frame.src = href
47 frames[href] = frame
48 }
49
50 for (let fhref in frames) {
51 let f = frames[fhref]
52 if (fhref == href) {
53 f.classList.remove("hidden")
54 } else {
55 f.classList.add("hidden")
56 }
57 }
58}
59
60
61function frameLoaded(frame) {
62 let doc = frame.contentDocument
63 if (doc.title.length > 0) {
64 document.title = doc.title
65 }
66 let icon = document.querySelector("link[rel~='icon']")
67 let dicon = doc.querySelector("link[rel~='icon']")
68 if (dicon) {
69 icon.href = dicon.href
70 } else {
71 icon.href = defaultIcon
72 }
73}
74
75let defaultIcon = null
76async function init() {
77 let doc = document.querySelector("iframe").contentDocument
78
79 defaultIcon = document.querySelector("link[rel~='icon']").href
80
81 for (let l of document.head.querySelectorAll("style")) {
82 doc.head.appendChild(l.cloneNode(true))
83 }
84 for (let l of document.head.querySelectorAll("link[rel='stylesheet']")) {
85 doc.head.appendChild(l.cloneNode())
86 }
87 for (let f of document.querySelectorAll("#app iframe")) {
88 frames[f.src] = f
89 }
90
91
92 let icons = doc.body.appendChild(doc.createElement("section"))
93 icons.classList.add("icons")
94
95 let nav = document.querySelector("nav")
96 let resp = await fetch("portal.json")
97 let obj = await resp.json()
98 for (let app of obj) {
99 let hlink = null
100 if (app.target != "_blank") {
101 hlink = nav.appendChild(document.createElement("a"))
102 hlink.href = app.href
103 hlink.textContent = app.title
104 if (app.target) {
105 hlink.target = app.target
106 } else {
107 hlink.addEventListener("click", event => activate(event, hlink))
108 }
109 }
110
111 let dlink = icons.appendChild(doc.createElement("a"))
112 dlink.href = app.href
113 if (app.target) {
114 dlink.target = app.target
115 } else {
116 dlink.addEventListener("click", event => activate(event, hlink))
117 }
118 if (app.icon) {
119 let icon = dlink.appendChild(doc.createElement("img"))
120 icon.src = app.icon
121 icon.alt = app.title
122 icon.title = app.title
123 icon.style.objectFit = "cover"
124 } else if (app.app) {
125 if (app.app == "stat") {
126 new StatApp(dlink)
127 }
128 } else {
129 let text = dlink.appendChild(doc.createElement("div"))
130 text.textContent = app.title
131 }
132 }
133}
134
135if (document.readyState === "loading") {
136 document.addEventListener("DOMContentLoaded", init)
137} else {
138 init()
139}