REFACTOR: Remove jquery usage from resolveAllShortUrls, and fix debounce

- This function now requires an explicit scope. It will never run on the entire document.

- Previously debounce was being used with an anonymous function, which means it was having no effect.
This commit is contained in:
David Taylor 2020-06-05 17:15:14 +01:00
parent d4caf69ed7
commit 293467a37a
No known key found for this signature in database
GPG Key ID: 46904C18B1D3F434
3 changed files with 44 additions and 38 deletions

View File

@ -16,7 +16,7 @@ const CookText = Component.extend({
next(() => next(() =>
window window
.requireModule("pretty-text/upload-short-url") .requireModule("pretty-text/upload-short-url")
.resolveAllShortUrls(ajax, this.siteSettings) .resolveAllShortUrls(ajax, this.siteSettings, this.element)
); );
}); });
} }

View File

@ -43,12 +43,14 @@ export function resetCache() {
_cache = {}; _cache = {};
} }
function retrieveCachedUrl($upload, siteSettings, dataAttribute, callback) { function retrieveCachedUrl(upload, siteSettings, dataAttribute, callback) {
const cachedUpload = lookupCachedUploadUrl($upload.data(dataAttribute)); const cachedUpload = lookupCachedUploadUrl(
upload.getAttribute(`data-${dataAttribute}`)
);
const url = getAttributeBasedUrl(dataAttribute, cachedUpload, siteSettings); const url = getAttributeBasedUrl(dataAttribute, cachedUpload, siteSettings);
if (url) { if (url) {
$upload.removeAttr(`data-${dataAttribute}`); upload.removeAttribute(`data-${dataAttribute}`);
if (url !== MISSING) { if (url !== MISSING) {
callback(url); callback(url);
} }
@ -77,43 +79,40 @@ function getAttributeBasedUrl(dataAttribute, cachedUpload, siteSettings) {
return cachedUpload.short_path; return cachedUpload.short_path;
} }
function _loadCachedShortUrls($uploads, siteSettings) { function _loadCachedShortUrls(uploadElements, siteSettings) {
$uploads.each((_idx, upload) => { uploadElements.forEach(upload => {
const $upload = $(upload);
switch (upload.tagName) { switch (upload.tagName) {
case "A": case "A":
retrieveCachedUrl($upload, siteSettings, "orig-href", url => { retrieveCachedUrl(upload, siteSettings, "orig-href", url => {
$upload.attr("href", url); upload.href = url;
}); });
break; break;
case "IMG": case "IMG":
retrieveCachedUrl($upload, siteSettings, "orig-src", url => { retrieveCachedUrl(upload, siteSettings, "orig-src", url => {
$upload.attr("src", url); upload.src = url;
}); });
break; break;
case "SOURCE": // video/audio tag > source tag case "SOURCE": // video/audio tag > source tag
retrieveCachedUrl($upload, siteSettings, "orig-src", url => { retrieveCachedUrl(upload, siteSettings, "orig-src", url => {
$upload.attr("src", url);
if (url.startsWith(`//${window.location.host}`)) { if (url.startsWith(`//${window.location.host}`)) {
let hostRegex = new RegExp("//" + window.location.host, "g"); let hostRegex = new RegExp("//" + window.location.host, "g");
url = url.replace(hostRegex, ""); url = url.replace(hostRegex, "");
} }
let fullUrl = window.location.origin + url; let fullUrl = window.location.origin + url;
$upload.attr("src", fullUrl); upload.src = fullUrl;
// this is necessary, otherwise because of the src change the // this is necessary, otherwise because of the src change the
// video/audio just doesn't bother loading! // video/audio just doesn't bother loading!
let $parent = $upload.parent(); upload.parentElement.load();
$parent[0].load();
// set the url and text for the <a> tag within the <video/audio> tag // set the url and text for the <a> tag within the <video/audio> tag
$parent const link = upload.parentElement.querySelector("a");
.find("a") if (link) {
.attr("href", fullUrl) link.href = fullUrl;
.text(fullUrl); link.textContent = fullUrl;
}
}); });
break; break;
@ -121,31 +120,36 @@ function _loadCachedShortUrls($uploads, siteSettings) {
}); });
} }
function _loadShortUrls($uploads, ajax, siteSettings) { function _loadShortUrls(uploads, ajax, siteSettings) {
let urls = $uploads.toArray().map(upload => { let urls = [...uploads].map(upload => {
const $upload = $(upload); return (
return $upload.data("orig-src") || $upload.data("orig-href"); upload.getAttribute("data-orig-src") ||
upload.getAttribute("data-orig-href")
);
}); });
return lookupUncachedUploadUrls(urls, ajax).then(() => return lookupUncachedUploadUrls(urls, ajax).then(() =>
_loadCachedShortUrls($uploads, siteSettings) _loadCachedShortUrls(uploads, siteSettings)
); );
} }
export function resolveAllShortUrls(ajax, siteSettings, scope = null) { export function resolveAllShortUrls(ajax, siteSettings, scope) {
const attributes = const attributes =
"img[data-orig-src], a[data-orig-href], source[data-orig-src]"; "img[data-orig-src], a[data-orig-href], source[data-orig-src]";
let $shortUploadUrls = $(scope || document).find(attributes); let shortUploadElements = scope.querySelectorAll(attributes);
if ($shortUploadUrls.length > 0) { if (shortUploadElements.length > 0) {
_loadCachedShortUrls($shortUploadUrls, siteSettings); _loadCachedShortUrls(shortUploadElements, siteSettings);
$shortUploadUrls = $(scope || document).find(attributes); shortUploadElements = scope.querySelectorAll(attributes);
if ($shortUploadUrls.length > 0) { if (shortUploadElements.length > 0) {
// this is carefully batched so we can do a leading debounce (trigger right away) // this is carefully batched so we can do a leading debounce (trigger right away)
return debounce( return debounce(
null, null,
() => _loadShortUrls($shortUploadUrls, ajax, siteSettings), _loadShortUrls,
shortUploadElements,
ajax,
siteSettings,
450, 450,
true true
); );

View File

@ -84,7 +84,7 @@ QUnit.test("resolveAllShortUrls", async assert => {
lookup = lookupCachedUploadUrl("upload://a.jpeg"); lookup = lookupCachedUploadUrl("upload://a.jpeg");
assert.deepEqual(lookup, {}); assert.deepEqual(lookup, {});
await resolveAllShortUrls(ajax, { secure_media: false }); await resolveAllShortUrls(ajax, { secure_media: false }, fixture()[0]);
lookup = lookupCachedUploadUrl("upload://a.jpeg"); lookup = lookupCachedUploadUrl("upload://a.jpeg");
@ -126,7 +126,7 @@ QUnit.test(
"resolveAllShortUrls - href + src replaced correctly", "resolveAllShortUrls - href + src replaced correctly",
async assert => { async assert => {
stubUrls(); stubUrls();
await resolveAllShortUrls(ajax, { secure_media: false }); await resolveAllShortUrls(ajax, { secure_media: false }, fixture()[0]);
let image1 = fixture() let image1 = fixture()
.find("img") .find("img")
@ -156,7 +156,7 @@ QUnit.test(
], ],
null null
); );
await resolveAllShortUrls(ajax, { secure_media: true }); await resolveAllShortUrls(ajax, { secure_media: true }, fixture()[0]);
let link = fixture().find("a"); let link = fixture().find("a");
assert.equal( assert.equal(
@ -169,7 +169,9 @@ QUnit.test(
QUnit.test("resolveAllShortUrls - scoped", async assert => { QUnit.test("resolveAllShortUrls - scoped", async assert => {
stubUrls(); stubUrls();
let lookup; let lookup;
await resolveAllShortUrls(ajax, ".scoped-area");
let scopedElement = fixture()[0].querySelector(".scoped-area");
await resolveAllShortUrls(ajax, {}, scopedElement);
lookup = lookupCachedUploadUrl("upload://z.jpeg"); lookup = lookupCachedUploadUrl("upload://z.jpeg");
@ -181,7 +183,7 @@ QUnit.test("resolveAllShortUrls - scoped", async assert => {
// do this because the pretender caches ALL the urls, not // do this because the pretender caches ALL the urls, not
// just the ones being looked up (like the normal behaviour) // just the ones being looked up (like the normal behaviour)
resetCache(); resetCache();
await resolveAllShortUrls(ajax, ".scoped-area"); await resolveAllShortUrls(ajax, {}, scopedElement);
lookup = lookupCachedUploadUrl("upload://a.jpeg"); lookup = lookupCachedUploadUrl("upload://a.jpeg");
assert.deepEqual(lookup, {}); assert.deepEqual(lookup, {});