commercetools-8.x-1.2-alpha1/modules/commercetools_decoupled/js/molecules/Pager.js
modules/commercetools_decoupled/js/molecules/Pager.js
const LABEL_FIRST = '«';
const LABEL_PREV = '‹';
const LABEL_NEXT = '›';
const LABEL_LAST = '»';
class Pager extends HTMLElement {
constructor() {
super();
this.currentPage = 0;
this.totalPages = 1;
this.handlePageClick = this.handlePageClick.bind(this);
}
connectedCallback() {
this.renderPager();
this.addEventListener('click', this.handlePageClick);
}
disconnectedCallback() {
this.removeEventListener('click', this.handlePageClick);
}
handlePageClick(event) {
event.preventDefault();
const { target } = event;
if (target.classList.contains('page-link')) {
const page = parseInt(target?.dataset?.page, 10);
if (!Number.isNaN(page) && page >= 0 && page < this.totalPages) {
this.dispatchEvent(
new CustomEvent('page-change', { detail: { page } }),
);
}
}
}
renderPager() {
const maxVisible = 9;
const total = this.totalPages;
let start = 0;
let end = total;
if (total > maxVisible) {
const half = Math.floor(maxVisible / 2);
start = Math.max(this.currentPage - half, 0);
if (start + maxVisible > total) {
start = total - maxVisible;
}
end = start + maxVisible;
}
const fragment = document.createDocumentFragment();
const nav = document.createElement('nav');
nav.setAttribute('aria-label', 'product-pagination');
const ul = document.createElement('ul');
ul.className = 'pagination';
if (this.currentPage !== 0) {
ul.appendChild(
Pager.createPageItem(0, LABEL_FIRST, this.currentPage === 0),
);
ul.appendChild(
Pager.createPageItem(
this.currentPage - 1,
LABEL_PREV,
this.currentPage === 0,
),
);
}
if (start > 0) {
ul.appendChild(Pager.createEllipsisItem());
}
for (let i = start; i < end; i++) {
ul.appendChild(
Pager.createPageItem(i, String(i + 1), false, i === this.currentPage),
);
}
if (end < total) {
ul.appendChild(Pager.createEllipsisItem());
}
if (this.currentPage !== this.totalPages - 1) {
ul.appendChild(
Pager.createPageItem(
this.currentPage + 1,
LABEL_NEXT,
this.currentPage === total - 1,
),
);
ul.appendChild(
Pager.createPageItem(
total - 1,
LABEL_LAST,
this.currentPage === total - 1,
),
);
}
nav.appendChild(ul);
fragment.appendChild(nav);
this.innerHTML = '';
this.appendChild(fragment);
}
static createPageItem(page, label, isDisabled = false, isActive = false) {
const li = document.createElement('li');
const classMap = {
LABEL_FIRST: 'page-item--first',
LABEL_PREV: 'page-item--prev',
LABEL_NEXT: 'page-item--next',
LABEL_LAST: 'page-item--last',
};
const bemClasses = classMap[label] || '';
li.className = `page-item ${bemClasses}${isDisabled ? ' disabled' : ''}${isActive ? ' active' : ''}`;
const inner = isActive
? document.createElement('span')
: document.createElement('a');
inner.className = 'page-link';
const url = new URL(window.location);
url.searchParams.set('page', page);
inner.href = isDisabled ? '#' : url.toString();
inner.setAttribute('data-page', page);
inner.innerHTML = label;
li.appendChild(inner);
return li;
}
static createEllipsisItem() {
const li = document.createElement('li');
li.className = 'page-item disabled';
const span = document.createElement('span');
span.className = 'page-link';
span.textContent = '…';
li.appendChild(span);
return li;
}
setPager(currentPage, totalPages) {
this.currentPage = currentPage;
this.totalPages = totalPages;
this.renderPager();
}
}
customElements.define('ct-pager', Pager);
