From f3d4b0245c8084768f3a8fc52fc0a6a3fb4d9e2f Mon Sep 17 00:00:00 2001
From: Kevin Ditscheid <kevin.ditscheid@sgalinski.de>
Date: Thu, 13 Oct 2022 23:49:47 +0200
Subject: [PATCH] [TASK] Rework pagination and make it easier to use

---
 Classes/Controller/RouteController.php        |  75 +++----
 Classes/Pagination/Pagination.php             | 199 ++++++++++++++++++
 Classes/Paginator/QueryResultPaginator.php    |  70 ------
 Classes/Paginator/QueryResultRawPaginator.php |  97 ---------
 .../Private/Backend/Templates/Route/List.html |   8 +-
 .../Private/Backend/Templates/Route/Log.html  |   6 +-
 Resources/Private/Partials/Pagination.html    |  58 ++---
 7 files changed, 266 insertions(+), 247 deletions(-)
 create mode 100644 Classes/Pagination/Pagination.php
 delete mode 100644 Classes/Paginator/QueryResultPaginator.php
 delete mode 100644 Classes/Paginator/QueryResultRawPaginator.php

diff --git a/Classes/Controller/RouteController.php b/Classes/Controller/RouteController.php
index 5b50f09..9b50e13 100644
--- a/Classes/Controller/RouteController.php
+++ b/Classes/Controller/RouteController.php
@@ -1,7 +1,5 @@
 <?php
 
-namespace SGalinski\SgRoutes\Controller;
-
 /***************************************************************
  *  Copyright notice
  *
@@ -26,18 +24,24 @@ namespace SGalinski\SgRoutes\Controller;
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
 
+namespace SGalinski\SgRoutes\Controller;
+
 use InvalidArgumentException;
+use Psr\Http\Message\ResponseInterface;
 use SGalinski\SgRoutes\Domain\Model\Category;
 use SGalinski\SgRoutes\Domain\Model\Route;
 use SGalinski\SgRoutes\Domain\Repository\CategoryRepository;
 use SGalinski\SgRoutes\Domain\Repository\LogRepository;
 use SGalinski\SgRoutes\Domain\Repository\RoutehitRepository;
 use SGalinski\SgRoutes\Domain\Repository\RouteRepository;
+use SGalinski\SgRoutes\Pagination\Pagination;
 use SGalinski\SgRoutes\Service\LicenceCheckService;
 use SGalinski\SgRoutes\Service\RoutingService;
 use TYPO3\CMS\Backend\Clipboard\Clipboard;
 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
+use TYPO3\CMS\Backend\Template\Components\DocHeaderComponent;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
+use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\ConnectionPool;
@@ -49,6 +53,7 @@ use TYPO3\CMS\Core\Messaging\AbstractMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Pagination\SimplePagination;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Http\ForwardResponse;
 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
 use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
@@ -90,12 +95,12 @@ class RouteController extends ActionController {
 
 	/**
 	 * DocHeaderComponent
-	 * @var \TYPO3\CMS\Backend\Template\Components\DocHeaderComponent
+	 * @var DocHeaderComponent
 	 */
 	private $docHeaderComponent;
 
 	/**
-	 * @var \SGalinski\SgRoutes\Domain\Repository\RouteRepository
+	 * @var RouteRepository
 	 */
 	private $routeRepository;
 
@@ -114,7 +119,7 @@ class RouteController extends ActionController {
 	}
 
 	/**
-	 * @var \SGalinski\SgRoutes\Domain\Repository\CategoryRepository
+	 * @var CategoryRepository
 	 */
 	private $categoryRepository;
 
@@ -128,7 +133,7 @@ class RouteController extends ActionController {
 	}
 
 	/**
-	 * @var \SGalinski\SgRoutes\Domain\Repository\LogRepository
+	 * @var LogRepository
 	 */
 	private $logRepository;
 
@@ -248,11 +253,12 @@ class RouteController extends ActionController {
 	 * Shows all the data for the selected page browser page in the backend.
 	 *
 	 * @param array $filters
+	 * @param int $currentPage
 	 * @throws InvalidQueryException
 	 * @throws UnexpectedValueException
 	 * @throws InvalidArgumentException
 	 */
-	public function listAction($filters = NULL): ?\Psr\Http\Message\ResponseInterface {
+	public function listAction($filters = NULL, int $currentPage = 1): ?ResponseInterface {
 		if ($this->rootPageUid) {
 			/** @var BackendUserAuthentication $backendUser */
 			$backendUser = $GLOBALS['BE_USER'];
@@ -261,16 +267,10 @@ class RouteController extends ActionController {
 			} else {
 				$backendUser->pushModuleData('tools_beuser/index.php/web_SgRoutesRoute_filters', $filters);
 			}
-			// Update Page in case we got a currentPage from Pagination
-			if ($this->request->hasArgument('currentPage')) {
-				$currentPage = (int) $this->request->getArgument('currentPage');
-			} else {
-				$currentPage = 1;
-			}
 
 			$routes = $this->routeRepository->findRoutes($this->rootPageUid, $filters);
-			$paginator = new \SGalinski\SgRoutes\Paginator\QueryResultPaginator($routes, $currentPage, 10);
-			$simplePagination = new SimplePagination($paginator);
+			$pagination = GeneralUtility::makeInstance(Pagination::class, $routes, $currentPage, 10);
+			$this->view->assign('pagination', $pagination);
 
 			$prevUid = 0;
 			$prevPrevUid = 0;
@@ -307,10 +307,6 @@ class RouteController extends ActionController {
 				$categoryOptions[$category->getUid()] = $category->getTitle();
 			}
 
-			$this->view->assign('paginator', $paginator);
-			$this->view->assign('pagination', $simplePagination);
-			$this->view->assign('currentPage', $currentPage);
-			$this->view->assign('routes', $routes);
 			$this->view->assign('sortingData', $sortingData);
 			$this->view->assign('categoryOptions', $categoryOptions);
 			$this->view->assign('filters', $filters);
@@ -363,12 +359,12 @@ class RouteController extends ActionController {
 	 * Delete all Routes
 	 *
 	 * @param array $filters
-	 * @return \Psr\Http\Message\ResponseInterface|null
+	 * @return ResponseInterface|null
 	 * @throws IllegalObjectTypeException
 	 * @throws InvalidQueryException
 	 * @throws StopActionException
 	 */
-	public function deleteAllAction(array $filters = []): ?\Psr\Http\Message\ResponseInterface {
+	public function deleteAllAction(array $filters = []): ?ResponseInterface {
 		/** @var ObjectStorage $routes */
 		$routes = $this->routeRepository->findRoutes($this->rootPageUid, $filters);
 		if ($routes && $routesCount = $routes->count()) {
@@ -389,10 +385,10 @@ class RouteController extends ActionController {
 	 * Show htaccess Strings
 	 *
 	 * @param array $filters
-	 * @return \Psr\Http\Message\ResponseInterface|null
+	 * @return ResponseInterface|null
 	 * @throws InvalidQueryException
 	 */
-	public function htaccessAction(array $filters = []): ?\Psr\Http\Message\ResponseInterface {
+	public function htaccessAction(array $filters = []): ?ResponseInterface {
 		/** @var array $routes */
 		$routes = $this->routeRepository->findRoutes($this->rootPageUid, $filters, TRUE);
 		$routingService = GeneralUtility::makeInstance(RoutingService::class);
@@ -406,26 +402,15 @@ class RouteController extends ActionController {
 	/**
 	 * Shows all log data of the executed redirects.
 	 *
+	 * @param int $currentPage
 	 * @throws UnexpectedValueException
 	 * @throws InvalidArgumentException
 	 */
-	public function logAction(): ?\Psr\Http\Message\ResponseInterface {
+	public function logAction(int $currentPage = 1): ?ResponseInterface {
 		if ($this->rootPageUid) {
-
-			// Update Page in case we got a currentPage from Pagination
-			if ($this->request->hasArgument('currentPage')) {
-				$currentPage = (int) $this->request->getArgument('currentPage');
-			} else {
-				$currentPage = 1;
-			}
-
-			[$logs, $queryResult] = $this->logRepository->findAllByPid($this->rootPageUid);
-			$paginator = new \SGalinski\SgRoutes\Paginator\QueryResultRawPaginator($queryResult, $currentPage, 10);
-			$simplePagination = new SimplePagination($paginator);
-
-			$this->view->assign('paginator', $paginator);
-			$this->view->assign('pagination', $simplePagination);
-			$this->view->assign('logs', $logs);
+			$queryResult = $this->logRepository->findAllByPid($this->rootPageUid);
+			$pagination = GeneralUtility::makeInstance(Pagination::class, $queryResult, $currentPage, 10);
+			$this->view->assign('pagination', $pagination);
 		}
 
 		$this->view->assign('V11', TRUE);
@@ -552,10 +537,10 @@ class RouteController extends ActionController {
 	 * @throws UnknownObjectException
 	 * @throws StopActionException
 	 */
-	public function resetHitsAction(int $routeUid): ?\Psr\Http\Message\ResponseInterface {
+	public function resetHitsAction(int $routeUid): ?ResponseInterface {
 		$this->routeRepository->resetHitCountForRoute($routeUid);
 
-		return new \TYPO3\CMS\Extbase\Http\ForwardResponse(
+		return new ForwardResponse(
 			'list',
 			'Route',
 			'SgRoutes',
@@ -682,7 +667,7 @@ class RouteController extends ActionController {
 	 *
 	 * @throws StopActionException
 	 */
-	public function activateDemoModeAction(): ?\Psr\Http\Message\ResponseInterface {
+	public function activateDemoModeAction(): ?ResponseInterface {
 		if (LicenceCheckService::isInDemoMode() || !LicenceCheckService::isDemoModeAcceptable()) {
 			return $this->redirect('list');
 		}
@@ -695,9 +680,9 @@ class RouteController extends ActionController {
 	/**
 	 * Use the ModuleTemplateResponse to create a response object for the backend
 	 *
-	 * @return  \Psr\Http\Message\ResponseInterface
+	 * @return  ResponseInterface
 	 */
-	protected function createBackendResponse(): \Psr\Http\Message\ResponseInterface {
+	protected function createBackendResponse(): ResponseInterface {
 		return $this->htmlResponse($this->view->render());
 	}
 
@@ -708,7 +693,7 @@ class RouteController extends ActionController {
 	protected function getModuleTemplate() {
 		if ($this->moduleTemplate === NULL) {
 			$moduleTemplateFactory = GeneralUtility::makeInstance(
-				\TYPO3\CMS\Backend\Template\ModuleTemplateFactory::class
+				ModuleTemplateFactory::class
 			);
 			$this->moduleTemplate = $moduleTemplateFactory->create($this->request);
 		}
diff --git a/Classes/Pagination/Pagination.php b/Classes/Pagination/Pagination.php
new file mode 100644
index 0000000..c85be83
--- /dev/null
+++ b/Classes/Pagination/Pagination.php
@@ -0,0 +1,199 @@
+<?php
+/*
+ * Copyright notice
+ *
+ * (c) sgalinski Internet Services (https://www.sgalinski.de)
+ * All rights reserved
+ *
+ * This script is part of the TYPO3 project. The TYPO3 project is
+ * free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The GNU General Public License can be found at
+ * http://www.gnu.org/copyleft/gpl.html.
+ *
+ * This script is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * This copyright notice MUST APPEAR in all copies of the script!
+ */
+
+namespace SGalinski\SgRoutes\Pagination;
+
+use TYPO3\CMS\Extbase\Persistence\Generic\QueryResult;
+
+/**
+ * This class is a representation of the pagination
+ * It contains functionality for handling the
+ */
+class Pagination {
+	/**
+	 * @var QueryResult
+	 */
+	private $queryResult;
+	/**
+	 * @var int
+	 */
+	private $currentPage;
+	/**
+	 * @var int
+	 */
+	private $limit;
+	/**
+	 * @var int
+	 */
+	private $nextPage;
+	/**
+	 * @var int
+	 */
+	private $previousPage;
+	/**
+	 * @var int
+	 */
+	private $lastPage;
+	/**
+	 * @var int
+	 */
+	private $firstPage;
+	/**
+	 * @var int
+	 */
+	private $startItem;
+	/**
+	 * @var int
+	 */
+	private $endItem;
+	/**
+	 * @var int
+	 */
+	private $totalItems;
+	/**
+	 * @var array
+	 */
+	private $items;
+
+	public function __construct(QueryResult $queryResult, int $currentPage, int $limit) {
+		$this->queryResult = $queryResult;
+		$this->currentPage = $currentPage;
+		$this->limit = $limit;
+		$this->initialize();
+	}
+
+	public function initialize() {
+		$this->firstPage = 1;
+		$this->totalItems = $this->fetchTotalItemCount();
+		$this->lastPage = ceil($this->totalItems / $this->limit);
+		// correct current page if out of bounds
+		$this->currentPage = $this->currentPage < 1 ? 1 : min($this->currentPage, $this->lastPage);
+		$this->nextPage = $this->currentPage >= $this->lastPage ? $this->lastPage : $this->currentPage + 1;
+		$this->previousPage = $this->currentPage <= 1 ? 1 : $this->currentPage - 1;
+		$this->startItem = ($this->currentPage - 1) * $this->limit + 1;
+		// correct startItem if out of bounds
+		$this->startItem = max($this->startItem, 1);
+		$this->endItem = ($this->currentPage - 1) * $this->limit + $this->limit;
+		// correct endItem if out of bounds
+		$this->endItem = min($this->endItem, $this->totalItems);
+		$this->items = $this->fetchItems();
+	}
+
+	/**
+	 * Reconfigure the query builder to fetch the total count of items
+	 *
+	 * @return int
+	 * @throws \Doctrine\DBAL\DBALException
+	 * @throws \Doctrine\DBAL\Driver\Exception
+	 */
+	private function fetchTotalItemCount(): int {
+		$query = clone $this->queryResult->getQuery();
+		$query->setOffset(0)->setLimit(9999999);
+		$count = $query->execute()->count();
+		return $count ?? 0;
+	}
+
+	/**
+	 * Reconfigure the queryResult to fetch the items for the configured currentPage
+	 *
+	 * @return array
+	 * @throws \Doctrine\DBAL\DBALException
+	 * @throws \Doctrine\DBAL\Driver\Exception
+	 */
+	private function fetchItems(): array {
+		$query = clone $this->queryResult->getQuery();
+		$query->setOffset($this->startItem - 1)->setLimit($this->limit);
+		return $query->execute()->toArray();
+	}
+
+	/**
+	 * @return int
+	 */
+	public function getCurrentPage(): int {
+		return $this->currentPage;
+	}
+
+	/**
+	 * @return int
+	 */
+	public function getLimit(): int {
+		return $this->limit;
+	}
+
+	/**
+	 * @return mixed
+	 */
+	public function getNextPage() {
+		return $this->nextPage;
+	}
+
+	/**
+	 * @return mixed
+	 */
+	public function getPreviousPage() {
+		return $this->previousPage;
+	}
+
+	/**
+	 * @return mixed
+	 */
+	public function getLastPage() {
+		return $this->lastPage;
+	}
+
+	/**
+	 * @return mixed
+	 */
+	public function getFirstPage() {
+		return $this->firstPage;
+	}
+
+	/**
+	 * @return mixed
+	 */
+	public function getStartItem() {
+		return $this->startItem;
+	}
+
+	/**
+	 * @return mixed
+	 */
+	public function getEndItem() {
+		return $this->endItem;
+	}
+
+	/**
+	 * @return mixed
+	 */
+	public function getTotalItems() {
+		return $this->totalItems;
+	}
+
+	/**
+	 * @return array
+	 */
+	public function getItems(): array {
+		return $this->items;
+	}
+}
diff --git a/Classes/Paginator/QueryResultPaginator.php b/Classes/Paginator/QueryResultPaginator.php
deleted file mode 100644
index 1eefbea..0000000
--- a/Classes/Paginator/QueryResultPaginator.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-namespace SGalinski\SgRoutes\Paginator;
-
-use TYPO3\CMS\Core\Pagination\AbstractPaginator;
-use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
-
-final class QueryResultPaginator extends AbstractPaginator {
-	/**
-	 * @var QueryResultInterface
-	 */
-	private $queryResult;
-
-	/**
-	 * @var QueryResultInterface
-	 */
-	private $paginatedQueryResult;
-
-	public function __construct(
-		QueryResultInterface $queryResult,
-		int $currentPageNumber = 1,
-		int $itemsPerPage = 10
-	) {
-		$this->queryResult = $queryResult;
-		$this->setCurrentPageNumber($currentPageNumber);
-		$this->setItemsPerPage($itemsPerPage);
-
-		$this->updateInternalState();
-	}
-
-	/**
-	 * @return iterable|QueryResultInterface
-	 */
-	public function getPaginatedItems(): iterable {
-		return $this->paginatedQueryResult;
-	}
-
-	protected function updatePaginatedItems(int $limit, int $offset): void {
-		$this->paginatedQueryResult = $this->queryResult
-			->getQuery()
-			->setLimit($limit)
-			->setOffset($offset)
-			->execute();
-	}
-
-	protected function getTotalAmountOfItems(): int {
-		/** @var QueryResultInterface $countQueryResult */
-		$countQueryResult = clone $this->queryResult;
-		return $countQueryResult->count();
-	}
-
-	protected function getAmountOfItemsOnCurrentPage(): int {
-		return count($this->paginatedQueryResult);
-	}
-}
diff --git a/Classes/Paginator/QueryResultRawPaginator.php b/Classes/Paginator/QueryResultRawPaginator.php
deleted file mode 100644
index 9f15101..0000000
--- a/Classes/Paginator/QueryResultRawPaginator.php
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-namespace SGalinski\SgRoutes\Paginator;
-
-use TYPO3\CMS\Core\Pagination\AbstractPaginator;
-use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
-
-/**
- * Copied QueryResult Paginator for us to get a raw result returned,
- * just like the old Controller used to use, also alot of BE ViewHelpers want an array
- */
-final class QueryResultRawPaginator extends AbstractPaginator {
-	/**
-	 * @var QueryResultInterface
-	 */
-	private $queryResult;
-
-	/**
-	 * @var array|QueryResultInterface
-	 */
-	private $paginatedQueryResult;
-
-	/**
-	 * @var int
-	 */
-	protected $totalItems = 0;
-
-	public function __construct(
-		QueryResultInterface $queryResult,
-		int $currentPageNumber = 1,
-		int $itemsPerPage = 10
-	) {
-		$this->queryResult = $queryResult;
-		$this->setCurrentPageNumber($currentPageNumber);
-		$this->setItemsPerPage($itemsPerPage);
-
-		$this->updateInternalState();
-	}
-
-	/**
-	 * @return iterable|QueryResultInterface
-	 */
-	public function getPaginatedItems(): iterable {
-		return $this->paginatedQueryResult;
-	}
-
-	protected function updatePaginatedItems(int $limit, int $offset): void {
-		$this->paginatedQueryResult = $this->queryResult
-			->getQuery()
-			->setLimit($limit)
-			->setOffset($offset)
-			->execute(TRUE);
-	}
-
-	protected function getTotalAmountOfItems(): int {
-		$totalItems = $this->queryResult
-			->getQuery()
-			->setLimit(99999)
-			->setOffset(0)
-			->count();
-		$this->setTotalItems($totalItems);
-		return $totalItems;
-	}
-
-	protected function getAmountOfItemsOnCurrentPage(): int {
-		return count($this->paginatedQueryResult);
-	}
-
-	/**
-	 * @return int
-	 */
-	public function getTotalItems(): int {
-		return $this->totalItems;
-	}
-
-	/**
-	 * @param int $totalItems
-	 */
-	public function setTotalItems(int $totalItems): void {
-		$this->totalItems = $totalItems;
-	}
-}
diff --git a/Resources/Private/Backend/Templates/Route/List.html b/Resources/Private/Backend/Templates/Route/List.html
index a345340..07193d0 100644
--- a/Resources/Private/Backend/Templates/Route/List.html
+++ b/Resources/Private/Backend/Templates/Route/List.html
@@ -163,7 +163,7 @@
 					<core:icon identifier="actions-document-new"/>
 					<f:translate key="backend.button_create_category"/>
 				</be:link.newRecord>
-				<f:if condition="{routes}">
+				<f:if condition="{pagination.totalItems}">
 					<f:if condition="{showLicenseBanner}">
 						<f:else>
 							<f:link.action class="btn btn-default" action="htaccess" arguments="{filters : filters}">
@@ -185,7 +185,7 @@
 				</f:if>
 			</div>
 
-			<f:if condition="{routes}">
+			<f:if condition="{pagination.totalItems}">
 				<f:then>
 					<p>
 						<f:translate key="backend.message.sorting"/>
@@ -196,12 +196,12 @@
 								<thead>
 									<tr class="bg-light">
 										<td colspan="3">
-											<f:render partial="Pagination" arguments="{pagination: pagination, paginator: queuePaginator, actionName: 'list', currentPage: currentPage}"/>
+											<f:render partial="Pagination" arguments="{pagination: pagination, actionName: 'list'}"/>
 										</td>
 									</tr>
 								</thead>
 								<tbody>
-									<f:for each="{paginator.paginatedItems}" as="route">
+									<f:for each="{pagination.items}" as="route">
 										<tr data-uid="{route.uid}">
 											<td nowrap="nowrap" class="col-icon">
 												<f:format.raw>
diff --git a/Resources/Private/Backend/Templates/Route/Log.html b/Resources/Private/Backend/Templates/Route/Log.html
index 7f1f31c..399254f 100644
--- a/Resources/Private/Backend/Templates/Route/Log.html
+++ b/Resources/Private/Backend/Templates/Route/Log.html
@@ -23,14 +23,14 @@
 				</f:link.action>
 			</div>
 			<br />
-			<f:if condition="{logs}">
+			<f:if condition="{pagination.totalItems}">
 				<f:then>
 					<div class="panel panel-default recordlist">
 						<div class="table-fit">
 							<table data-table="tx_sgroutes_domain_model_log" class="table table-striped table-hover">
-								<f:render partial="Pagination" arguments="{pagination: pagination, paginator: queuePaginator, actionName: 'log', currentPage: currentPage}"/>
+								<f:render partial="Pagination" arguments="{pagination: pagination, actionName: 'log'}"/>
 								<tbody>
-									<f:for each="{paginator.paginatedItems}" as="log">
+									<f:for each="{paginator.items}" as="log">
 										{sg:backend.editOnClick(table: 'tx_sgroutes_domain_model_log', uid: log.uid) -> sg:set(name: 'editOnClick')}
 										<tr data-uid="{log.uid}">
 											<td style="white-space: normal;">
diff --git a/Resources/Private/Partials/Pagination.html b/Resources/Private/Partials/Pagination.html
index 242dff9..5c79ecd 100644
--- a/Resources/Private/Partials/Pagination.html
+++ b/Resources/Private/Partials/Pagination.html
@@ -3,15 +3,19 @@
 
 <nav class="pagination-wrap">
 	<ul class="pagination pagination-block">
-		<f:if condition="{pagination.previousPageNumber} && {pagination.previousPageNumber} >= {pagination.firstPageNumber}">
+		<f:if condition="{pagination.previousPage} && {pagination.previousPage} >= {pagination.firstPage}">
 			<f:then>
 				<li class="page-item">
-					<a href="{f:uri.action(action:actionName, arguments:{currentPage: 1})}" title="{f:translate(key:'widget.pagination.first')}" class="page-link">
+					<a href="{f:uri.action(action: actionName, arguments: {currentPage: 1})}"
+					   title="{f:translate(key:'widget.pagination.first')}"
+					   class="page-link">
 						<core:icon identifier="actions-view-paging-first" />
 					</a>
 				</li>
 				<li class="page-item">
-					<a href="{f:uri.action(action:actionName, arguments:{currentPage: pagination.previousPageNumber})}" title="{f:translate(key:'widget.pagination.previous')}" class="page-link">
+					<a href="{f:uri.action(action: actionName, arguments: {currentPage: pagination.previousPage})}"
+					   title="{f:translate(key:'widget.pagination.previous')}"
+					   class="page-link">
 						<core:icon identifier="actions-view-paging-previous" />
 					</a>
 				</li>
@@ -31,52 +35,48 @@
 		</f:if>
 		<li class="page-item">
 			<span class="page-link">
-				<f:if condition="{recordsLabel}">
-					<f:then>
-						{recordsLabel}
-					</f:then>
-					<f:else>
-						<f:translate key="widget.pagination.records" />
-					</f:else>
-				</f:if>
-				{pagination.startRecordNumber} - {pagination.endRecordNumber} / {paginator.totalItems}
+				<f:translate key="widget.pagination.records" />
+				{pagination.startItem} - {pagination.endItem} / {pagination.totalItems}
 			</span>
 		</li>
 		<li class="page-item">
 			<span class="page-link">
 				<f:translate key="widget.pagination.page" />
-				<form id="paginator-form-{position}" onsubmit="goToPage{position}(this); return false;" style="display:inline;">
+				<form id="paginator-form" onsubmit="goToPage(this); return false;" style="display:inline;">
 				<script type="text/javascript">
-					function goToPage{position}(formObject) {
+					function goToPage(formObject) {
 						var page = formObject.elements['paginator-target-page'].value;
-						var url = '{f:uri.action(action:actionName, arguments:{currentPage: 987654321}) -> f:format.raw()}';
+						var url = '{f:uri.action(action: actionName, arguments: {currentPage: 987654321}) -> f:format.raw()}';
 
-						if (page > {pagination.lastPageNumber}) {
-							page = {pagination.lastPageNumber};
-						}
-						else
-						if (page < 1) {
-							page = 1;
-						}
 						url = url.replace('987654321', page);
 						self.location.href = url;
 					}
 				</script>
-				<f:form.textfield id="paginator-{position}" name="paginator-target-page" additionalAttributes="{min: '1'}" class="form-control input-sm paginator-input" size="5" value="{currentPage}" type="number" />
+				<f:form.textfield id="paginator"
+								  name="paginator-target-page"
+								  additionalAttributes="{min: '1'}"
+								  class="form-control input-sm paginator-input"
+								  size="5"
+								  value="{pagination.currentPage}"
+								  type="number" />
 				</form>
 
-				/ {pagination.lastPageNumber}
+				/ {pagination.lastPage}
 			</span>
 		</li>
-		<f:if condition="{pagination.nextPageNumber} && {pagination.nextPageNumber} <= {pagination.lastPageNumber}">
+		<f:if condition="{pagination.nextPage} && {pagination.nextPage} <= {pagination.lastPage}">
 			<f:then>
 				<li class="page-item">
-					<a class="page-link" href="{f:uri.action(action:actionName, arguments:{currentPage: pagination.nextPageNumber})}" title="{f:translate(key:'widget.pagination.next')}">
+					<a class="page-link"
+					   href="{f:uri.action(action: actionName, arguments: {currentPage: pagination.nextPage})}"
+					   title="{f:translate(key:'widget.pagination.next')}">
 						<core:icon identifier="actions-view-paging-next" />
 					</a>
 				</li>
 				<li class="page-item">
-					<a class="page-link" href="{f:uri.action(action:actionName, arguments:{currentPage: pagination.lastPageNumber})}" title="{f:translate(key:'widget.pagination.last')}">
+					<a class="page-link"
+					   href="{f:uri.action(action: actionName, arguments: {currentPage: pagination.lastPage})}"
+					   title="{f:translate(key:'widget.pagination.last')}">
 						<core:icon identifier="actions-view-paging-last" />
 					</a>
 				</li>
@@ -95,7 +95,9 @@
 			</f:else>
 		</f:if>
 		<li class="page-item">
-			<a class="page-link" href="{f:uri.action(action:actionName, arguments:{currentPage: currentPage})}" title="{f:translate(key:'widget.pagination.refresh')}">
+			<a class="page-link"
+			   href="{f:uri.action(action: actionName, arguments:{currentPage: pagination.currentPage})}"
+			   title="{f:translate(key:'widget.pagination.refresh')}">
 				<core:icon identifier="actions-refresh" />
 			</a>
 		</li>
-- 
GitLab