import { LitElement, html, css } from '@lion/core'; import { LocalizeMixin } from '@lion/localize'; /** * `LionPagination` is a class for custom Pagination element (`` web component). * * @customElement lion-pagination * @extends LitElement */ export class LionPagination extends LocalizeMixin(LitElement) { static get styles() { return css` :host { cursor: default; } ul { list-style: none; padding: 0; text-align: center; } li { display: inline-block; } button[aria-current='true'] { font-weight: bold; } `; } static get localizeNamespaces() { return [ { 'lion-pagination': locale => { switch (locale) { case 'bg-BG': return import('../translations/bg.js'); case 'cs-CZ': return import('../translations/cs.js'); case 'de-AT': case 'de-DE': return import('../translations/de.js'); case 'en-AU': case 'en-GB': case 'en-PH': case 'en-US': return import('../translations/en.js'); case 'es-ES': return import('../translations/es.js'); case 'fr-FR': case 'fr-BE': return import('../translations/fr.js'); case 'hu-HU': return import('../translations/hu.js'); case 'it-IT': return import('../translations/it.js'); case 'nl-BE': case 'nl-NL': return import('../translations/nl.js'); case 'pl-PL': return import('../translations/pl.js'); case 'ro-RO': return import('../translations/ro.js'); case 'ru-RU': return import('../translations/ru.js'); case 'sk-SK': return import('../translations/sk.js'); case 'uk-UA': return import('../translations/uk.js'); case 'zh-CN': return import('../translations/zh.js'); default: return import('../translations/en.js'); } }, }, ...super.localizeNamespaces, ]; } static get properties() { return { current: { type: Number, reflect: true, }, count: { type: Number, reflect: true, }, }; } set current(value) { if (value !== this.current) { const oldValue = this.current; this.__current = value; this.dispatchEvent(new Event('current-changed')); this.requestUpdate('current', oldValue); } } get current() { return this.__current; } constructor() { super(); this.__visiblePages = 5; this.current = 1; this.count = 0; } /** * Go next in pagination * @public */ next() { if (this.current < this.count) { this.__fire(this.current + 1); } } /** * Go to first page * @public */ first() { if (this.count >= 1) { this.__fire(1); } } /** * Go to the last page * @public */ last() { if (this.count >= 1) { this.__fire(this.count); } } /** * Go to the specific page * @public */ goto(pageNumber) { if (pageNumber >= 1 && pageNumber <= this.count) { this.__fire(pageNumber); } } /** * Go back in pagination * @public */ previous() { if (this.current !== 1) { this.__fire(this.current - 1); } } /** * Set desired page in the pagination and fire the current changed event. * @param {Number} page page number to be set * @private */ __fire(page) { if (page !== this.current) { this.current = page; } } /** * Calculate nav list based on current page selection. * @returns {Array} * @private */ __calculateNavList() { const start = 1; const finish = this.count; // If there are more pages then we want to display we have to redo the list each time // Else we can just return the same list every time. if (this.count > this.__visiblePages) { // Calculate left side of current page and right side const pos3 = this.current - 1; const pos4 = this.current; const pos5 = this.current + 1; // if pos 3 is lower than 4 we have a predefined list of elements if (pos4 <= 4) { const list = Array(this.__visiblePages) .fill() .map((_, idx) => start + idx); list.push('...'); list.push(this.count); return list; } // if we are close to the end of the list with the current page then we have again a predefined list if (finish - pos4 <= 3) { const list = []; list.push(1); list.push('...'); const listRemaining = Array(this.__visiblePages) .fill() .map((_, idx) => this.count - this.__visiblePages + 1 + idx); return list.concat(listRemaining); } return [start, '...', pos3, pos4, pos5, '...', finish]; } return Array(finish - start + 1) .fill() .map((_, idx) => start + idx); } /** * Get previous or next button template. * This method can be overridden to apply customized template in wrapper. * @param {String} label namespace label i.e. next or previous * @returns {TemplateResult} icon template * @protected */ // eslint-disable-next-line class-methods-use-this _prevNextIconTemplate(label) { return label === 'next' ? html` > ` : html` < `; } /** * Get next or previous button template. * This method can be overridden to apply customized template in wrapper. * @param {String} label namespace label i.e. next or previous * @param {Number} pageNumber page number to be set * @param {String} namespace namespace prefix for translations * @returns {TemplateResult} nav item template * @protected */ _prevNextButtonTemplate(label, pageNumber, namespace = 'lion') { return html`
  • `; } /** * Get disabled button template. * This method can be overridden to apply customized template in wrapper. * @param {String} label namespace label i.e. next or previous * @returns {TemplateResult} nav item template * @protected */ _disabledButtonTemplate(label) { return html`
  • `; } /** * Render navigation list * @returns {TemplateResult} nav list template * @protected */ _renderNavList() { return this.__calculateNavList().map(page => page === '...' ? html`
  • ${page}
  • ` : html`
  • `, ); } render() { return html` `; } }