Skip to content

Commit 28d7ad4

Browse files
committed
fix: timeline working with calendars
1 parent d31a73a commit 28d7ad4

1 file changed

Lines changed: 91 additions & 74 deletions

File tree

scripts/renderers/vis-timeline-renderer.js

Lines changed: 91 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -79,27 +79,6 @@ const msToSec = (ms) => (ms != null && Number.isFinite(Number(ms))) ? Number(ms)
7979
// Calendar formatting helpers
8080
// ---------------------------------------------------------------------------
8181

82-
/**
83-
* Resolve the localised month name (or abbreviation) from CONFIG.
84-
* Returns null if the calendar config is not available.
85-
*
86-
* @param {number} monthIndex – 0-based month index from timeToComponents
87-
* @param {"full"|"abbr"} form
88-
*/
89-
function calendarMonthName(monthIndex, form = "full") {
90-
try {
91-
const months = CONFIG.time?.worldCalendarConfig?.months?.values ?? [];
92-
const m = months[monthIndex];
93-
if (!m) return null;
94-
const raw = form === "abbr"
95-
? (m.abbreviation ?? m.name ?? null)
96-
: (m.name ?? m.abbreviation ?? null);
97-
if (raw == null) return null;
98-
return typeof raw === "string" ? game.i18n.localize(raw) : String(raw);
99-
} catch (e) {
100-
return null;
101-
}
102-
}
10382

10483
/**
10584
* Format a seconds timestamp for a given vis.js axis scale.
@@ -122,31 +101,23 @@ function calendarMonthName(monthIndex, form = "full") {
122101
function fgFormatForScale(seconds, scale, role) {
123102
console.log(seconds, scale, role)
124103
try {
125-
const cal = game?.time?.calendar;
126-
if (!cal?.timeToComponents) {
127-
// No calendar API: fall back to the raw calendar.format() or the number
128-
return cal?.format ? cal.format(seconds) : String(seconds);
129-
}
130-
131-
//const c = cal.timeToComponents(seconds);
132-
const c = game.time.calendar.constructor.dateFormattingParts(game.time.calendar, game.time.calendar.timeToComponents(seconds))
133-
// c: { year, month (0-based), dayOfMonth (0-based), hour, minute, second }
134-
135-
/*
136-
const year = c.year ?? 0;
137-
const month = c.month ?? 0; // 0-based
138-
const day = (c.dayOfMonth ?? 0) + 1; // make 1-based for display
139-
const hour = String(c.hour ?? 0).padStart(2, "0");
140-
const min = String(c.minute ?? 0).padStart(2, "0");
141-
*/
142-
const year = c.y ?? 0;
143-
const month = c.m ?? 0; // 0-based
144-
const day = (c.d ?? 0) + 1; // make 1-based for display
145-
const hour = c.H;
146-
const min = c.M;
147-
148-
const monthFull = c.B;
149-
const monthAbbr = c.B;
104+
const parts = getCalendarDateParts(seconds);
105+
if (!parts) return String(seconds);
106+
107+
const {
108+
year,
109+
monthIndex,
110+
monthOrdinal,
111+
monthName,
112+
monthAbbreviation,
113+
day,
114+
hour,
115+
minute,
116+
second,
117+
hourPadded,
118+
minutePadded,
119+
secondPadded
120+
} = parts;
150121

151122
switch (scale) {
152123
// ── Finest scales: we don't show sub-minute detail ──────────────────
@@ -157,27 +128,27 @@ function fgFormatForScale(seconds, scale, role) {
157128
// intentional fall-through
158129
case "minute":
159130
return role === "major"
160-
? `${day} ${monthFull} ${year}`
161-
: `${hour}:${min}`;
131+
? `${day} ${monthName} ${year}`
132+
: `${hour}:${minute}`;
162133

163134
// ── Hour ─────────────────────────────────────────────────────────────
164135
case "hour":
165136
return role === "major"
166-
? `${day} ${monthFull} ${year}`
137+
? `${day} ${monthName} ${year}`
167138
: `${hour}:00`;
168139

169140
// ── Day / weekday ─────────────────────────────────────────────────────
170141
case "weekday":
171142
case "day":
172143
return role === "major"
173-
? `${monthFull} ${year}`
174-
: `${day} ${monthAbbr}`;
144+
? `${monthName} ${year}`
145+
: `${day} ${monthAbbreviation}`;
175146

176147
// ── Month ─────────────────────────────────────────────────────────────
177148
case "month":
178149
return role === "major"
179150
? String(year)
180-
: `${monthFull} ${year}`;
151+
: `${monthName} ${year}`;
181152

182153
// ── Year ──────────────────────────────────────────────────────────────
183154
case "year":
@@ -253,29 +224,25 @@ function installMomentPatch() {
253224
* Always shows full date + time down to minutes: "DD MonthName Year HH:MM"
254225
*/
255226
function fgFormatFull(seconds) {
256-
console.log(seconds)
257227
try {
258-
const cal = game?.time?.calendar;
259-
if (!cal?.timeToComponents) {
260-
return cal?.format ? cal.format(seconds) : String(seconds);
261-
}
262-
// const c = cal.timeToComponents(seconds);
263-
const c = game.time.calendar.constructor.dateFormattingParts(game.time.calendar, game.time.calendar.timeToComponents(seconds))
264-
265-
/*
266-
const year = c.year ?? 0;
267-
const month = c.month ?? 0;
268-
const day = (c.dayOfMonth ?? 0) + 1;
269-
const hour = String(c.hour ?? 0).padStart(2, "0");
270-
const min = String(c.minute ?? 0).padStart(2, "0");
271-
*/
272-
const year = c.y ?? 0;
273-
const month = c.m ?? 0; // 0-based
274-
const day = (c.d ?? 0) + 1; // make 1-based for display
275-
const hour = c.H;
276-
const min = c.M;
277-
const monthName = c.B;
278-
return `${day} ${monthName} ${year} ${hour}:${min}`;
228+
const parts = getCalendarDateParts(seconds);
229+
if (!parts) return String(seconds);
230+
231+
const {
232+
year,
233+
monthIndex,
234+
monthOrdinal,
235+
monthName,
236+
monthAbbreviation,
237+
day,
238+
hour,
239+
minute,
240+
second,
241+
hourPadded,
242+
minutePadded,
243+
secondPadded
244+
} = parts;
245+
return `${day} ${monthName} ${year} ${hour}:${minute}`;
279246
} catch (e) {
280247
return String(seconds);
281248
}
@@ -293,6 +260,54 @@ function buildVisAxisFormat() {
293260
return { minorLabels: minor, majorLabels: major };
294261
}
295262

263+
function getCalendarDateParts(seconds) {
264+
const calendar = game?.time?.calendar;
265+
if (!calendar?.timeToComponents) return null;
266+
267+
const components = calendar.timeToComponents(seconds);
268+
const monthIndex = Number(components.month ?? 0);
269+
const month = calendar.months?.values?.[monthIndex] ?? null;
270+
271+
const localize = value => {
272+
if (value == null) return "";
273+
return typeof value === "string"
274+
? game.i18n.localize(value)
275+
: String(value);
276+
};
277+
278+
const rawYear = Number(components.year ?? 0);
279+
const yearZero = Number(calendar.years?.yearZero ?? 0);
280+
const year = rawYear + (Number.isFinite(yearZero) ? yearZero : 0);
281+
282+
const day = Number(components.dayOfMonth ?? 0) + 1;
283+
const hour = Number(components.hour ?? 0);
284+
const minute = Number(components.minute ?? 0);
285+
const second = Number(components.second ?? 0);
286+
287+
const monthName =
288+
localize(month?.name) ||
289+
String(month?.ordinal ?? monthIndex + 1);
290+
291+
const monthAbbreviation =
292+
localize(month?.abbreviation) ||
293+
monthName;
294+
295+
return {
296+
year,
297+
monthIndex,
298+
monthOrdinal: month?.ordinal ?? monthIndex + 1,
299+
monthName,
300+
monthAbbreviation,
301+
day,
302+
hour,
303+
minute,
304+
second,
305+
hourPadded: String(hour).padStart(2, "0"),
306+
minutePadded: String(minute).padStart(2, "0"),
307+
secondPadded: String(second).padStart(2, "0")
308+
};
309+
}
310+
296311
// ---------------------------------------------------------------------------
297312
// VisTimelineRenderer
298313
// ---------------------------------------------------------------------------
@@ -347,6 +362,8 @@ export class VisTimelineRenderer extends BaseRenderer {
347362
return false;
348363
}
349364

365+
366+
350367
get instructions() {
351368
return t("VisTimeline.Instructions");
352369
}

0 commit comments

Comments
 (0)