| Current Path : /var/www/html/media/com_jdownloads/js/ |
| Current File : /var/www/html/media/com_jdownloads/js/subcategory-pagination.js |
/**
* @package jDownloads
* @version 4.1
* @copyright (C) 2007 - 2026 - Arno Betz - www.jdownloads.com
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.txt
*
* Modern Subcategory Pagination with Bootstrap 5 Support
* Hybrid approach: Auto-detects layout type and applies appropriate pagination
*/
(function() {
'use strict';
class JDSubcatPagination {
constructor(config) {
this.config = {
containerId: 'results',
itemSelector: '.jd_subcat_pagination_inner_wrapper',
itemsPerPage: 10,
labels: {
prev: 'Previous',
next: 'Next',
start: 'Start',
end: 'End',
page: 'Page',
of: 'of'
},
...config
};
this.container = document.getElementById(this.config.containerId);
if (!this.container) {
return;
}
this.items = Array.from(this.container.querySelectorAll(this.config.itemSelector));
this.totalItems = this.items.length;
this.totalPages = Math.ceil(this.totalItems / this.config.itemsPerPage);
this.currentPage = 1;
this.detectLayoutType();
this.init();
}
detectLayoutType() {
// Auto-detect layout type based on existing HTML structure
const container = this.container;
// Check for Bootstrap 5 classes
if (container.querySelector('.row, .col-, [class*="col-"]')) {
this.layoutType = 'bootstrap5';
}
// Check for table layout
else if (container.querySelector('table') || this.container.parentElement.querySelector('table')) {
this.layoutType = 'table';
}
// Default: modern divs
else {
this.layoutType = 'modern';
}
}
init() {
if (this.totalItems === 0 || this.totalItems <= this.config.itemsPerPage) {
// No pagination needed
return;
}
// Create pagination container
this.createPaginationContainer();
// Show first page
this.showPage(1);
}
createPaginationContainer() {
// Find or create pagination wrapper
let paginationWrapper = document.getElementById('jd_page_nav');
const placeBottom = Number(this.config.paginationPosBottom) === 1;
if (!paginationWrapper) {
paginationWrapper = document.createElement('div');
paginationWrapper.id = 'jd_page_nav';
paginationWrapper.className = 'jd-subcategory-pagination';
}
// Insert based on config (0 = above, 1 = below)
if (placeBottom) {
this.container.parentNode.insertBefore(paginationWrapper, this.container.nextSibling);
} else {
this.container.parentNode.insertBefore(paginationWrapper, this.container);
}
this.paginationWrapper = paginationWrapper;
this.renderPagination();
}
renderPagination() {
const paginationHTML = this.layoutType === 'bootstrap5'
? this.buildBootstrap5Pagination()
: this.buildLegacyPagination();
this.paginationWrapper.innerHTML = paginationHTML;
this.attachEventListeners();
}
buildBootstrap5Pagination() {
const pages = [];
const maxVisiblePages = 7;
let startPage = Math.max(1, this.currentPage - Math.floor(maxVisiblePages / 2));
let endPage = Math.min(this.totalPages, startPage + maxVisiblePages - 1);
if (endPage - startPage < maxVisiblePages - 1) {
startPage = Math.max(1, endPage - maxVisiblePages + 1);
}
let html = `
${this.config.subcategoriesLabel ? `<div class="text-end text-muted small pe-3 mt-2">${this.config.subcategoriesLabel}</div>` : ''}
<nav aria-label="Subcategory pagination" class="mt-0 mb-0">
<ul class="pagination justify-content-end mb-0 mt-1">
<!-- First -->
<li class="page-item ${this.currentPage === 1 ? 'disabled' : ''}">
<a class="page-link" href="#" data-page="1" aria-label="${this.config.labels.start}">
<span aria-hidden="true">«</span>
</a>
</li>
<!-- Previous -->
<li class="page-item ${this.currentPage === 1 ? 'disabled' : ''}">
<a class="page-link" href="#" data-page="${this.currentPage - 1}" aria-label="${this.config.labels.prev}">
<span aria-hidden="true">‹</span>
</a>
</li>
`;
// Page numbers
if (startPage > 1) {
html += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
}
for (let i = startPage; i <= endPage; i++) {
html += `
<li class="page-item ${i === this.currentPage ? 'active' : ''}">
<a class="page-link" href="#" data-page="${i}">${i}</a>
</li>
`;
}
if (endPage < this.totalPages) {
html += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
}
html += `
<!-- Next -->
<li class="page-item ${this.currentPage === this.totalPages ? 'disabled' : ''}">
<a class="page-link" href="#" data-page="${this.currentPage + 1}" aria-label="${this.config.labels.next}">
<span aria-hidden="true">›</span>
</a>
</li>
<!-- Last -->
<li class="page-item ${this.currentPage === this.totalPages ? 'disabled' : ''}">
<a class="page-link" href="#" data-page="${this.totalPages}" aria-label="${this.config.labels.end}">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
<div class="text-end text-muted small pe-3 border-bottom pb-2">
${this.config.labels.page} ${this.currentPage} ${this.config.labels.of} ${this.totalPages}
</div>
`;
return html;
}
buildLegacyPagination() {
let html = '<div class="jd_pagination_wrapper" style="text-align:center; margin:10px 0;">';
// First & Previous
if (this.currentPage > 1) {
html += `<a href="#" class="jd-page-link" data-page="1">${this.config.labels.start}</a> `;
html += `<a href="#" class="jd-page-link" data-page="${this.currentPage - 1}">${this.config.labels.prev}</a> `;
}
// Page numbers (simplified)
const maxPages = 10;
let startPage = Math.max(1, this.currentPage - 5);
let endPage = Math.min(this.totalPages, startPage + maxPages - 1);
for (let i = startPage; i <= endPage; i++) {
if (i === this.currentPage) {
html += `<strong style="margin:0 3px;">${i}</strong> `;
} else {
html += `<a href="#" class="jd-page-link" data-page="${i}" style="margin:0 3px;">${i}</a> `;
}
}
// Next & Last
if (this.currentPage < this.totalPages) {
html += `<a href="#" class="jd-page-link" data-page="${this.currentPage + 1}">${this.config.labels.next}</a> `;
html += `<a href="#" class="jd-page-link" data-page="${this.totalPages}">${this.config.labels.end}</a>`;
}
html += `<div style="margin-top:5px; font-size:0.9em;">${this.config.labels.page} ${this.currentPage} ${this.config.labels.of} ${this.totalPages}</div>`;
html += '</div>';
return html;
}
attachEventListeners() {
const links = this.paginationWrapper.querySelectorAll('a[data-page]');
links.forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const page = parseInt(link.getAttribute('data-page'));
if (page && page !== this.currentPage && page >= 1 && page <= this.totalPages) {
this.showPage(page);
}
});
});
}
showPage(pageNumber) {
if (pageNumber < 1 || pageNumber > this.totalPages) {
return;
}
this.currentPage = pageNumber;
// Hide all items
this.items.forEach(item => {
item.style.display = 'none';
});
// Show items for current page
const startIndex = (pageNumber - 1) * this.config.itemsPerPage;
const endIndex = Math.min(startIndex + this.config.itemsPerPage, this.totalItems);
for (let i = startIndex; i < endIndex; i++) {
this.items[i].style.display = '';
}
// Update pagination UI
this.renderPagination();
// Scroll to top of results
this.container.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
// Auto-initialize if config is present in window
if (typeof window.jdSubcatPaginationConfig !== 'undefined') {
document.addEventListener('DOMContentLoaded', () => {
new JDSubcatPagination(window.jdSubcatPaginationConfig);
});
}
// Make class available globally if needed
window.JDSubcatPagination = JDSubcatPagination;
})();