Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/src/packages/frontend/markdown/mentions-plugin.ts
Views: 1053
/*1* LICENSE: MIT (same as upstream hashtags plugin)2*/34/*56What this plugin mainly does is take a stream of inline tokens like this:78...9{type: "text", ...}10{type: "html_inline", content: "<span class="user-mention" account-id=47d0393e-4814-4452-bb6c-35bac4cbd314 >", ...}11{type: "text", content: "@Bella Welski", ...}12{type: "html_inline", content: "</span>", ...}13{type: "text", ...}14...1516and turn it into1718...19{type: "text", ...}20{type: "mention", account_id: "47d0393e-4814-4452-bb6c-35bac4cbd314 >", name:"Bella Welski", ...}21{type: "text", ...}22...232425It also defines a renderer.2627The motivation is that in CoCalc we store our mentions in markdown as2829<span class="user-mention" account-id=47d0393e-4814-4452-bb6c-35bac4cbd314 >@Bella Welski</span>3031With an appropriate class user-mention, this does render fine with no32processing at all. However, by parsing this, we can also use mentions33in our Slate editor, and it's much easier to dynamically update the34user's name (with given account_id) if they change it. Morever, we could35easily use user colors, avatars, etc. to render mention users36with this parser, but it's much harder without.3738*/3940import { startswith } from "@cocalc/util/misc";4142function renderMention(tokens, idx): string {43// TODO: we could dynamically update the username using the account-id44// in case it changed from what is stored in the doc.45// This user-mention is a CSS class we defined somewhere...46const token = tokens[idx];47return `<span class="user-mention">@${token.name}</span>`;48}4950function isMentionOpen(str: string): boolean {51return startswith(str, '<span class="user-mention" ');52}53function isMentionClose(str: string): boolean {54return str == "</span>";55}5657export function mentionPlugin(md): void {58function mention(state) {59const { Token, tokens: blockTokens } = state;6061for (let j = 0; j < blockTokens.length; j++) {62if (blockTokens[j].type !== "inline") {63continue;64}6566let tokens = blockTokens[j].children;6768for (let i = tokens.length - 1; i >= 2; i--) {69if (70!(71isMentionClose(tokens[i].content) &&72isMentionOpen(tokens[i - 2].content)73)74) {75continue;76}77// tokens[i-2] like: <span class="user-mention" account-id=47d0393e-4814-4452-bb6c-35bac4cbd314 >78// tokens[i-1] like: @Bella Welski79// and tokens[i] like: </span>80const { level } = tokens[i];81const token = new Token("mention", "", 0);82token.level = level;83const i0 = tokens[i - 2].content.lastIndexOf("=");84token.account_id = tokens[i - 2].content.slice(i0 + 1, i0 + 37);85token.name = tokens[i - 1].content.slice(1).trim();8687tokens = tokens88.slice(0, i - 2)89.concat([token])90.concat(tokens.slice(i + 1));9192// replace current node93blockTokens[j].children = tokens;9495i -= 2;96}97}98}99100md.core.ruler.after("inline", "mention", mention);101md.renderer.rules.mention = renderMention;102}103104105