2020-07-10 22:57:06 +08:00
|
|
|
import I18n from "I18n";
|
2020-12-18 21:18:52 +08:00
|
|
|
import discourseDebounce from "discourse-common/lib/debounce";
|
2020-07-10 22:57:06 +08:00
|
|
|
|
2019-05-29 09:00:25 +08:00
|
|
|
let _cache = {};
|
|
|
|
|
|
|
|
export function lookupCachedUploadUrl(shortUrl) {
|
|
|
|
return _cache[shortUrl] || {};
|
|
|
|
}
|
|
|
|
|
|
|
|
const MISSING = "missing";
|
|
|
|
|
|
|
|
export function lookupUncachedUploadUrls(urls, ajax) {
|
2020-09-02 04:47:22 +08:00
|
|
|
urls = urls.filter(Boolean);
|
2020-03-03 12:44:01 +08:00
|
|
|
if (urls.length === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-29 09:00:25 +08:00
|
|
|
return ajax("/uploads/lookup-urls", {
|
2020-03-27 04:00:10 +08:00
|
|
|
type: "POST",
|
2019-05-29 09:00:25 +08:00
|
|
|
data: { short_urls: urls },
|
|
|
|
}).then((uploads) => {
|
|
|
|
uploads.forEach((upload) => {
|
|
|
|
cacheShortUploadUrl(upload.short_url, {
|
|
|
|
url: upload.url,
|
|
|
|
short_path: upload.short_path,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
urls.forEach((url) =>
|
|
|
|
cacheShortUploadUrl(url, {
|
|
|
|
url: lookupCachedUploadUrl(url).url || MISSING,
|
|
|
|
short_path: lookupCachedUploadUrl(url).short_path || MISSING,
|
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
return uploads;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function cacheShortUploadUrl(shortUrl, value) {
|
|
|
|
_cache[shortUrl] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function resetCache() {
|
|
|
|
_cache = {};
|
|
|
|
}
|
|
|
|
|
2020-07-10 22:57:06 +08:00
|
|
|
function retrieveCachedUrl(
|
|
|
|
upload,
|
|
|
|
siteSettings,
|
|
|
|
dataAttribute,
|
|
|
|
opts,
|
|
|
|
callback
|
|
|
|
) {
|
2020-06-06 00:15:14 +08:00
|
|
|
const cachedUpload = lookupCachedUploadUrl(
|
|
|
|
upload.getAttribute(`data-${dataAttribute}`)
|
|
|
|
);
|
2020-03-04 07:11:08 +08:00
|
|
|
const url = getAttributeBasedUrl(dataAttribute, cachedUpload, siteSettings);
|
2020-01-23 07:41:39 +08:00
|
|
|
|
|
|
|
if (url) {
|
2020-06-06 00:15:14 +08:00
|
|
|
upload.removeAttribute(`data-${dataAttribute}`);
|
2020-01-23 07:41:39 +08:00
|
|
|
if (url !== MISSING) {
|
|
|
|
callback(url);
|
2020-07-10 22:57:06 +08:00
|
|
|
} else if (opts && opts.removeMissing) {
|
|
|
|
const style = getComputedStyle(document.body);
|
|
|
|
const canvas = document.createElement("canvas");
|
|
|
|
canvas.width = upload.width;
|
|
|
|
canvas.height = upload.height;
|
|
|
|
|
|
|
|
const context = canvas.getContext("2d");
|
|
|
|
|
|
|
|
// Draw background
|
|
|
|
context.fillStyle = getComputedStyle(document.body).backgroundColor;
|
|
|
|
context.strokeRect(0, 0, canvas.width, canvas.height);
|
|
|
|
|
|
|
|
// Draw border
|
|
|
|
context.lineWidth = 2;
|
|
|
|
context.strokeStyle = getComputedStyle(document.body).color;
|
|
|
|
context.strokeRect(0, 0, canvas.width, canvas.height);
|
|
|
|
|
|
|
|
let fontSize = 25;
|
|
|
|
const text = I18n.t("image_removed");
|
|
|
|
|
|
|
|
// Fill text size to fit the canvas
|
|
|
|
let textSize;
|
|
|
|
do {
|
|
|
|
--fontSize;
|
|
|
|
context.font = `${fontSize}px ${style.fontFamily}`;
|
|
|
|
textSize = context.measureText(text);
|
|
|
|
} while (textSize.width > canvas.width);
|
|
|
|
|
|
|
|
context.fillStyle = getComputedStyle(document.body).color;
|
|
|
|
context.fillText(
|
|
|
|
text,
|
|
|
|
(canvas.width - textSize.width) / 2,
|
|
|
|
(canvas.height + fontSize) / 2
|
|
|
|
);
|
|
|
|
|
|
|
|
upload.parentNode.replaceChild(canvas, upload);
|
2020-01-23 07:41:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-04 07:11:08 +08:00
|
|
|
function getAttributeBasedUrl(dataAttribute, cachedUpload, siteSettings) {
|
|
|
|
if (!cachedUpload.url) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// non-attachments always use the full URL
|
|
|
|
if (dataAttribute !== "orig-href") {
|
|
|
|
return cachedUpload.url;
|
|
|
|
}
|
|
|
|
|
|
|
|
// attachments should use the full /secure-media-uploads/ URL
|
|
|
|
// in this case for permission checks
|
|
|
|
if (
|
|
|
|
siteSettings.secure_media &&
|
|
|
|
cachedUpload.url.indexOf("secure-media-uploads") > -1
|
|
|
|
) {
|
|
|
|
return cachedUpload.url;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cachedUpload.short_path;
|
|
|
|
}
|
|
|
|
|
2020-07-10 22:57:06 +08:00
|
|
|
function _loadCachedShortUrls(uploadElements, siteSettings, opts) {
|
2020-06-06 00:15:14 +08:00
|
|
|
uploadElements.forEach((upload) => {
|
2019-05-29 09:00:25 +08:00
|
|
|
switch (upload.tagName) {
|
|
|
|
case "A":
|
2020-07-10 22:57:06 +08:00
|
|
|
retrieveCachedUrl(upload, siteSettings, "orig-href", opts, (url) => {
|
2020-06-06 00:15:14 +08:00
|
|
|
upload.href = url;
|
2020-01-23 07:41:39 +08:00
|
|
|
});
|
2019-05-29 09:00:25 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
case "IMG":
|
2020-07-10 22:57:06 +08:00
|
|
|
retrieveCachedUrl(upload, siteSettings, "orig-src", opts, (url) => {
|
2020-06-06 00:15:14 +08:00
|
|
|
upload.src = url;
|
2020-01-23 07:41:39 +08:00
|
|
|
});
|
2019-05-29 09:00:25 +08:00
|
|
|
|
2020-01-23 07:41:39 +08:00
|
|
|
break;
|
2020-03-03 12:44:01 +08:00
|
|
|
case "SOURCE": // video/audio tag > source tag
|
2020-07-10 22:57:06 +08:00
|
|
|
retrieveCachedUrl(upload, siteSettings, "orig-src", opts, (url) => {
|
2020-01-23 07:41:39 +08:00
|
|
|
if (url.startsWith(`//${window.location.host}`)) {
|
|
|
|
let hostRegex = new RegExp("//" + window.location.host, "g");
|
|
|
|
url = url.replace(hostRegex, "");
|
2019-05-29 09:00:25 +08:00
|
|
|
}
|
2020-07-22 07:23:55 +08:00
|
|
|
|
|
|
|
upload.src = url;
|
2020-01-23 07:41:39 +08:00
|
|
|
|
2020-03-03 12:44:01 +08:00
|
|
|
// set the url and text for the <a> tag within the <video/audio> tag
|
2020-06-06 00:15:14 +08:00
|
|
|
const link = upload.parentElement.querySelector("a");
|
|
|
|
if (link) {
|
2020-07-22 07:23:55 +08:00
|
|
|
link.href = url;
|
|
|
|
link.textContent = url;
|
2020-06-06 00:15:14 +08:00
|
|
|
}
|
2020-01-23 07:41:39 +08:00
|
|
|
});
|
2019-05-29 09:00:25 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-07-10 22:57:06 +08:00
|
|
|
function _loadShortUrls(uploads, ajax, siteSettings, opts) {
|
2020-06-06 00:15:14 +08:00
|
|
|
let urls = [...uploads].map((upload) => {
|
|
|
|
return (
|
|
|
|
upload.getAttribute("data-orig-src") ||
|
|
|
|
upload.getAttribute("data-orig-href")
|
|
|
|
);
|
2019-05-29 09:00:25 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
return lookupUncachedUploadUrls(urls, ajax).then(() =>
|
2020-07-10 22:57:06 +08:00
|
|
|
_loadCachedShortUrls(uploads, siteSettings, opts)
|
2019-05-29 09:00:25 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-02-18 22:07:26 +08:00
|
|
|
const SHORT_URL_ATTRIBUTES =
|
|
|
|
"img[data-orig-src], a[data-orig-href], source[data-orig-src]";
|
|
|
|
|
|
|
|
export function resolveCachedShortUrls(siteSettings, scope, opts) {
|
|
|
|
let shortUploadElements = scope.querySelectorAll(SHORT_URL_ATTRIBUTES);
|
|
|
|
|
|
|
|
if (shortUploadElements.length > 0) {
|
|
|
|
_loadCachedShortUrls(shortUploadElements, siteSettings, opts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 22:57:06 +08:00
|
|
|
export function resolveAllShortUrls(ajax, siteSettings, scope, opts) {
|
2021-02-18 22:07:26 +08:00
|
|
|
let shortUploadElements = scope.querySelectorAll(SHORT_URL_ATTRIBUTES);
|
2019-05-29 09:00:25 +08:00
|
|
|
|
2020-06-06 00:15:14 +08:00
|
|
|
if (shortUploadElements.length > 0) {
|
2020-07-10 22:57:06 +08:00
|
|
|
_loadCachedShortUrls(shortUploadElements, siteSettings, opts);
|
2019-05-29 09:00:25 +08:00
|
|
|
|
2021-02-18 22:07:26 +08:00
|
|
|
shortUploadElements = scope.querySelectorAll(SHORT_URL_ATTRIBUTES);
|
2020-06-06 00:15:14 +08:00
|
|
|
if (shortUploadElements.length > 0) {
|
2019-05-29 09:00:25 +08:00
|
|
|
// this is carefully batched so we can do a leading debounce (trigger right away)
|
2020-12-18 21:18:52 +08:00
|
|
|
return discourseDebounce(
|
2019-05-29 09:00:25 +08:00
|
|
|
null,
|
2020-06-06 00:15:14 +08:00
|
|
|
_loadShortUrls,
|
|
|
|
shortUploadElements,
|
|
|
|
ajax,
|
|
|
|
siteSettings,
|
2020-07-10 22:57:06 +08:00
|
|
|
opts,
|
2019-05-29 09:00:25 +08:00
|
|
|
450,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|