UNPKG

showcar-ui

Version:

Showcar-ui is the pattern library that is used to build the frontend of AutoScout24. It provides CSS classes, custom elements and components.

290 lines (239 loc) 8.12 kB
class Pager { /** * @param {HTMLElement|String} root can be a selector * @param {Number} itemsPerPage * @param {Number} activePage * @param {Number} totalItems * @param {String} urlTemplate * @param {Boolean} unlimited */ constructor (root, itemsPerPage, activePage, totalItems, urlTemplate, unlimited) { this.ETC = '...'; try { this.rootElement = $(root); } catch (error) { window.onerror('showcar-ui-test. $ is not defined', 'showcar-ui'); } this.itemsPerPage = parseInt(itemsPerPage); this.activePage = parseInt(activePage); this.totalCount = parseInt(totalItems); this.urlTemplate = urlTemplate; this.unlimited = unlimited; this.maxPage = this.calculatePageCount(); this.tileWidth = 48; this.prototypeLi = $('<li>'); this.prototypeA = $('<a>'); this.prototypeIcon = $('<as24-icon>'); $(window).on('resize', $.proxy(this.render, this)); this.render(); } /** * @returns {Number} */ get maxPage() { return this._maxPage; } /** * @param {Number} pages */ set maxPage(pages) { this._maxPage = pages; } /** * @returns {Object|Zepto} */ get previousButton() { let li = this.prototypeLi.clone(), a = this.prototypeA.clone(), icon = this.prototypeIcon.clone(); const previousText = $(this.rootElement).data('previous-text') || 'Previous'; const isPreviousPageAvailable = this.totalCount > 0 && (this.activePage > 1 || this.activePage > this.maxPage); li.addClass('previous-page'); if (isPreviousPageAvailable) { const pageNumber = this.activePage > this.maxPage ? this.maxPage : this.activePage-1; a.attr('href', this.getPageUrl(pageNumber)); } else { a.addClass('disabled'); } a.text(' ' + previousText); icon.attr('type', 'arrow'); return li.append(a.prepend(icon)); } /** * @returns {Object|Zepto} */ get nextButton() { let li = this.prototypeLi.clone(), a = this.prototypeA.clone(), icon = this.prototypeIcon.clone(); const nextText = $(this.rootElement).data('next-text') || 'Next'; const isNextPageAvailable = this.activePage < this.maxPage; li.addClass('next-page'); if (isNextPageAvailable) { a.attr('href', this.getPageUrl(this.activePage + 1)); } else { a.addClass('disabled'); } a.text(nextText + ' '); icon.attr('type', 'arrow'); return li.append(a.append(icon)); } get infoPage() { return this.prototypeLi.clone().addClass('info-page').append( this.prototypeA.clone().addClass('disabled').attr('href', 'javascript:void(0)').text( this.activePage + ' / ' + this.maxPage ) ); } /** * @param {Number} pageNumber * @returns {String} */ getPageUrl(pageNumber) { let template = this.urlTemplate.replace('{page}', pageNumber.toString()); return template.replace('{size}', this.itemsPerPage.toString()); } /** * Create a single page element * * @param {Number} pageNumber * @returns {Object|Zepto} */ createPage(pageNumber) { let tile = this.prototypeLi.clone().data('page', pageNumber), a = this.prototypeA.clone().attr('href', this.getPageUrl(pageNumber)); if (this.ETC === pageNumber) { tile.data('page', 'etc'); a.addClass('disabled'); a.removeAttr('href'); a.attr('rel','nofollow'); } if (this.activePage === pageNumber) { a.addClass('active'); a.removeAttr('href'); a.attr('rel','nofollow'); } a.text(pageNumber); return tile.append(a); } /** * Returns the maximum possible amount ot tiles between <PREV> and <NEXT> * * @returns {int} */ getMaximumPossibleTiles() { const rootWidth = this.rootElement.width(); // We assume that this is the minWidth for both buttons const prevNextWidth = 200; return Math.floor((rootWidth - prevNextWidth) / this.tileWidth); } /** * Returns an array with all page numbers in the correct order * * Example: * activePage = 17 * maxPage = 20 * Returns [1, "...", 14, 15, 16, 17, 18, 19, 20] * * @param {Number} activePage * @returns {Array} */ getPageTiles(activePage) { let startTile = activePage > this.maxPage ? this.maxPage : activePage, leftNumber = startTile - 1, rightNumber = startTile + 1, maxPossibleTiles = this.getMaximumPossibleTiles(), usefulTiles = 0, countEtc = 0; // we always want to have an odd number of tiles to show if (maxPossibleTiles % 2 === 0 && this.maxPage > maxPossibleTiles) { maxPossibleTiles--; } let tiles = [startTile]; // because we have our activePage, we have one possible tile less maxPossibleTiles--; while ((leftNumber > 0 || rightNumber <= this.maxPage) && maxPossibleTiles > 0) { if (leftNumber > 0) { tiles.unshift(leftNumber); usefulTiles++; maxPossibleTiles--; if (0 === maxPossibleTiles) { break; } } if (rightNumber <= this.maxPage) { tiles.push(rightNumber); usefulTiles++; maxPossibleTiles--; if (0 === maxPossibleTiles) { break; } } leftNumber--; rightNumber++; } // special case: we have enough space to show 'em all if (tiles.length === this.maxPage) { return tiles; } // special case: If we have less or equal to 7 pages/tiles in total, we show all or infopage if (this.maxPage <= 7 && tiles.length < this.maxPage) { return []; } // show dots on the left ( < 1 ... 7 8 9) if (1 !== tiles[0]) { tiles[0] = 1; tiles[1] = this.ETC; countEtc++; usefulTiles -= 1; } // show dots on the right ( 10 11 ... 20 >) if (this.maxPage !== tiles[tiles.length - 1]) { tiles[tiles.length - 1] = this.maxPage; tiles[tiles.length - 2] = this.ETC; countEtc++; usefulTiles -= 1; } // special case: show info page if less than 3 useful tiles if (countEtc >= 1 && usefulTiles <= 3) { return []; } // show only the info page tile if (usefulTiles <= 2 || this.maxPage <= 3) { return []; } return tiles; } /** * Render the pagination */ render() { this.rootElement.children().remove(); let pagination = this.getPageTiles(this.activePage), collection = $(); this.rootElement.append(this.previousButton); if (0 === pagination.length) { this.rootElement.append(this.infoPage); } else { pagination.forEach((page) => { collection = collection.add(this.createPage(page)); }); this.rootElement.append(collection); } this.rootElement.append(this.nextButton); } /** * @returns {Number} */ calculatePageCount() { let numberOfPages = Math.ceil(this.totalCount / this.itemsPerPage); if (this.unlimited) { return numberOfPages; } if (numberOfPages >= 20) { return 20; } return numberOfPages; } } export default Pager;