mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
a1e77aa2ed
Previously, the site setting was only effective on the client side of things. Once the site setting was been reached, all oneboxes are not rendered. This commit changes it such that the site setting is respected both on the client and server side. The first N oneboxes are rendered and once the limit has been reached, subsequent oneboxes will not be rendered.
123 lines
3.3 KiB
JavaScript
123 lines
3.3 KiB
JavaScript
import { lookupCache } from "pretty-text/oneboxer";
|
|
|
|
import {
|
|
cachedInlineOnebox,
|
|
INLINE_ONEBOX_LOADING_CSS_CLASS,
|
|
INLINE_ONEBOX_CSS_CLASS
|
|
} from "pretty-text/inline-oneboxer";
|
|
|
|
const ONEBOX = 1;
|
|
const INLINE = 2;
|
|
|
|
function isTopLevel(href) {
|
|
let split = href.split(/https?:\/\/[^\/]+[\/?]/i);
|
|
let hasExtra = split && split[1] && split[1].length > 0;
|
|
return !hasExtra;
|
|
}
|
|
|
|
function applyOnebox(state, silent) {
|
|
if (silent || !state.tokens) {
|
|
return;
|
|
}
|
|
|
|
for (let i = 1; i < state.tokens.length; i++) {
|
|
let token = state.tokens[i];
|
|
let prev = state.tokens[i - 1];
|
|
let mode =
|
|
prev.type === "paragraph_open" && prev.level === 0 ? ONEBOX : INLINE;
|
|
|
|
if (token.type === "inline") {
|
|
let children = token.children;
|
|
for (let j = 0; j < children.length - 2; j++) {
|
|
let child = children[j];
|
|
|
|
if (
|
|
child.type === "link_open" &&
|
|
child.markup === "linkify" &&
|
|
child.info === "auto"
|
|
) {
|
|
if (j > children.length - 3) {
|
|
continue;
|
|
}
|
|
|
|
if (j === 0 && token.leading_space) {
|
|
mode = INLINE;
|
|
} else if (j > 0) {
|
|
let prevSibling = children[j - 1];
|
|
if (prevSibling.tag !== "br" || prevSibling.leading_space) {
|
|
mode = INLINE;
|
|
}
|
|
}
|
|
|
|
// look ahead for soft or hard break
|
|
let text = children[j + 1];
|
|
let close = children[j + 2];
|
|
let lookahead = children[j + 3];
|
|
|
|
if (lookahead && lookahead.tag !== "br") {
|
|
mode = INLINE;
|
|
}
|
|
|
|
// check attrs only include a href
|
|
let attrs = child.attrs;
|
|
|
|
if (!attrs || attrs.length !== 1 || attrs[0][0] !== "href") {
|
|
continue;
|
|
}
|
|
|
|
let href = attrs[0][1];
|
|
|
|
// edge case ... what if this is not http or protocoless?
|
|
if (!/^http|^\/\//i.test(href)) {
|
|
continue;
|
|
}
|
|
|
|
// we already know text matches cause it is an auto link
|
|
if (!close || close.type !== "link_close") {
|
|
continue;
|
|
}
|
|
|
|
if (mode === ONEBOX) {
|
|
// we already determined earlier that 0 0 was href
|
|
let cached = lookupCache(attrs[0][1]);
|
|
|
|
if (cached) {
|
|
// replace link with 2 blank text nodes and inline html for onebox
|
|
child.type = "html_raw";
|
|
child.content = cached;
|
|
child.inline = true;
|
|
|
|
text.type = "html_raw";
|
|
text.content = "";
|
|
text.inline = true;
|
|
|
|
close.type = "html_raw";
|
|
close.content = "";
|
|
close.inline = true;
|
|
} else {
|
|
// decorate...
|
|
attrs.push(["class", "onebox"]);
|
|
attrs.push(["target", "_blank"]);
|
|
}
|
|
} else if (mode === INLINE && !isTopLevel(href)) {
|
|
const onebox = cachedInlineOnebox(href);
|
|
|
|
if (onebox && onebox.title) {
|
|
text.content = onebox.title;
|
|
attrs.push(["class", INLINE_ONEBOX_CSS_CLASS]);
|
|
} else {
|
|
attrs.push(["class", INLINE_ONEBOX_LOADING_CSS_CLASS]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export function setup(helper) {
|
|
helper.registerPlugin(md => {
|
|
md.core.ruler.after("linkify", "onebox", applyOnebox);
|
|
});
|
|
}
|