discourse/plugins/discourse-local-dates/assets/javascripts/lib/discourse-markdown/discourse-local-dates.js.es6
Joffrey JAFFEUX d23c0c06c3
PERF: reduces rendering time of local-dates (#13931)
- prefers insertAdjacentHTML over innerHTML as it's much faster in this case (about 5x)
- memoizes tz.guess()
- memoizes list of timezones
- inlines template
- applies main element class in one pass

All in all for a very edge case of about 80 dates it should be faster of about 15/20ms.
2021-08-04 08:27:22 +02:00

166 lines
4.0 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";
const timezoneNames = moment.tz.names();
function addLocalDate(buffer, matches, state) {
let token;
let config = {
date: null,
time: null,
timezone: null,
format: null,
timezones: null,
displayedTimezone: null,
countdown: null,
};
const matchString = matches[1].replace(/||„|“|«|»|”/g, '"');
let parsed = parseBBCodeTag(
"[date date" + matchString + "]",
0,
matchString.length + 11
);
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;
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.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 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[data-*]",
"span[aria-label]",
]);
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);
});
}