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`