discourse/app/assets/javascripts/pretty-text/engines/discourse-markdown/quotes.js

202 lines
5.7 KiB
JavaScript

import { performEmojiUnescape } from "pretty-text/emoji";
const rule = {
tag: "quote",
before(state, tagInfo) {
const attrs = tagInfo.attrs;
let options = state.md.options.discourse;
let quoteInfo = attrs["_default"];
let username,
postNumber,
topicId,
avatarImg,
primaryGroupName,
full,
displayName;
if (quoteInfo) {
let split = quoteInfo.split(/\,\s*/);
username = split[0];
let i;
for (i = 1; i < split.length; i++) {
if (split[i].indexOf("post:") === 0) {
postNumber = parseInt(split[i].slice(5), 10);
continue;
}
if (split[i].indexOf("topic:") === 0) {
topicId = parseInt(split[i].slice(6), 10);
continue;
}
if (/full:\s*true/.test(split[i])) {
full = true;
continue;
}
// if we have the additional attribute of username: because we are prioritizing full name
// then assign the name to be the displayName
if (split[i].indexOf("username:") === 0) {
// return users name by selecting all values from the first index to the post
// this protects us from when a user has a `,` in their name
displayName = split.slice(0, split.indexOf(`post:${postNumber}`));
// preserve `,` in a users name if they exist
if (displayName.length > 1) {
displayName = displayName.join(", ");
}
// strip key of 'username:' and return username
username = split[i].slice(9);
continue;
}
}
}
if (options.lookupAvatarByPostNumber) {
// client-side, we can retrieve the avatar from the post
avatarImg = options.lookupAvatarByPostNumber(postNumber, topicId);
} else if (options.lookupAvatar) {
// server-side, we need to lookup the avatar from the username
avatarImg = options.lookupAvatar(username);
}
if (options.lookupPrimaryUserGroupByPostNumber) {
// client-side, we can retrieve the primary user group from the post
primaryGroupName = options.lookupPrimaryUserGroupByPostNumber(
postNumber,
topicId
);
} else if (options.lookupPrimaryUserGroup) {
// server-side, we need to lookup the primary user group from the username
primaryGroupName = options.lookupPrimaryUserGroup(username);
}
if (options.formatUsername) {
displayName = displayName || options.formatUsername(username);
} else {
displayName = displayName || username;
}
let token = state.push("bbcode_open", "aside", 1);
token.attrs = [];
if (primaryGroupName && primaryGroupName.length !== 0) {
token.attrs.push(["class", `quote group-${primaryGroupName}`]);
} else {
token.attrs.push(["class", "quote no-group"]);
}
if (username) {
token.attrs.push(["data-username", username]);
}
if (postNumber) {
token.attrs.push(["data-post", postNumber]);
}
if (topicId) {
token.attrs.push(["data-topic", topicId]);
}
if (full) {
token.attrs.push(["data-full", "true"]);
}
if (username) {
let forOtherTopic = options.topicId && topicId !== options.topicId;
let offTopicQuote =
postNumber &&
options.getTopicInfo &&
(forOtherTopic || options.forceQuoteLink);
// on topic quote
token = state.push("quote_header_open", "div", 1);
token.attrs = [["class", "title"]];
token = state.push("quote_controls_open", "div", 1);
token.attrs = [["class", "quote-controls"]];
state.push("quote_controls_close", "div", -1);
if (avatarImg) {
token = state.push("html_inline", "", 0);
token.content = avatarImg;
}
if (offTopicQuote) {
const topicInfo = options.getTopicInfo(topicId);
if (topicInfo) {
let href = topicInfo.href;
if (postNumber > 0) {
href += "/" + postNumber;
}
let title = topicInfo.title;
if (options.enableEmoji) {
title = performEmojiUnescape(topicInfo.title, {
getURL: options.getURL,
emojiSet: options.emojiSet,
emojiCDNUrl: options.emojiCDNUrl,
enableEmojiShortcuts: options.enableEmojiShortcuts,
inlineEmoji: options.inlineEmoji,
lazy: true,
});
}
token = state.push("link_open", "a", 1);
token.attrs = [["href", href]];
token.block = false;
token = state.push("html_inline", "", 0);
token.content = title;
token = state.push("link_close", "a", -1);
token.block = false;
}
} else {
token = state.push("text", "", 0);
token.content = ` ${displayName}:`;
}
state.push("quote_header_close", "div", -1);
}
state.push("bbcode_open", "blockquote", 1);
},
after(state) {
state.push("bbcode_close", "blockquote", -1);
state.push("bbcode_close", "aside", -1);
},
};
export function setup(helper) {
helper.registerOptions((opts, siteSettings) => {
opts.enableEmoji = siteSettings.enable_emoji;
opts.emojiSet = siteSettings.emoji_set;
opts.emojiCDNUrl = siteSettings.external_emoji_url;
opts.enableEmojiShortcuts = siteSettings.enable_emoji_shortcuts;
opts.inlineEmoji = siteSettings.enable_inline_emoji_translation;
});
helper.registerPlugin((md) => {
md.block.bbcode.ruler.push("quotes", rule);
});
helper.allowList(["img[class=avatar]", "img[loading=lazy]"]);
helper.allowList({
custom(tag, name, value) {
if (tag === "aside" && name === "class") {
return (
value === "quote no-group" || !!/^quote group\-(.+)$/.exec(value)
);
}
},
});
}