diff --git a/assets/scripts/KaplayMap/lang.js b/assets/scripts/KaplayMap/lang.js index 1694a18..644f6a9 100644 --- a/assets/scripts/KaplayMap/lang.js +++ b/assets/scripts/KaplayMap/lang.js @@ -2,6 +2,15 @@ import localization from "./localization.js"; export class LangManager { #lang; + #units = { + year: 24 * 60 * 60 * 1000 * 365, + month: (24 * 60 * 60 * 1000 * 365) / 12, + week: 7 * 24 * 60 * 60 * 1000, + day: 24 * 60 * 60 * 1000, + hour: 60 * 60 * 1000, + minute: 60 * 1000, + second: 1000, + }; constructor(lang) { this.#lang = lang; @@ -14,4 +23,23 @@ export class LangManager { get langCode() { return this.#lang; } + + getTimeDuration(d1, d2) { + let elapsed = d2 - d1; + + for (var u in this.#units) + if (Math.abs(elapsed) > this.#units[u] || u == "second") { + let currentUnit = this.currentLocalization.time_units[u]; + return currentUnit(Math.round(elapsed / this.#units[u])); + } + } + + formatList(items) { + const formatter = new Intl.ListFormat("en", { + style: "long", + type: "conjunction", + }); + + return formatter.format(items); + } } diff --git a/assets/scripts/KaplayMap/localization.js b/assets/scripts/KaplayMap/localization.js index 764ea0a..fdff0ea 100644 --- a/assets/scripts/KaplayMap/localization.js +++ b/assets/scripts/KaplayMap/localization.js @@ -2,6 +2,15 @@ export default new Map([ [ "en-US", { + time_units: { + year: (t) => (t == 1 ? `${t} year` : `${t} years`), + month: (t) => (t == 1 ? `${t} month` : `${t} months`), + week: (t) => (t == 1 ? `${t} week` : `${t} weeks`), + day: (t) => (t == 1 ? `${t} day` : `${t} days`), + hour: (t) => (t == 1 ? `${t} hour` : `${t} hours`), + minute: (t) => (t == 1 ? `${t} minute` : `${t} minutes`), + second: (t) => (t == 1 ? `${t} second` : `${t} seconds`), + }, floors_header: "Floors", date_starting: "Starting", date_started: "Started", @@ -22,6 +31,7 @@ export default new Map([ minimize: "Toggle event panel docking", event_inspector_header: (name) => `Event ${name}`, event_inspector_host: "Host: ", + event_inspector_hosts: "Hosts: ", event_inspector_back: "Return to events panel", event_inspector_minimize: "Toggle event inspector docking", zoom_in_button: "Zoom in", @@ -53,8 +63,8 @@ Thanks to: label: "Description", title: "Search by text found in the description.", }, - host: { - label: "Host", + hosts: { + label: "Hosts", title: "Search by who is hosting the event.", }, url: { @@ -73,7 +83,7 @@ Thanks to: search_filters: { name: ({ src }) => `Found by title`, // Already present description: ({ src }) => `Found by description`, // Too long to be present - host: ({ src }) => `Found by host ${src}`, + hosts: ({ src }) => `Found by host ${src}`, url: ({ src }) => `Found by URL ${src}`, floor: ({ src }) => `Found by floor ${src}`, room: ({ src }) => `Found by room ${src}`, diff --git a/assets/scripts/KaplayMap/ui.js b/assets/scripts/KaplayMap/ui.js index 903efcc..8b343ca 100644 --- a/assets/scripts/KaplayMap/ui.js +++ b/assets/scripts/KaplayMap/ui.js @@ -1,6 +1,5 @@ import { DatetoLocaleDynamicString, - getMinutesDifference, getRelativeTime, } from "../modules/relative_time.js"; @@ -292,8 +291,8 @@ export class UIManager { } #Search__selectedTags = []; - #Search__filters = ["name", "description", "host", "floor", "room"]; - #Search__selectedFilters = ["name", "description", "host", "floor", "room"]; + #Search__filters = ["name", "description", "hosts", "floor", "room"]; + #Search__selectedFilters = ["name", "description", "hosts", "floor", "room"]; #Search__allEvents = null; __updateSearchUI() { @@ -439,16 +438,18 @@ export class UIManager { src: event.description, }); return true; - } else if ( - this.#Search__selectedFilters.includes("host") && - event.host && - searchTransform(event.host).includes(searchValue) - ) { - whatFilter.push({ - type: "host", - src: event.host, - }); - return true; + } else if (this.#Search__selectedFilters.includes("hosts") && event.hosts) { + const host = event.hosts.find((host) => + searchTransform(host).includes(searchValue) + ); + + if (host != null) { + whatFilter.push({ + type: "hosts", + src: host, + }); + return true; + } } else { // Filter by room/floor @@ -556,6 +557,7 @@ export class UIManager { const eventListContainerSummaryName = document.createElement("a"); eventListContainerSummaryName.href = "#" + event.id; eventListContainerSummaryName.textContent = event.name; + eventListContainerSummaryName.title = event.name; eventListContainerSummary.appendChild(eventListContainerSummaryName); @@ -616,8 +618,11 @@ export class UIManager { const eventListContainerSummaryLength = document.createElement("span"); eventListContainerSummaryLength.textContent = currentLocalization.parenthesis( - currentLocalization.minutes_long( - getMinutesDifference(eventDateStart, eventDateEnd) + this.mainmanager.callManagerFunction( + "lang", + "getTimeDuration", + eventDateStart, + eventDateEnd ) ); eventListContainerSummaryLength.title = eventDateEnd.toLocaleString( @@ -699,8 +704,11 @@ export class UIManager { ); this.uiElements.eventsInspectorEventLength.textContent = currentLocalization.separator( - currentLocalization.minutes_long( - getMinutesDifference(eventDateStart, eventDateEnd) + this.mainmanager.callManagerFunction( + "lang", + "getTimeDuration", + eventDateStart, + eventDateEnd ), "" ); @@ -714,14 +722,20 @@ export class UIManager { this.uiElements.eventsInspectorBody.replaceChildren(); - if (currentEvent.host != null) { + if (currentEvent.hosts != null) { const eventHost = document.createElement("p"); eventHost.classList.add("widget-description"); - eventHost.textContent = currentLocalization.event_inspector_host; + if (currentEvent.hosts.length == 1) + eventHost.textContent = currentLocalization.event_inspector_host; + else eventHost.textContent = currentLocalization.event_inspector_hosts; const eventHostName = document.createElement("b"); - eventHostName.textContent = currentEvent.host; + eventHostName.textContent = this.mainmanager.callManagerFunction( + "lang", + "formatList", + currentEvent.hosts + ); eventHost.appendChild(eventHostName); @@ -736,6 +750,7 @@ export class UIManager { eventDescription.classList.add("widget-description"); eventDescription.textContent = currentEvent.description; + eventDescription.title = currentEvent.description; this.uiElements.eventsInspectorBody.appendChild(eventDescription); } @@ -780,6 +795,7 @@ export class UIManager { } this.uiElements.eventsRoomDescription.textContent = focusedRoom.description; + this.uiElements.eventsRoomDescription.title = focusedRoom.description; this.uiElements.eventsBackButton.disabled = false; this.uiElements.eventsBackButton.title = currentLocalization.view_events_in(focusedFloor.name); @@ -792,6 +808,7 @@ export class UIManager { } this.uiElements.eventsRoomDescription.textContent = focusedFloor.description; + this.uiElements.eventsRoomDescription.title = focusedFloor.description; this.uiElements.eventsBackButton.disabled = true; this.uiElements.eventsBackButton.title = ""; } @@ -831,6 +848,7 @@ export class UIManager { const eventListContainerSummaryName = document.createElement("a"); eventListContainerSummaryName.href = "#" + id; eventListContainerSummaryName.textContent = event.name; + eventListContainerSummaryName.title = event.name; eventListContainerSummary.appendChild(eventListContainerSummaryName); @@ -875,8 +893,11 @@ export class UIManager { const eventListContainerSummaryLength = document.createElement("span"); eventListContainerSummaryLength.textContent = currentLocalization.parenthesis( - currentLocalization.minutes_long( - getMinutesDifference(eventDateStart, eventDateEnd) + this.mainmanager.callManagerFunction( + "lang", + "getTimeDuration", + eventDateStart, + eventDateEnd ) ); eventListContainerSummaryLength.title = eventDateEnd.toLocaleString( diff --git a/assets/scripts/modules/relative_time.js b/assets/scripts/modules/relative_time.js index d61a668..6386923 100644 --- a/assets/scripts/modules/relative_time.js +++ b/assets/scripts/modules/relative_time.js @@ -2,6 +2,7 @@ export const units = { year: 24 * 60 * 60 * 1000 * 365, month: (24 * 60 * 60 * 1000 * 365) / 12, + week: 7 * 24 * 60 * 60 * 1000, day: 24 * 60 * 60 * 1000, hour: 60 * 60 * 1000, minute: 60 * 1000, @@ -15,16 +16,27 @@ export function getRelativeTime(d1, d2, locale) { let elapsed = d1 - d2; + if (Math.abs(elapsed) >= units.year) { + return d1.toLocaleDateString(locale, { + weekday: "long", + month: "long", + day: "numeric", + year: "numeric", + }); + } else if (Math.abs(elapsed) >= units.day) { + return d1.toLocaleDateString(locale, { + weekday: "long", + month: "long", + day: "numeric", + }); + } + // "Math.abs" accounts for both "past" & "future" scenarios for (var u in units) if (Math.abs(elapsed) > units[u] || u == "second") return rtf.format(Math.round(elapsed / units[u]), u); } -export function getMinutesDifference(d1, d2) { - return (d2.getTime() - d1.getTime()) / units.minute; -} - export function sameDay(d1, d2) { return Math.abs(d2.getTime() - d1.getTime()) < units.day; } @@ -38,4 +50,4 @@ export function DatetoLocaleDynamicString(d1, ref, lang) { return d1.toLocaleDateString(lang, { dateStyle: "short", }); -} \ No newline at end of file +} diff --git a/scripts/server.js b/scripts/server.js index b06c39c..cde739a 100644 --- a/scripts/server.js +++ b/scripts/server.js @@ -34,8 +34,8 @@ app.get('/data/:lang/events/:floor', async (req, res) => { event.name = curLang.name ?? ""; event.description = curLang.description ?? ""; - if (curLang.host != null) - event.host = curLang.host; + if (curLang.hosts != null) + event.hosts = curLang.hosts; delete event.lang; return event; @@ -73,8 +73,8 @@ app.get('/data/:lang/events/', async (req, res) => { event.name = curLang.name ?? ""; event.description = curLang.description ?? ""; - if (curLang.host != null) - event.host = curLang.host; + if (curLang.hosts != null) + event.hosts = curLang.hosts; delete event.lang; return event;