- Rename all .js files to .ts in assets/js/ - Add interfaces for hook state, data structures, and event payloads - Add type annotations to function parameters and return types - Create type declarations for vendor deps (Leaflet, Chart.js, Phoenix, topbar) - Update tsconfig.json for strict TypeScript checking - Update esbuild entry point to app.ts
74 lines
2.1 KiB
TypeScript
74 lines
2.1 KiB
TypeScript
interface CopyLinkHook extends ViewHook {
|
|
el: HTMLElement
|
|
}
|
|
|
|
export const CopyLink = {
|
|
mounted(this: CopyLinkHook): void {
|
|
this.el.addEventListener("click", () => {
|
|
navigator.clipboard.writeText(window.location.href).then(() => {
|
|
const orig = this.el.innerHTML
|
|
this.el.innerHTML = '<span class="text-success">Copied!</span>'
|
|
setTimeout(() => { this.el.innerHTML = orig }, 1500)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
interface LocateMeHook extends ViewHook {
|
|
el: HTMLElement
|
|
watchId: number | null
|
|
lastSentAt: number
|
|
startWatching(): void
|
|
}
|
|
|
|
export const LocateMe = {
|
|
mounted(this: LocateMeHook): void {
|
|
this.watchId = null
|
|
this.lastSentAt = 0
|
|
|
|
this.el.addEventListener("click", () => this.startWatching())
|
|
|
|
// Also respond to server-pushed request (for source=gps URLs)
|
|
this.handleEvent("request_gps", () => this.startWatching())
|
|
},
|
|
|
|
destroyed(this: LocateMeHook): void {
|
|
if (this.watchId !== null) {
|
|
navigator.geolocation.clearWatch(this.watchId)
|
|
}
|
|
},
|
|
|
|
startWatching(this: LocateMeHook): void {
|
|
if (!navigator.geolocation) {
|
|
alert("Geolocation is not supported by this browser")
|
|
return
|
|
}
|
|
|
|
// Already watching — don't start another
|
|
if (this.watchId !== null) return
|
|
|
|
this.el.classList.add("loading", "loading-spinner")
|
|
|
|
this.watchId = navigator.geolocation.watchPosition(
|
|
(pos: GeolocationPosition) => {
|
|
const now = Date.now()
|
|
// Send immediately on first fix, then at most once per minute
|
|
if (this.lastSentAt === 0 || now - this.lastSentAt >= 60000) {
|
|
this.lastSentAt = now
|
|
this.el.classList.remove("loading", "loading-spinner")
|
|
this.pushEvent("gps_location", {
|
|
lat: pos.coords.latitude,
|
|
lon: pos.coords.longitude
|
|
})
|
|
}
|
|
},
|
|
(err: GeolocationPositionError) => {
|
|
this.el.classList.remove("loading", "loading-spinner")
|
|
navigator.geolocation.clearWatch(this.watchId!)
|
|
this.watchId = null
|
|
alert("Could not get location: " + err.message)
|
|
},
|
|
{ enableHighAccuracy: true, timeout: 10000 }
|
|
)
|
|
}
|
|
}
|