mirror of
https://github.com/discourse/discourse.git
synced 2024-12-16 23:53:43 +08:00
08acf51be0
Displaying videos, animated GIFs or any kind of rich content in preview used to refresh on every keystroke, which could cause performance problems.
157 lines
3.4 KiB
JavaScript
157 lines
3.4 KiB
JavaScript
import {
|
|
failedCache,
|
|
localCache,
|
|
normalize,
|
|
resetFailedCache,
|
|
resetLocalCache,
|
|
setFailedCache,
|
|
setLocalCache,
|
|
} from "pretty-text/oneboxer-cache";
|
|
import { later } from "@ember/runloop";
|
|
|
|
let timeout;
|
|
const loadingQueue = [];
|
|
|
|
export const LOADING_ONEBOX_CSS_CLASS = "loading-onebox";
|
|
|
|
export function resetCache() {
|
|
loadingQueue.clear();
|
|
resetLocalCache();
|
|
resetFailedCache();
|
|
}
|
|
|
|
function resolveSize(img) {
|
|
$(img).addClass("size-resolved");
|
|
|
|
if (img.width > 0 && img.width === img.height) {
|
|
$(img).addClass("onebox-avatar");
|
|
}
|
|
}
|
|
|
|
// Detect square images and apply smaller onebox-avatar class
|
|
function applySquareGenericOnebox($elem) {
|
|
if (!$elem.hasClass("allowlistedgeneric")) {
|
|
return;
|
|
}
|
|
|
|
let $img = $elem.find(".onebox-body img.thumbnail");
|
|
let img = $img[0];
|
|
|
|
// already resolved... skip
|
|
if ($img.length !== 1 || $img.hasClass("size-resolved")) {
|
|
return;
|
|
}
|
|
|
|
if (img.complete) {
|
|
resolveSize(img);
|
|
} else {
|
|
$img.on("load.onebox", () => {
|
|
resolveSize(img);
|
|
$img.off("load.onebox");
|
|
});
|
|
}
|
|
}
|
|
|
|
function loadNext(ajax) {
|
|
if (loadingQueue.length === 0) {
|
|
timeout = null;
|
|
return;
|
|
}
|
|
|
|
let timeoutMs = 150;
|
|
let removeLoading = true;
|
|
const { url, refresh, $elem, categoryId, topicId } = loadingQueue.shift();
|
|
|
|
// Retrieve the onebox
|
|
return ajax("/onebox", {
|
|
dataType: "html",
|
|
data: {
|
|
url,
|
|
refresh,
|
|
category_id: categoryId,
|
|
topic_id: topicId,
|
|
},
|
|
cache: true,
|
|
})
|
|
.then(
|
|
(html) => {
|
|
let $html = $(html);
|
|
setLocalCache(normalize(url), $html);
|
|
$elem.replaceWith($html);
|
|
applySquareGenericOnebox($html);
|
|
},
|
|
(result) => {
|
|
if (result && result.jqXHR && result.jqXHR.status === 429) {
|
|
timeoutMs = 2000;
|
|
removeLoading = false;
|
|
loadingQueue.unshift({ url, refresh, $elem, categoryId, topicId });
|
|
} else {
|
|
setFailedCache(normalize(url), true);
|
|
}
|
|
}
|
|
)
|
|
.finally(() => {
|
|
timeout = later(() => loadNext(ajax), timeoutMs);
|
|
if (removeLoading) {
|
|
$elem.removeClass(LOADING_ONEBOX_CSS_CLASS);
|
|
$elem.data("onebox-loaded");
|
|
}
|
|
});
|
|
}
|
|
|
|
// Perform a lookup of a onebox based an anchor $element.
|
|
// It will insert a loading indicator and remove it when the loading is complete or fails.
|
|
export function load({
|
|
elem,
|
|
ajax,
|
|
topicId,
|
|
categoryId,
|
|
refresh = true,
|
|
offline = false,
|
|
synchronous = false,
|
|
}) {
|
|
const $elem = $(elem);
|
|
|
|
// If the onebox has loaded or is loading, return
|
|
if ($elem.data("onebox-loaded")) {
|
|
return;
|
|
}
|
|
if ($elem.hasClass(LOADING_ONEBOX_CSS_CLASS)) {
|
|
return;
|
|
}
|
|
|
|
const url = elem.href;
|
|
|
|
// Unless we're forcing a refresh...
|
|
if (!refresh) {
|
|
// If we have it in our cache, return it.
|
|
const cached = localCache[normalize(url)];
|
|
if (cached) {
|
|
return cached.prop("outerHTML");
|
|
}
|
|
|
|
// If the request failed, don't do anything
|
|
const failed = failedCache[normalize(url)];
|
|
if (failed) {
|
|
return;
|
|
}
|
|
|
|
if (offline) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Add the loading CSS class
|
|
$elem.addClass(LOADING_ONEBOX_CSS_CLASS);
|
|
|
|
// Add to the loading queue
|
|
loadingQueue.push({ url, refresh, $elem, categoryId, topicId });
|
|
|
|
// Load next url in queue
|
|
if (synchronous) {
|
|
return loadNext(ajax);
|
|
} else {
|
|
timeout = timeout || later(() => loadNext(ajax), 150);
|
|
}
|
|
}
|