mirror of
https://github.com/discourse/discourse.git
synced 2024-12-14 07:43:43 +08:00
7d8cda9858
Essentially, Saturday at 2:50 PM -> Saturday at 4:38 PM becomes Saturday at 2:50 PM -> 4:38 PM (Singapore) Also, the displayed dates are shortened when the standalone date is within two days. So despite the 'from' and 'to' date being the same day, it may show 'Saturday' for 'from', and the specific date for the 'to'. This corrects the behaviour. (so if the current date and time is Thursday 5PM, the 'from' date below is within 2 days, but the 'to' date is not) Saturday at 2:50 PM -> 8 October 2022 at 9:38 PM becomes Saturday at 2:50 PM -> 9:38 PM
228 lines
5.7 KiB
JavaScript
228 lines
5.7 KiB
JavaScript
import { parseBBCodeTag } from "pretty-text/engines/discourse-markdown/bbcode-block";
|
||
|
||
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);
|
||
});
|
||
}
|