first commit

This commit is contained in:
2024-11-05 12:22:50 +01:00
commit e5682a3912
19641 changed files with 2948548 additions and 0 deletions

View File

@@ -0,0 +1,266 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
const {$} = window;
/**
* Related html template src/PrestaShopBundle/Resources/views/Admin/Common/javascript_pagination.html.twig
*
* Usage
*```
* $paginator new DynamicPaginator(
* '#foo-container',
* FooDataService,
* FooRenderer
* );
* this.eventEmitter.on('fooEventThatShouldTriggerPagination', () => $paginator.paginate(1));
*```
* You can also provide the starting page to initiate it automatically on page load:
*```
* $paginator new DynamicPaginator(
* '#foo-container',
* FooDataService,
* FooRenderer,
* 1
* );
*```
* There is also a possibility to provide custom selectorsMap as 5th argument. See this.setSelectorsMap().
*
* Pagination service must have a method fetch(offset, limit) which returns data.{any resources name} & data.total
* e.g.
* ```
* class FooDataService {
* fetch(offset, limit) {
* return $.get(this.router.generate('admin_products_combinations', {
* productId: this.productId,
* page,
* limit,
* }));
* }
* }
*```
* * In this case the action of route `admin_products_combinations` returns following json:
* ```
* {
* total: 100,
* combinations: [{combinationId: 1, name: foo...}, {combinationId: 2, name: bar...}]
* }
*```
*
* The renderer must have a method render(data) which accepts the data from PaginationService
* and renders it depending on needs
*/
export default class DynamicPaginator {
/**
* @param {String} containerSelector
* @param {Object} paginationService
* @param {Object} renderer
* @param {Number|null} startingPage If provided it will load the provided page data on page load
* @param {Object|null} selectorsMap If provided it will override css selectors used for all the actions.
*/
constructor(containerSelector, paginationService, renderer, startingPage = null, selectorsMap = null) {
this.$paginationContainer = $(containerSelector);
this.paginationService = paginationService;
this.renderer = renderer;
this.setSelectorsMap(selectorsMap);
this.init();
this.currentPage = 1;
if (startingPage !== null) {
this.paginate(startingPage);
}
return {
paginate: (page) => this.paginate(page),
getCurrentPage: () => this.currentPage,
};
}
/**
* Initiates the pagination component
*
* @private
*/
init() {
this.$paginationContainer.on('click', this.selectorsMap.pageLink, (e) => {
this.paginate(Number($(e.currentTarget).data('page')));
});
this.$paginationContainer.find(this.selectorsMap.jumpToPageInput).keypress((e) => {
if (e.which === 13) {
e.preventDefault();
const page = this.getValidPageNumber(Number(e.currentTarget.value));
this.paginate(page);
}
});
this.$paginationContainer.on('change', this.selectorsMap.limitSelect, () => {
this.paginate(1);
});
}
/**
* @param {Number} page
*/
async paginate(page) {
this.currentPage = page;
this.renderer.toggleLoading(true);
const limit = this.getLimit();
const data = await this.paginationService.fetch(this.calculateOffset(page, limit), limit);
$(this.selectorsMap.jumpToPageInput).val(page);
this.countPages(data.total);
this.refreshButtonsData(page);
this.refreshInfoLabel(page, data.total);
this.toggleTargetAvailability(this.selectorsMap.firstPageItem, page > 1);
this.toggleTargetAvailability(this.selectorsMap.previousPageItem, page > 1);
this.toggleTargetAvailability(this.selectorsMap.nextPageItem, page < this.pagesCount);
this.toggleTargetAvailability(this.selectorsMap.lastPageItem, page < this.pagesCount);
this.renderer.render(data);
this.renderer.toggleLoading(false);
window.prestaShopUiKit.initToolTips();
}
/**
* @param page
* @param limit
*
* @returns {Number}
*/
calculateOffset(page, limit) {
return (page - 1) * limit;
}
/**
* @param {Number} page
*
* @private
*/
refreshButtonsData(page) {
this.$paginationContainer.find(this.selectorsMap.nextPageBtn).data('page', page + 1);
this.$paginationContainer.find(this.selectorsMap.previousPageBtn).data('page', page - 1);
this.$paginationContainer.find(this.selectorsMap.lastPageBtn).data('page', this.pagesCount);
}
/**
* @param {Number} page
* @param {Number} total
*/
refreshInfoLabel(page, total) {
const infoLabel = this.$paginationContainer.find(this.selectorsMap.paginationInfoLabel);
const limit = this.getLimit();
const from = page === 1 ? 1 : Math.round((page - 1) * limit);
const to = page === this.pagesCount ? total : Math.round(page * limit);
const modifiedInfoText = infoLabel
.data('pagination-info')
.replace(/%from%/g, from)
.replace(/%to%/g, to)
.replace(/%total%/g, total)
.replace(/%current_page%/g, page)
.replace(/%page_count%/g, this.pagesCount);
infoLabel.text(modifiedInfoText);
}
/**
* @param {String} targetSelector
* @param {Boolean} enable
*
* @private
*/
toggleTargetAvailability(targetSelector, enable) {
const target = this.$paginationContainer.find(targetSelector);
if (enable) {
target.removeClass('disabled');
} else {
target.addClass('disabled');
}
}
/**
* @param {Number} total
*
* @private
*/
countPages(total) {
this.pagesCount = Math.ceil(total / this.getLimit());
const lastPageItem = this.$paginationContainer.find(this.selectorsMap.lastPageBtn);
lastPageItem.data('page', this.pagesCount);
lastPageItem.text(this.pagesCount);
}
/**
* @returns {Number}
*
* @private
*/
getLimit() {
return this.$paginationContainer.find(this.selectorsMap.limitSelect).val();
}
/**
*
* @param page
*
* @returns {Number}
*/
getValidPageNumber(page) {
if (page > this.pagesCount) {
return this.pagesCount;
}
if (page < 1) {
return 1;
}
return page;
}
/**
* @param {Object} selectorsMap
*/
setSelectorsMap(selectorsMap) {
if (selectorsMap) {
this.selectorsMap = selectorsMap;
return;
}
this.selectorsMap = {
jumpToPageInput: 'input[name="paginator-jump-page"]',
firstPageBtn: 'button.page-link.first',
firstPageItem: 'li.page-item.first',
nextPageBtn: 'button.page-link.next',
nextPageItem: 'li.page-item.next',
previousPageBtn: 'button.page-link.previous',
previousPageItem: 'li.page-item.previous',
lastPageItem: 'li.page-item.last',
lastPageBtn: 'button.page-link.last',
pageLink: 'button.page-link',
limitSelect: '#paginator-limit',
paginationInfoLabel: '#pagination-info',
};
}
}