oleg.vodyanov91@gmail.com 6e20d9c3f9
All checks were successful
continuous-integration/drone/push Build is passing
add_caching
2025-04-23 13:18:54 +04:00

190 lines
5.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const newLinkInput = document.getElementById('newLinkInput');
const addLinkBtn = document.getElementById('addLinkBtn');
const newLinksContainer = document.getElementById('newLinksContainer');
const watchedLinksContainer = document.getElementById('watchedLinksContainer');
const PER_PAGE = 8;
let currentPage = 1;
let linksData = [];
function loadLinks() {
const cacheKey = `links_cache_page_${currentPage}_per_${PER_PAGE}`;
const cached = localStorage.getItem(cacheKey);
if (cached) {
const data = JSON.parse(cached);
linksData = data.results;
renderPaginatedList(
linksData.filter(l => !l.watched),newLinksContainer,false,data.page,data.pages
);
renderPaginatedList(
linksData.filter(l => l.watched),watchedLinksContainer,true,data.page,data.pages
);
}
// Always fetch fresh data in the background
fetch(`/api/links/?page=${currentPage}&per_page=${PER_PAGE}`)
.then(res => res.json())
.then(data => {
localStorage.setItem(cacheKey, JSON.stringify(data));
if (!cached) {
linksData = data.results;
renderPaginatedList(
linksData.filter(l => !l.watched),newLinksContainer,false,data.page,data.pages
);
renderPaginatedList(
linksData.filter(l => l.watched),watchedLinksContainer,true,data.page,data.pages
);
}
})
.catch(err => console.error(err));
}
function renderPaginatedList(linkList, container, isWatched, page, totalPages) {
container.innerHTML = '';
const row = document.createElement('div');
row.className = 'row gy-4';
linkList
.filter(link => link.watched === isWatched)
.forEach(link => {
const col = document.createElement('div');
col.className = 'col-12 col-sm-6 col-md-4 col-lg-3';
col.appendChild(createLinkElement(link, isWatched));
row.appendChild(col);
});
container.appendChild(row);
// Pagination controls
if (totalPages > 1) {
const nav = document.createElement('div');
nav.className = 'd-flex justify-content-center mt-4 gap-2';
const prevBtn = document.createElement('button');
prevBtn.innerText = '← Previous';
prevBtn.className = 'btn btn-outline-primary';
prevBtn.disabled = page <= 1;
prevBtn.onclick = () => {
currentPage--;
loadLinks();
};
const nextBtn = document.createElement('button');
nextBtn.innerText = 'Next →';
nextBtn.className = 'btn btn-outline-primary';
nextBtn.disabled = page >= totalPages;
nextBtn.onclick = () => {
currentPage++;
loadLinks();
};
nav.appendChild(prevBtn);
nav.appendChild(nextBtn);
container.appendChild(nav);
}
reinitializeInstagramEmbeds();
}
// Create a DOM element for a single link
function createLinkElement(link, isWatched) {
const wrapper = document.createElement('div');
wrapper.className = 'mb-3';
// Instagram embed blockquote
const blockquote = document.createElement('blockquote');
blockquote.className = 'instagram-media';
blockquote.setAttribute('data-instgrm-permalink', link.url);
blockquote.style.background = '#FFF';
const p = document.createElement('p');
p.innerText = 'Loading Instagram...';
blockquote.appendChild(p);
wrapper.appendChild(blockquote);
// Button to mark watched if it's not watched
if (!isWatched) {
const watchButton = document.createElement('button');
watchButton.className = 'btn btn-sm btn-secondary';
watchButton.innerText = 'Mark Watched';
watchButton.onclick = () => markLinkWatched(link.id);
wrapper.appendChild(watchButton);
}
// Delete button
const deleteButton = document.createElement('button');
deleteButton.innerText = 'Delete';
deleteButton.className = 'btn btn-sm btn-danger';
deleteButton.onclick = () => deleteLink(link.id);
wrapper.appendChild(deleteButton);
return wrapper;
}
function deleteLink(linkId) {
fetch(`/api/links/${linkId}/delete/`, {
method: 'DELETE'
})
.then(res => {
if (res.ok) {
linksData = linksData.filter(link => link.id !== linkId);
currentPage = 1;
loadLinks();
reinitializeInstagramEmbeds();
}
})
.catch(err => console.error(err));
}
// Re-run the Instagram embed script after weve injected new blockquotes
function reinitializeInstagramEmbeds() {
if (window.instgrm) {
window.instgrm.Embeds.process();
}
}
// Mark a link as watched
function markLinkWatched(linkId) {
fetch(`/api/links/${linkId}/watched/`, {
method: 'PATCH'
})
.then(res => res.json())
.then(updatedLink => {
// Update the local array
const idx = linksData.findIndex(l => l.id === updatedLink.id);
if (idx !== -1) {
linksData[idx] = updatedLink;
}
loadLinks();
reinitializeInstagramEmbeds();
})
.catch(err => console.error(err));
}
// Add new link
addLinkBtn.addEventListener('click', () => {
const newUrl = newLinkInput.value.trim();
if (!newUrl) return;
fetch('/api/links/add/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url: newUrl })
})
.then(res => res.json())
.then(addedLink => {
// update local data
linksData.push(addedLink);
newLinkInput.value = '';
currentPage = 1;
loadLinks();
reinitializeInstagramEmbeds();
})
.catch(err => console.error(err));
});
// On page load
loadLinks();