Skip to content

Commit

Permalink
refactor: image progress
Browse files Browse the repository at this point in the history
  • Loading branch information
dewanakl committed Jan 20, 2025
1 parent fd9a487 commit f3dfec0
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 117 deletions.
145 changes: 28 additions & 117 deletions js/app/guest/guest.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { image } from './image.js';
import { audio } from './audio.js';
import { progress } from './progress.js';
import { util } from '../../common/util.js';
Expand Down Expand Up @@ -83,7 +84,8 @@ export const guest = (() => {
div.classList.add('m-2');
div.innerHTML = `
<p class="mt-0 mb-1 mx-0 p-0" style="font-size: 0.95rem;">${guest?.getAttribute('data-message')}</p>
<h2 class="m-0 p-0">${util.escapeHtml(name)}</h2>`;
<h2 class="m-0 p-0">${util.escapeHtml(name)}</h2>
`;

guest?.appendChild(div);
}
Expand Down Expand Up @@ -147,96 +149,12 @@ export const guest = (() => {
/**
* @returns {void}
*/
const normalize = () => {
const normalizeArabicFont = () => {
document.querySelectorAll('.font-arabic').forEach((el) => {
el.innerHTML = String(el.innerHTML).normalize('NFC');
});
};

/**
* @returns {void}
*/
const imageProgress = () => {
/**
* @type {Map<string, string>}
*/
const uniqueUrl = new Map();

/**
* @param {HTMLImageElement} el
* @returns {Promise<void>}
*/
const getByFetch = async (el) => {
// 6 hour TTL
const ttl = 1000 * 60 * 60 * 6;
const url = el.getAttribute('data-src');
const exp = 'x-expiration-time';
const cacheName = 'image_cache';

if (uniqueUrl.has(url)) {
el.src = uniqueUrl.get(url);
progress.complete('image');
return;
}

/**
* @param {Cache} c
* @returns {Promise<blob>}
*/
const fetchPut = (c) => {
return fetch(url).then((res) => res.blob().then((b) => {
const headers = new Headers(res.headers);
headers.append(exp, String(Date.now() + ttl));

return c.put(url, new Response(b, { headers })).then(() => b);
}));
};

await caches.open(cacheName).then((c) => {
return c.match(url).then((res) => {
if (!res) {
return fetchPut(c);
}

if (Date.now() <= parseInt(res.headers.get(exp))) {
return res.blob();
}

return c.delete(url).then((s) => s ? fetchPut(c) : res.blob());
}).then((b) => {
el.src = URL.createObjectURL(b);
uniqueUrl.set(url, el.src);
progress.complete('image');
})
}).catch(() => progress.invalid('image'));
};

/**
* @param {HTMLImageElement} el
* @returns {void}
*/
const getByDefault = (el) => {
el.onerror = () => progress.invalid('image');
el.onload = () => progress.complete('image');

if (el.complete && el.naturalWidth !== 0 && el.naturalHeight !== 0) {
progress.complete('image');
} else if (el.complete) {
progress.invalid('image');
}
};

(async (els) => {
for (const el of els) {
if (el.hasAttribute('data-src')) {
await getByFetch(el);
} else {
getByDefault(el);
}
}
})(document.querySelectorAll('img'));
};

/**
* @returns {object}
*/
Expand All @@ -246,13 +164,12 @@ export const guest = (() => {
offline.init();
progress.init();

normalize();
countDownDate();
normalizeArabicFont();
information = storage('information');
document.addEventListener('progressDone', () => {
showGuestName();
window.AOS.init();
});

document.addEventListener('progressDone', showGuestName);
document.addEventListener('progressDone', window.AOS.init);

if (session.isAdmin()) {
storage('user').clear();
Expand All @@ -272,12 +189,9 @@ export const guest = (() => {
info.remove();
}

// add total image.
document.querySelectorAll('img').forEach(progress.add);

const token = document.body.getAttribute('data-key');
if (!token || token.length === 0) {
imageProgress();
image.init().load();
document.getElementById('comment')?.remove();
document.querySelector('a.nav-link[href="#comment"]')?.closest('li.nav-item')?.remove();
}
Expand All @@ -287,31 +201,28 @@ export const guest = (() => {
progress.add();
progress.add();

const hasDataSrc = Array.from(document.querySelectorAll('img')).some((i) => i.hasAttribute('data-src'));
if (!hasDataSrc) {
imageProgress();
const img = image.init();
if (!img.hasDataSrc()) {
img.load();
}

session.setToken(token);
session.guest()
.then((res) => {
if (res.code !== 200) {
progress.invalid('config');
return;
}

progress.complete('config');

if (hasDataSrc) {
imageProgress();
}

comment.init();
comment.comment()
.then(() => progress.complete('comment'))
.catch(() => progress.invalid('comment'));
})
.catch(() => progress.invalid('config'));
session.guest().then((res) => {
if (res.code !== 200) {
progress.invalid('config');
return;
}

progress.complete('config');
if (img.hasDataSrc()) {
img.load();
}

comment.init();
comment.comment()
.then(() => progress.complete('comment'))
.catch(() => progress.invalid('comment'));
}).catch(() => progress.invalid('config'));
}

return {
Expand Down
122 changes: 122 additions & 0 deletions js/app/guest/image.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { progress } from './progress.js';

export const image = (() => {

/**
* @type {Map<string, string>}
*/
let uniqueUrl = null;

/**
* @type {NodeListOf<HTMLImageElement>}
*/
let images = null;

let hasSrc = true;

// 6 hour TTL
const ttl = 1000 * 60 * 60 * 6;

const cacheName = 'image_cache';

/**
* @param {HTMLImageElement} el
* @returns {Promise<void>}
*/
const getByFetch = async (el) => {
const url = el.getAttribute('data-src');
const exp = 'x-expiration-time';

if (uniqueUrl.has(url)) {
el.src = uniqueUrl.get(url);
progress.complete('image');
return;
}

/**
* @param {Cache} c
* @returns {Promise<blob>}
*/
const fetchPut = (c) => {
return fetch(url).then((res) => res.blob().then((b) => {
const headers = new Headers(res.headers);
headers.append(exp, String(Date.now() + ttl));

return c.put(url, new Response(b, { headers })).then(() => b);
}));
};

await caches.open(cacheName).then((c) => {
return c.match(url).then((res) => {
if (!res) {
return fetchPut(c);
}

if (Date.now() <= parseInt(res.headers.get(exp))) {
return res.blob();
}

return c.delete(url).then((s) => s ? fetchPut(c) : res.blob());
}).then((b) => {
el.src = URL.createObjectURL(b);
uniqueUrl.set(url, el.src);
progress.complete('image');
})
}).catch(() => progress.invalid('image'));
};

/**
* @param {HTMLImageElement} el
* @returns {void}
*/
const getByDefault = (el) => {
el.onerror = () => progress.invalid('image');
el.onload = () => progress.complete('image');

if (el.complete && el.naturalWidth !== 0 && el.naturalHeight !== 0) {
progress.complete('image');
} else if (el.complete) {
progress.invalid('image');
}
};

/**
* @returns {boolean}
*/
const hasDataSrc = () => hasSrc;

/**
* @returns {void}
*/
const load = () => {
(async () => {
for (const el of images) {
if (el.hasAttribute('data-src')) {
await getByFetch(el);
} else {
getByDefault(el);
}
}
})();
};

/**
* @returns {object}
*/
const init = () => {
uniqueUrl = new Map();
images = document.querySelectorAll('img');

images.forEach(progress.add);
hasSrc = Array.from(images).some((i) => i.hasAttribute('data-src'));

return {
load,
hasDataSrc,
};
};

return {
init,
};
})();

0 comments on commit f3dfec0

Please sign in to comment.