gd-bs
Version:
Bootstrap JavaScript, TypeScript and Web Components library.
394 lines (393 loc) • 17.5 kB
JavaScript
import { Base } from "../base";
import { skipBackward } from "../../icons/svgs/skipBackward";
import { skipForward } from "../../icons/svgs/skipForward";
import { skipEnd } from "../../icons/svgs/skipEnd";
import { skipStart } from "../../icons/svgs/skipStart";
import { HTML, HTMLItem } from "./templates";
/**
* Pagination Alignment
*/
export var PaginationAlignment;
(function (PaginationAlignment) {
PaginationAlignment[PaginationAlignment["Center"] = 1] = "Center";
PaginationAlignment[PaginationAlignment["Left"] = 2] = "Left";
PaginationAlignment[PaginationAlignment["Right"] = 3] = "Right";
})(PaginationAlignment || (PaginationAlignment = {}));
/**
* Pagination
*/
class _Pagination extends Base {
// Constructor
constructor(props, template = HTML, itemTemplate = HTMLItem) {
super(template, props);
this._activePage = null;
this._elList = null;
this._items = null;
this._showDefault = true;
// Buttons
this._buttons = null;
// Create the default buttons
this.createButtons(itemTemplate);
// Configure the collapse
this.configure(itemTemplate);
// Configure the parent
this.configureParent();
}
// Configure the card group
configure(itemTemplate) {
// Update the nav properties
this.props.label ? this.el.setAttribute("aria-label", this.props.label) : null;
// Update the list
this._elList = this.el.querySelector("ul");
if (this._elList) {
this.props.isLarge ? this._elList.classList.add("pagination-lg") : null;
this.props.isSmall ? this._elList.classList.add("pagination-sm") : null;
// Read the alignment
switch (this.props.alignment) {
// Danger
case PaginationAlignment.Center:
this._elList.classList.add("justify-content-center");
break;
// Dark
case PaginationAlignment.Right:
this._elList.classList.add("justify-content-end");
break;
}
// Render the page numbers
this.renderPageNumbers(itemTemplate);
}
}
// Configures the default buttons, based on the active index
configureDefaultButtons() {
// Update the previous button
if (this._activePage == 1) {
// Ensure the first/previous item is disabled
this._buttons.First.classList.add("disabled");
this._buttons.Previous.classList.add("disabled");
}
else {
// Ensure the first/previous item is enabled
this._buttons.First.classList.remove("disabled");
this._buttons.Previous.classList.remove("disabled");
}
// Update the next/last button
if (this._activePage == this._items.length) {
// Ensure the next/last item is disabled
this._buttons.Next.classList.add("disabled");
this._buttons.Last.classList.add("disabled");
}
else {
// Ensure the next/last item is enabled
this._buttons.Next.classList.remove("disabled");
this._buttons.Last.classList.remove("disabled");
}
}
// Configure the events
configureEvents(item, itemTemplate) {
// See if this is a spacer
let link = item.querySelector("a").getAttribute("aria-label");
if (link == "...") {
// Do nothing
return;
}
// See if this is the next or previous item and skip it
if (link == "Previous" || link == "Next") {
let isPrevious = link == "Previous";
// Add a click event
item.addEventListener("click", ev => {
var _a;
// Prevent the page from moving to the top
ev.preventDefault();
// Do nothing if it's disabled
if (item.classList.contains("disabled")) {
return;
}
// See if we are rendering the default
if (this._showDefault) {
// Click the previous/next item
(_a = this._items[isPrevious ? this._activePage - 2 : this._activePage]) === null || _a === void 0 ? void 0 : _a.click();
}
else {
// Update the active page
isPrevious ? this._activePage-- : this._activePage++;
// Render the active buttons
this.renderActivePageNumbers(itemTemplate);
// Call the click event
this.props.onClick ? this.props.onClick(this._activePage) : null;
}
});
}
else if (link == "First" || link == "Last") {
let isLast = link == "Last";
// Add a click event
item.addEventListener("click", ev => {
var _a, _b;
// Prevent the page from moving to the top
ev.preventDefault();
// Do nothing if it's disabled
if (item.classList.contains("disabled")) {
return;
}
// See if we are rendering the default
if (this._showDefault) {
// See if this is the last item
if (isLast) {
// Click on the last item
(_a = this._items[this._items.length - 1]) === null || _a === void 0 ? void 0 : _a.click();
}
else {
// Click on the first item
(_b = this._items[0]) === null || _b === void 0 ? void 0 : _b.click();
}
}
else {
// Update the active page
this._activePage = isLast ? this.props.numberOfPages : 1;
// Render the active buttons
this.renderActivePageNumbers(itemTemplate);
// Call the click event
this.props.onClick ? this.props.onClick(this._activePage) : null;
}
});
}
else if (link == "<<" || link == "<" || link == ">" || link == ">>") {
// Add a click event
item.addEventListener("click", ev => {
// Prevent the page from moving to the top
ev.preventDefault();
// Update the active page
switch (link) {
case "<<":
this._activePage -= 10;
break;
case "<":
this._activePage -= 5;
break;
case ">":
this._activePage += 5;
break;
case ">>":
this._activePage += 10;
break;
}
// Validate the page number
if (this._activePage <= 0) {
this._activePage = 1;
}
else if (this._activePage > this.props.numberOfPages) {
this._activePage = this.props.numberOfPages;
}
// Render the active buttons
this.renderActivePageNumbers(itemTemplate);
// Call the click event
this.props.onClick ? this.props.onClick(this._activePage) : null;
});
}
else {
let pageNumber = parseInt(link);
// Add a click event
item.addEventListener("click", ev => {
// Prevent the page from moving to the top
ev.preventDefault();
// See if we are showing the default
if (this._showDefault) {
// Clear the active item
let activeItem = this._items[this._activePage - 1];
if (activeItem) {
// Clear the active class
activeItem.classList.remove("active");
// Remove the active span
let span = activeItem.querySelector("span");
span ? span.parentNode.removeChild(span) : null;
}
// Set the active index
this._activePage = pageNumber;
// Show the active item
this._items[this._activePage - 1].classList.add("active");
// Add the span
let span = document.createElement("span");
span.classList.add("visually-hidden");
span.innerHTML = "(current)";
this._items[this._activePage - 1].appendChild(span);
// Configure the default buttons
this.configureDefaultButtons();
}
else {
// Set the active index
this._activePage = pageNumber;
// Render the active buttons
this.renderActivePageNumbers(itemTemplate);
}
// Call the click event
this.props.onClick ? this.props.onClick(pageNumber) : null;
});
}
}
// Creates the default buttons
createButtons(itemTemplate) {
this._buttons = {
First: this.createItem("First", itemTemplate, true),
Last: this.createItem("Last", itemTemplate, true),
Next: this.createItem("Next", itemTemplate, true),
Previous: this.createItem("Previous", itemTemplate, true),
SkipBack10: this.createItem("<<", itemTemplate, true),
SkipBack5: this.createItem("<", itemTemplate, true),
SkipForward5: this.createItem(">", itemTemplate, true),
SkipForward10: this.createItem(">>", itemTemplate, true)
};
// Set the default classes
this._buttons.First.classList.add("first");
this._buttons.Last.classList.add("last");
this._buttons.Next.classList.add("next");
this._buttons.Previous.classList.add("previous");
// Disable the first and previous buttons by default
this._buttons.First.classList.add("disabled");
this._buttons.Previous.classList.add("disabled");
// Set the icons
this._buttons.SkipBack10.querySelector("a").innerHTML = skipBackward(15, 15).outerHTML;
this._buttons.SkipBack5.querySelector("a").innerHTML = skipStart(15, 15).outerHTML;
this._buttons.SkipForward5.querySelector("a").innerHTML = skipEnd(15, 15).outerHTML;
this._buttons.SkipForward10.querySelector("a").innerHTML = skipForward(15, 15).outerHTML;
}
// Creates an page number item
createItem(text, itemTemplate, isDefault = false) {
// Create the item
let el = document.createElement("div");
el.innerHTML = itemTemplate;
let item = el.firstChild;
isDefault ? null : this._items.push(item);
// Update the link
let link = item.querySelector("a");
if (link) {
link.innerHTML = text;
link.setAttribute("aria-label", link.innerHTML);
}
// Configure the events
this.configureEvents(item, itemTemplate);
// Return the item
return item;
}
// Renders the page numbers
renderPageNumbers(itemTemplate) {
// Clear the items
this._activePage = 1;
this._items = [];
// Determine if there are > 10 pages
let pages = this.props.numberOfPages || 1;
let maxPages = typeof (this.props.maxPages) === "number" ? this.props.maxPages : 10;
this._showDefault = pages < maxPages;
// See if we are rendering the default
if (this._showDefault) {
// Append the first/previous link
this._elList.appendChild(this._buttons.First);
this._elList.appendChild(this._buttons.Previous);
// Loop for the number of pages to create
for (let i = 1; i <= pages; i++) {
// Create a link
let item = this.createItem(i.toString(), itemTemplate);
i == this._activePage ? item.classList.add("active") : null;
this._elList.appendChild(item);
}
// Append the next/last link
this._elList.appendChild(this._buttons.Next);
this._elList.appendChild(this._buttons.Last);
if (pages == 1) {
this._buttons.Next.classList.add("disabled");
this._buttons.Last.classList.add("disabled");
}
}
else {
// Render the active page numbers
this.renderActivePageNumbers(itemTemplate);
}
}
// Renders the active page numbers
renderActivePageNumbers(itemTemplate) {
// Clear the items and list element
this._items = [];
while (this._elList.firstChild) {
this._elList.removeChild(this._elList.firstChild);
}
// Append the first/previous link
this._elList.appendChild(this._buttons.First);
this._elList.appendChild(this._buttons.Previous);
if (this._activePage == 1) {
this._buttons.First.classList.add("disabled");
this._buttons.Previous.classList.add("disabled");
}
else {
this._buttons.First.classList.remove("disabled");
this._buttons.Previous.classList.remove("disabled");
}
// See if we are at the beginning
if (this._activePage < 5) {
// Render the first five
for (let i = 1; i <= 5; i++) {
// Create a link
let item = this.createItem(i.toString(), itemTemplate);
i == this._activePage ? item.classList.add("active") : null;
this._elList.appendChild(item);
}
// Render a spacer
let item = this.createItem("...", itemTemplate, true);
this._elList.appendChild(item);
// Render the last 3
let diff = Math.round((this.props.numberOfPages - 5) / 3);
for (let i = 2; i >= 0; i--) {
// Create a link
let idx = this.props.numberOfPages - i * diff;
let item = this.createItem((idx).toString(), itemTemplate);
this._elList.appendChild(item);
}
}
// Else, see if we are at the end
else if (this._activePage > this.props.numberOfPages - 5) {
// Render the first 3
let diff = Math.round((this.props.numberOfPages - 5) / 3);
for (let i = 0; i <= 2; i++) {
// Create a link
let idx = i == 0 ? 1 : i * diff;
let item = this.createItem((idx).toString(), itemTemplate);
this._elList.appendChild(item);
}
// Render a spacer
let item = this.createItem("...", itemTemplate, true);
this._elList.appendChild(item);
// Render the last five
for (let i = this.props.numberOfPages - 5; i <= this.props.numberOfPages; i++) {
// Create a link
let item = this.createItem(i.toString(), itemTemplate);
i == this._activePage ? item.classList.add("active") : null;
this._elList.appendChild(item);
}
}
// Else, render the skip buttons
else {
// Render the skip buttons
this._elList.appendChild(this._buttons.SkipBack10);
this._elList.appendChild(this._buttons.SkipBack5);
// Render +/- 2 from the active index
for (let i = this._activePage - 2; i <= this._activePage + 2; i++) {
// Create a link
let item = this.createItem(i.toString(), itemTemplate);
i == this._activePage ? item.classList.add("active") : null;
this._elList.appendChild(item);
}
// Render the skip buttons
this._elList.appendChild(this._buttons.SkipForward5);
this._elList.appendChild(this._buttons.SkipForward10);
}
// Append the next/last link
this._elList.appendChild(this._buttons.Next);
this._elList.appendChild(this._buttons.Last);
if (this._activePage == this.props.numberOfPages) {
this._buttons.Next.classList.add("disabled");
this._buttons.Last.classList.add("disabled");
}
else {
this._buttons.Next.classList.remove("disabled");
this._buttons.Last.classList.remove("disabled");
}
}
}
export const Pagination = (props, template, itemTemplate) => { return new _Pagination(props, template, itemTemplate); };