refactor to ES modules
This commit is contained in:
+1
-1
@@ -22,6 +22,6 @@
|
|||||||
|
|
||||||
<div class="days" id="championships_table"></div>
|
<div class="days" id="championships_table"></div>
|
||||||
|
|
||||||
<script src="script.js"></script>
|
<script type="module" src="js/sso-timer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import Data from './data.js'
|
||||||
|
import Day from './day.js'
|
||||||
|
import Transform from './transform.js'
|
||||||
|
|
||||||
|
export default class Championship {
|
||||||
|
static last = null
|
||||||
|
|
||||||
|
static get next() {
|
||||||
|
let remainingOffset = 0
|
||||||
|
let day = Day.today
|
||||||
|
let time = Championship.nextTime
|
||||||
|
|
||||||
|
if (time == null) {
|
||||||
|
remainingOffset += 1440
|
||||||
|
day = Day.tomorrow
|
||||||
|
time = Championship.firstTimeNextDay
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
day: day,
|
||||||
|
time: time,
|
||||||
|
location: Data.championships[day][time],
|
||||||
|
remaining: (remainingOffset + time) - Day.minutesPassedSinceMidnight,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static firstTimeOnDay(day) {
|
||||||
|
return Math.min(...Object.keys(Data.championships[day]))
|
||||||
|
}
|
||||||
|
|
||||||
|
static get nextTime() {
|
||||||
|
let nextTimes = Transform.dropChampionshipsBefore(Data.championshipsToday, Day.minutesPassedSinceMidnight)
|
||||||
|
|
||||||
|
if (nextTimes.length < 1) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.min(...nextTimes)
|
||||||
|
}
|
||||||
|
|
||||||
|
static get firstTimeTomorrow() {
|
||||||
|
return Championship.firstTimeOnDay(Day.tomorrow)
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
import Transform from './transform.js'
|
||||||
|
import Day from './day.js'
|
||||||
|
|
||||||
|
export default class Data {
|
||||||
|
static championships = {}
|
||||||
|
static championshipsURL = 'data/championships.json'
|
||||||
|
static locations = []
|
||||||
|
|
||||||
|
static get championshipsToday() {
|
||||||
|
return Data.championships[Day.today]
|
||||||
|
}
|
||||||
|
|
||||||
|
static get isLoaded() {
|
||||||
|
return Object.keys(Data.championships).length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
static init(json) {
|
||||||
|
Data.championships = json
|
||||||
|
Data.locations = Transform.championshipsToLocations(json)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
export default class Day {
|
||||||
|
static date = new Date() // maybe easier to offset time zone later
|
||||||
|
|
||||||
|
static update() {
|
||||||
|
Day.date = new Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
static get today() {
|
||||||
|
return Day.date.getDay()
|
||||||
|
}
|
||||||
|
|
||||||
|
static get tomorrow() {
|
||||||
|
let day = Day.today + 1
|
||||||
|
if (day > 6) day -= 6
|
||||||
|
|
||||||
|
return day
|
||||||
|
}
|
||||||
|
|
||||||
|
static get secondsUntilFullMinute() {
|
||||||
|
return (60 - Day.date.getSeconds()).toString().padStart(2, '0')
|
||||||
|
}
|
||||||
|
|
||||||
|
static get minutesPassedSinceMidnight() {
|
||||||
|
return Day.date.getHours() * 60 + Day.date.getMinutes()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import UI from './ui.js'
|
||||||
|
|
||||||
|
window.addEventListener('load', UI.init)
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
export default class Transform {
|
||||||
|
static championshipsToLocations(championships) {
|
||||||
|
return Transform.unique(Transform.flatten(championships))
|
||||||
|
}
|
||||||
|
|
||||||
|
static flatten(object) {
|
||||||
|
return Object.values(object).reduce((arr, t) => arr.concat(Object.values(t)), [])
|
||||||
|
}
|
||||||
|
|
||||||
|
static unique(array) {
|
||||||
|
return [...new Set(array)]
|
||||||
|
}
|
||||||
|
|
||||||
|
static dropChampionshipsBefore(championshipsToday, time) {
|
||||||
|
return Object.keys(championshipsToday).filter((t) => parseInt(t) >= time)
|
||||||
|
}
|
||||||
|
|
||||||
|
static time(time) {
|
||||||
|
return Math.floor(time/60).toString().padStart(2, '0') + ":" + (time % 60).toString().padStart(2, '0')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import Transform from './transform.js'
|
||||||
|
import Championship from './championship.js'
|
||||||
|
import Data from './data.js'
|
||||||
|
import Day from './day.js'
|
||||||
|
|
||||||
|
export default class UI {
|
||||||
|
static instance = null
|
||||||
|
static updateFrequency = 500 // in ms
|
||||||
|
|
||||||
|
constructor(rootObject) {
|
||||||
|
this.rootObject = rootObject
|
||||||
|
this.loadChampionships()
|
||||||
|
this.start() // auto-start, might need some more thought
|
||||||
|
}
|
||||||
|
|
||||||
|
static init() {
|
||||||
|
UI.instance = new UI(window.document)
|
||||||
|
}
|
||||||
|
|
||||||
|
loadResponseIntoData(response) {
|
||||||
|
response.json().then(Data.init)
|
||||||
|
}
|
||||||
|
|
||||||
|
loadChampionships() {
|
||||||
|
fetch(Data.championshipsURL).then(this.loadResponseIntoData)
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.intervalId = setInterval(() => { UI.instance.update() }, UI.updateFrequency)
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
clearInterval(this.intervalId)
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
if (!Data.isLoaded) { return }
|
||||||
|
|
||||||
|
Day.update()
|
||||||
|
|
||||||
|
let next = Championship.next
|
||||||
|
|
||||||
|
if (Championship.last != next) {
|
||||||
|
Championship.last = next
|
||||||
|
this.updateChampionshipDetails(next)
|
||||||
|
this.updateChampionshipTable(next)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateTimer(next)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateChampionshipDetails(next) {
|
||||||
|
this.rootObject.getElementById('time').innerHTML = Transform.time(next.time)
|
||||||
|
this.rootObject.getElementById('location').innerHTML = next.location
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTimer(next) {
|
||||||
|
let remaining = Transform.time(next.remaining) + ":" + Day.secondsUntilFullMinute
|
||||||
|
this.rootObject.getElementById('timer').innerHTML = remaining
|
||||||
|
this.rootObject.title = `${remaining} - ${next.location} - SSO Timer`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: refactor to builder
|
||||||
|
updateChampionshipTable(next) {
|
||||||
|
const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
|
||||||
|
let table = ``
|
||||||
|
for (const [day, details] of Object.entries(Data.championships)) {
|
||||||
|
let dayContainer = `<h1 class="day-title">${weekdays[day]}</h1>`
|
||||||
|
let dayContainerClasses = 'day-container'
|
||||||
|
|
||||||
|
if (Day.today == day) {
|
||||||
|
dayContainerClasses += ' today'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [time, location] of Object.entries(details)) {
|
||||||
|
let formattedTime = Transform.time(time)
|
||||||
|
let classes = 'time-container'
|
||||||
|
if (next.day == day && next.time == time) {
|
||||||
|
classes += ' next-time'
|
||||||
|
}
|
||||||
|
|
||||||
|
dayContainer += `<li class="${classes}"><b class="time">${formattedTime}</b>: ${location}</li>`
|
||||||
|
}
|
||||||
|
|
||||||
|
table += `<div class="${dayContainerClasses}"><ul class="times">${dayContainer}</ul></div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('championships_table').innerHTML = table
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
var championships = {}
|
|
||||||
var lastChampionship = null
|
|
||||||
var locations = []
|
|
||||||
var updateFrequency = 500; // in ms
|
|
||||||
|
|
||||||
function flattenObjectIntoSingleUniqueArray(object) {
|
|
||||||
return [...new Set(Object.values(object).reduce((arr, t) => arr.concat(Object.values(t)), []))]
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDateObject() {
|
|
||||||
return new Date() // maybe easier to offset time zone later
|
|
||||||
}
|
|
||||||
|
|
||||||
function currentDay() {
|
|
||||||
return getDateObject().getDay()
|
|
||||||
}
|
|
||||||
|
|
||||||
function currentTime() {
|
|
||||||
let date = getDateObject()
|
|
||||||
return date.getHours() * 60 + date.getMinutes()
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextDay() {
|
|
||||||
let day = currentDay() + 1
|
|
||||||
if (day > 6) day -= 6
|
|
||||||
|
|
||||||
return day
|
|
||||||
}
|
|
||||||
|
|
||||||
function firstTimeOnDay(day) {
|
|
||||||
return Math.min(...Object.keys(championships[day]))
|
|
||||||
}
|
|
||||||
|
|
||||||
function firstTimeNextDay() {
|
|
||||||
return firstTimeOnDay(nextDay())
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextTime() {
|
|
||||||
let time = currentTime()
|
|
||||||
|
|
||||||
let nextTimes = Object.keys(championships[currentDay()]).filter((t) => parseInt(t) >= time)
|
|
||||||
|
|
||||||
if (nextTimes.length < 1) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.min(...nextTimes)
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatTime(time) {
|
|
||||||
return Math.floor(time/60).toString().padStart(2, '0') + ":" + (time % 60).toString().padStart(2, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatSeconds() {
|
|
||||||
return (60 - getDateObject().getSeconds()).toString().padStart(2, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextChampionship() {
|
|
||||||
let remainingOffset = 0
|
|
||||||
let day = currentDay()
|
|
||||||
let time = nextTime()
|
|
||||||
|
|
||||||
if (time == null) {
|
|
||||||
remainingOffset = 1440
|
|
||||||
day = nextDay()
|
|
||||||
time = firstTimeNextDay()
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
day: day,
|
|
||||||
time: time,
|
|
||||||
location: championships[day][time],
|
|
||||||
remaining: (remainingOffset + time) - currentTime(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateChampionshipDetails(next) {
|
|
||||||
document.getElementById('time').innerHTML = formatTime(next.time)
|
|
||||||
document.getElementById('location').innerHTML = next.location
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateTimer(next) {
|
|
||||||
let remaining = formatTime(next.remaining) + ":" + formatSeconds()
|
|
||||||
document.getElementById('timer').innerHTML = remaining
|
|
||||||
document.title = `${remaining} - ${next.location} - SSO Timer`
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateChampionshipTable(next) {
|
|
||||||
const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
|
|
||||||
let table = ``
|
|
||||||
for (const [day, details] of Object.entries(championships)) {
|
|
||||||
let dayContainer = `<h1 class="day-title">${weekdays[day]}</h1>`
|
|
||||||
let dayContainerClasses = 'day-container'
|
|
||||||
|
|
||||||
if (currentDay() == day) {
|
|
||||||
dayContainerClasses += ' today'
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [time, location] of Object.entries(details)) {
|
|
||||||
let formattedTime = formatTime(time)
|
|
||||||
let classes = 'time-container'
|
|
||||||
if (next.day == day && next.time == time) {
|
|
||||||
classes += ' next-time'
|
|
||||||
}
|
|
||||||
|
|
||||||
dayContainer += `<li class="${classes}"><b class="time">${formattedTime}</b>: ${location}</li>`
|
|
||||||
}
|
|
||||||
|
|
||||||
table += `<div class="${dayContainerClasses}"><ul class="times">${dayContainer}</ul></div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('championships_table').innerHTML = table
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('load', () => {
|
|
||||||
fetch('data/championships.json').then((response) => {
|
|
||||||
response.json().then((json) => {
|
|
||||||
championships = json
|
|
||||||
locations = flattenObjectIntoSingleUniqueArray(championships)
|
|
||||||
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
setInterval(() => {
|
|
||||||
if (championships.length < 1) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let next = nextChampionship()
|
|
||||||
|
|
||||||
if (lastChampionship != nextChampionship()) {
|
|
||||||
updateChampionshipDetails(next)
|
|
||||||
updateChampionshipTable(next)
|
|
||||||
}
|
|
||||||
|
|
||||||
updateTimer(next)
|
|
||||||
}, updateFrequency)
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user