discourse/plugins/discourse-local-dates/assets/javascripts/lib/discourse-markdown/discourse-local-dates.js
Krzysztof Kotlarek 7f3f07dd40
FIX: missing IST KST and JST timezones in cooked posts (#26252)
In this PR we introduced 3 new timezones to UX - IST, KST and JST

cb2569303f

However, the same has to be done in PrettyText so cooked posts respect those timezones.
2024-03-20 11:28:45 +11:00

229 lines
5.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { parseBBCodeTag } from "pretty-text/engines/discourse-markdown/bbcode-block";
moment.tz.link(["Asia/Kolkata|IST", "Asia/Seoul|KST", "Asia/Tokyo|JST"]);
const timezoneNames = moment.tz.names();
function addSingleLocalDate(buffer, state, config) {
let token = new state.Token("span_open", "span", 1);
token.attrs = [["data-date", state.md.utils.escapeHtml(config.date)]];
if (!config.date.match(/\d{4}-\d{2}-\d{2}/)) {
closeBuffer(buffer, state, moment.invalid().format());
return;
}
if (config.time && !config.time.match(/\d{2}:\d{2}(?::\d{2})?/)) {
closeBuffer(buffer, state, moment.invalid().format());
return;
}
let dateTime = config.date;
if (config.time) {
token.attrs.push(["data-time", state.md.utils.escapeHtml(config.time)]);
dateTime = `${dateTime} ${config.time}`;
}
if (!moment(dateTime).isValid()) {
closeBuffer(buffer, state, moment.invalid().format());
return;
}
token.attrs.push(["class", "discourse-local-date"]);
if (config.format) {
token.attrs.push(["data-format", state.md.utils.escapeHtml(config.format)]);
}
if (config.countdown) {
token.attrs.push([
"data-countdown",
state.md.utils.escapeHtml(config.countdown),
]);
}
if (config.calendar) {
token.attrs.push([
"data-calendar",
state.md.utils.escapeHtml(config.calendar),
]);
}
if (config.range) {
token.attrs.push(["data-range", config.range]);
}
if (
config.displayedTimezone &&
timezoneNames.includes(config.displayedTimezone)
) {
token.attrs.push([
"data-displayed-timezone",
state.md.utils.escapeHtml(config.displayedTimezone),
]);
}
if (config.timezones) {
const timezones = config.timezones.split("|").filter((timezone) => {
return timezoneNames.includes(timezone);
});
token.attrs.push([
"data-timezones",
state.md.utils.escapeHtml(timezones.join("|")),
]);
}
if (config.timezone && timezoneNames.includes(config.timezone)) {
token.attrs.push([
"data-timezone",
state.md.utils.escapeHtml(config.timezone),
]);
dateTime = moment.tz(dateTime, config.timezone);
} else {
dateTime = moment.utc(dateTime);
}
if (config.recurring) {
token.attrs.push([
"data-recurring",
state.md.utils.escapeHtml(config.recurring),
]);
}
buffer.push(token);
const formattedDateTime = dateTime
.tz("Etc/UTC")
.format(
state.md.options.discourse.datesEmailFormat || moment.defaultFormat
);
token.attrs.push(["data-email-preview", `${formattedDateTime} UTC`]);
closeBuffer(buffer, state, dateTime.utc().format(config.format));
}
function defaultDateConfig() {
return {
date: null,
time: null,
timezone: null,
format: null,
timezones: null,
displayedTimezone: null,
countdown: null,
range: false,
};
}
function parseTagAttributes(tag) {
const matchString = tag.replace(/||„|“|«|»|”/g, '"');
return parseBBCodeTag(
"[date date" + matchString + "]",
0,
matchString.length + 12
);
}
function addLocalDate(buffer, matches, state) {
let config = defaultDateConfig();
const parsed = parseTagAttributes(matches[1]);
config.date = parsed.attrs.date;
config.format = parsed.attrs.format;
config.calendar = parsed.attrs.calendar;
config.time = parsed.attrs.time;
config.timezone = (parsed.attrs.timezone || "").trim();
config.recurring = parsed.attrs.recurring;
config.timezones = parsed.attrs.timezones;
config.displayedTimezone = parsed.attrs.displayedTimezone;
config.countdown = parsed.attrs.countdown;
addSingleLocalDate(buffer, state, config);
}
function addLocalRange(buffer, matches, state) {
let config = defaultDateConfig();
let date, time;
const parsed = parseTagAttributes(matches[1]);
config.format = parsed.attrs.format;
config.calendar = parsed.attrs.calendar;
config.timezone = (parsed.attrs.timezone || "").trim();
config.recurring = parsed.attrs.recurring;
config.timezones = parsed.attrs.timezones;
config.displayedTimezone = parsed.attrs.displayedTimezone;
config.countdown = parsed.attrs.countdown;
if (parsed.attrs.from) {
[date, time] = parsed.attrs.from.split("T");
config.date = date;
config.time = time;
config.range = "from";
addSingleLocalDate(buffer, state, config);
}
if (config.range) {
closeBuffer(buffer, state, "→");
}
if (parsed.attrs.to) {
[date, time] = parsed.attrs.to.split("T");
config.date = date;
config.time = time;
config.range = "to";
addSingleLocalDate(buffer, state, config);
}
}
function closeBuffer(buffer, state, text) {
let token;
token = new state.Token("text", "", 0);
token.content = text;
buffer.push(token);
token = new state.Token("span_close", "span", -1);
buffer.push(token);
}
export function setup(helper) {
helper.allowList([
"span.discourse-local-date",
"span[aria-label]",
"span[data-date]",
"span[data-time]",
"span[data-format]",
"span[data-countdown]",
"span[data-calendar]",
"span[data-displayed-timezone]",
"span[data-timezone]",
"span[data-timezones]",
"span[data-recurring]",
"span[data-email-preview]",
]);
helper.registerOptions((opts, siteSettings) => {
opts.datesEmailFormat = siteSettings.discourse_local_dates_email_format;
opts.features["discourse-local-dates"] =
!!siteSettings.discourse_local_dates_enabled;
});
helper.registerPlugin((md) => {
const rule = {
matcher: /\[date(=.+?)\]/,
onMatch: addLocalDate,
};
md.core.textPostProcess.ruler.push("discourse-local-dates", rule);
});
helper.registerPlugin((md) => {
const rule = {
matcher: /\[date-range(.+?)\]/,
onMatch: addLocalRange,
};
md.core.textPostProcess.ruler.push("discourse-local-dates", rule);
});
}