mirror of
https://github.com/olegvodyanov/instalinks.git
synced 2025-12-20 07:57:04 +03:00
add pagination
This commit is contained in:
parent
a513641c38
commit
07d1d7d990
@ -29,3 +29,4 @@ volumes:
|
|||||||
trigger:
|
trigger:
|
||||||
branch:
|
branch:
|
||||||
- master
|
- master
|
||||||
|
- develop
|
||||||
@ -16,11 +16,27 @@ def links_list(request):
|
|||||||
"""
|
"""
|
||||||
Return JSON list of all links.
|
Return JSON list of all links.
|
||||||
"""
|
"""
|
||||||
if request.method == 'GET':
|
|
||||||
all_links = Link.objects.all().values('id', 'url', 'watched')
|
try:
|
||||||
return JsonResponse(list(all_links), safe=False)
|
page = int(request.GET.get('page', 1))
|
||||||
else:
|
per_page = int(request.GET.get('per_page', 8))
|
||||||
return JsonResponse({'error': 'Method not allowed'}, status=405)
|
except ValueError:
|
||||||
|
return JsonResponse({'error': 'Invalid page or per_page'}, status=400)
|
||||||
|
|
||||||
|
offset = (page - 1) * per_page
|
||||||
|
limit = offset + per_page
|
||||||
|
|
||||||
|
all_links = Link.objects.all().order_by('-id') # latest first
|
||||||
|
total = all_links.count()
|
||||||
|
results = list(all_links[offset:limit].values('id', 'url', 'watched'))
|
||||||
|
|
||||||
|
return JsonResponse({
|
||||||
|
'results': results,
|
||||||
|
'total': total,
|
||||||
|
'page': page,
|
||||||
|
'per_page': per_page,
|
||||||
|
'pages': (total + per_page - 1) // per_page
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
|
|||||||
@ -3,52 +3,65 @@ const addLinkBtn = document.getElementById('addLinkBtn');
|
|||||||
const newLinksContainer = document.getElementById('newLinksContainer');
|
const newLinksContainer = document.getElementById('newLinksContainer');
|
||||||
const watchedLinksContainer = document.getElementById('watchedLinksContainer');
|
const watchedLinksContainer = document.getElementById('watchedLinksContainer');
|
||||||
|
|
||||||
|
const PER_PAGE = 8;
|
||||||
let linksData = [];
|
let linksData = [];
|
||||||
|
let currentPage = 1;
|
||||||
|
|
||||||
// Fetch all links from the server
|
|
||||||
function loadLinks() {
|
function loadLinks() {
|
||||||
fetch('/api/links/')
|
fetch('/api/links/?page=${currentPage}&per_page=${PER_PAGE}')
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
linksData = data; // store in a global variable
|
linksData = data.results;
|
||||||
renderLinks();
|
renderPaginatedList(linksData, newLinksContainer, false, data.page, data.pages);
|
||||||
|
renderPaginatedList(linksData.filter(l => l.watched), watchedLinksContainer, true, data.page, data.pages);
|
||||||
})
|
})
|
||||||
.catch(err => console.error(err));
|
.catch(err => console.error(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the links into the two tabs
|
function renderPaginatedList(linkList, container, isWatched, page, totalPages) {
|
||||||
function renderLinks() {
|
container.innerHTML = '';
|
||||||
// separate them
|
|
||||||
const newLinks = linksData.filter(link => !link.watched);
|
|
||||||
const watchedLinks = linksData.filter(link => link.watched);
|
|
||||||
|
|
||||||
const newRow = document.createElement('div');
|
const row = document.createElement('div');
|
||||||
newRow.className = 'row gy-4';
|
row.className = 'row gy-4';
|
||||||
|
|
||||||
// Render "New" links
|
linkList
|
||||||
newLinksContainer.innerHTML = '';
|
.filter(link => link.watched === isWatched)
|
||||||
newLinks.forEach(link => {
|
.forEach(link => {
|
||||||
const col = document.createElement('div');
|
|
||||||
col.className = 'col-12 col-sm-6 col-md-4 col-lg-3'; // responsive columns
|
|
||||||
col.appendChild(createLinkElement(link, false));
|
|
||||||
newRow.appendChild(col);
|
|
||||||
});
|
|
||||||
|
|
||||||
newLinksContainer.appendChild(newRow);
|
|
||||||
|
|
||||||
const watchedRow = document.createElement('div');
|
|
||||||
watchedRow.className = 'row gy-4';
|
|
||||||
|
|
||||||
// Render "Watched" links
|
|
||||||
watchedLinksContainer.innerHTML = '';
|
|
||||||
watchedLinks.forEach(link => {
|
|
||||||
const col = document.createElement('div');
|
const col = document.createElement('div');
|
||||||
col.className = 'col-12 col-sm-6 col-md-4 col-lg-3';
|
col.className = 'col-12 col-sm-6 col-md-4 col-lg-3';
|
||||||
col.appendChild(createLinkElement(link, true));
|
col.appendChild(createLinkElement(link, isWatched));
|
||||||
watchedRow.appendChild(col);
|
row.appendChild(col);
|
||||||
});
|
});
|
||||||
|
|
||||||
watchedLinksContainer.appendChild(watchedRow);
|
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();
|
reinitializeInstagramEmbeds();
|
||||||
}
|
}
|
||||||
@ -95,7 +108,8 @@ function deleteLink(linkId) {
|
|||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
linksData = linksData.filter(link => link.id !== linkId);
|
linksData = linksData.filter(link => link.id !== linkId);
|
||||||
renderLinks();
|
currentPage = 1;
|
||||||
|
renderPaginatedList();
|
||||||
reinitializeInstagramEmbeds();
|
reinitializeInstagramEmbeds();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -121,7 +135,7 @@ function markLinkWatched(linkId) {
|
|||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
linksData[idx] = updatedLink;
|
linksData[idx] = updatedLink;
|
||||||
}
|
}
|
||||||
renderLinks();
|
renderPaginatedList();
|
||||||
reinitializeInstagramEmbeds();
|
reinitializeInstagramEmbeds();
|
||||||
})
|
})
|
||||||
.catch(err => console.error(err));
|
.catch(err => console.error(err));
|
||||||
@ -142,7 +156,8 @@ addLinkBtn.addEventListener('click', () => {
|
|||||||
// update local data
|
// update local data
|
||||||
linksData.push(addedLink);
|
linksData.push(addedLink);
|
||||||
newLinkInput.value = '';
|
newLinkInput.value = '';
|
||||||
renderLinks();
|
currentPage = 1;
|
||||||
|
renderPaginatedList();
|
||||||
reinitializeInstagramEmbeds();
|
reinitializeInstagramEmbeds();
|
||||||
})
|
})
|
||||||
.catch(err => console.error(err));
|
.catch(err => console.error(err));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user