mirror of
https://github.com/discourse/discourse.git
synced 2025-01-25 02:06:14 +08:00
65481858c2
For consistency this PR introduces using custom markdown and short upload:// URLs for video and audio uploads, rather than just treating them as links and relying on the oneboxer. The markdown syntax for videos is ![file text|video](upload://123456.mp4) and for audio it is ![file text|audio](upload://123456.mp3). This is achieved in discourse-markdown-it by modifying the rules for images in mardown-it via md.renderer.rules.image. We return HTML instead of the token when we encounter audio or video after | and the preview renders that HTML. Also when uploading an audio or video file we insert the relevant markdown into the composer.
92 lines
2.4 KiB
JavaScript
92 lines
2.4 KiB
JavaScript
// add image to array if src has an upload
|
|
function addImage(uploads, token) {
|
|
if (token.attrs) {
|
|
for (let i = 0; i < token.attrs.length; i++) {
|
|
if (token.attrs[i][1].indexOf("upload://") === 0) {
|
|
uploads.push([token, i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function rule(state) {
|
|
let uploads = [];
|
|
|
|
for (let i = 0; i < state.tokens.length; i++) {
|
|
let blockToken = state.tokens[i];
|
|
|
|
if (blockToken.tag === "img" || blockToken.tag === "a") {
|
|
addImage(uploads, blockToken);
|
|
}
|
|
|
|
if (!blockToken.children) continue;
|
|
|
|
for (let j = 0; j < blockToken.children.length; j++) {
|
|
let token = blockToken.children[j];
|
|
|
|
if (token.tag === "img" || token.tag === "a") addImage(uploads, token);
|
|
}
|
|
}
|
|
|
|
if (uploads.length > 0) {
|
|
let srcList = uploads.map(([token, srcIndex]) => token.attrs[srcIndex][1]);
|
|
let lookup = state.md.options.discourse.lookupUploadUrls;
|
|
let longUrls = (lookup && lookup(srcList)) || {};
|
|
|
|
uploads.forEach(([token, srcIndex]) => {
|
|
let origSrc = token.attrs[srcIndex][1];
|
|
let mapped = longUrls[origSrc];
|
|
|
|
switch (token.tag) {
|
|
case "img":
|
|
if (mapped) {
|
|
token.attrs[srcIndex][1] = mapped.url;
|
|
token.attrs.push(["data-base62-sha1", mapped.base62_sha1]);
|
|
} else {
|
|
// no point putting a transparent .png for audio/video
|
|
if (token.content.match(/\|video|\|audio/)) {
|
|
token.attrs[srcIndex][1] = state.md.options.discourse.getURL(
|
|
"/404"
|
|
);
|
|
} else {
|
|
token.attrs[srcIndex][1] = state.md.options.discourse.getURL(
|
|
"/images/transparent.png"
|
|
);
|
|
}
|
|
|
|
token.attrs.push(["data-orig-src", origSrc]);
|
|
}
|
|
break;
|
|
case "a":
|
|
if (mapped) {
|
|
token.attrs[srcIndex][1] = mapped.short_path;
|
|
} else {
|
|
token.attrs[srcIndex][1] = state.md.options.discourse.getURL(
|
|
"/404"
|
|
);
|
|
|
|
token.attrs.push(["data-orig-href", origSrc]);
|
|
}
|
|
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
export function setup(helper) {
|
|
const opts = helper.getOptions();
|
|
if (opts.previewing) helper.whiteList(["img.resizable"]);
|
|
|
|
helper.whiteList([
|
|
"img[data-orig-src]",
|
|
"img[data-base62-sha1]",
|
|
"a[data-orig-href]"
|
|
]);
|
|
|
|
helper.registerPlugin(md => {
|
|
md.core.ruler.push("upload-protocol", rule);
|
|
});
|
|
}
|