discourse/app/assets/javascripts/pretty-text/oneboxer.js.es6

122 lines
3.0 KiB
JavaScript

let timeout;
const loadingQueue = [];
const localCache = {};
const failedCache = {};
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, normalizedUrl) {
if (!$elem.hasClass('whitelistedgeneric')) {
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, $elem, normalizedUrl);
} else {
$img.on('load.onebox', () => {
resolveSize(img, $elem, normalizedUrl);
$img.off('load.onebox');
});
}
}
function loadNext(ajax) {
if (loadingQueue.length === 0) {
timeout = null;
return;
}
let timeoutMs = 150;
let removeLoading = true;
const { url, refresh, $elem, userId } = loadingQueue.shift();
// Retrieve the onebox
return ajax("/onebox", {
dataType: 'html',
data: { url, refresh },
cache: true
}).then(html => {
let $html = $(html);
localCache[normalize(url)] = $html;
$elem.replaceWith($html);
applySquareGenericOnebox($html, normalize(url));
}, result => {
if (result && result.jqXHR && result.jqXHR.status === 429) {
timeoutMs = 2000;
removeLoading = false;
loadingQueue.unshift({ url, refresh, $elem, userId });
} else {
failedCache[normalize(url)] = true;
}
}).finally(() => {
timeout = Ember.run.later(() => loadNext(ajax), timeoutMs);
if (removeLoading) {
$elem.removeClass('loading-onebox');
$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(e, refresh, ajax, userId, synchronous) {
const $elem = $(e);
// If the onebox has loaded or is loading, return
if ($elem.data('onebox-loaded')) return;
if ($elem.hasClass('loading-onebox')) return;
const url = e.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;
}
// Add the loading CSS class
$elem.addClass('loading-onebox');
// Add to the loading queue
loadingQueue.push({ url, refresh, $elem, userId });
// Load next url in queue
if (synchronous) {
return loadNext(ajax);
} else {
timeout = timeout || Ember.run.later(() => loadNext(ajax), 150);
}
}
// Sometimes jQuery will return URLs with trailing slashes when the
// `href` didn't have them.
function normalize(url) {
return url.replace(/\/$/, '');
}
export function lookupCache(url) {
const cached = localCache[normalize(url)];
return cached && cached.prop('outerHTML');
}