2018-10-24 08:07:21 +02:00
|
|
|
<?php
|
2020-02-09 15:45:36 +01:00
|
|
|
/**
|
|
|
|
* @copyright Copyright (C) 2020, Friendica
|
|
|
|
*
|
|
|
|
* @license GNU AGPL version 3 or any later version
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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 Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
2018-10-24 08:07:21 +02:00
|
|
|
|
|
|
|
namespace Friendica\Content;
|
|
|
|
|
2018-10-31 15:35:50 +01:00
|
|
|
use Friendica\Core\Renderer;
|
2020-01-18 22:07:07 +01:00
|
|
|
use Friendica\DI;
|
2019-01-12 01:29:39 +01:00
|
|
|
use Friendica\Util\Strings;
|
2018-10-24 08:07:21 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The Pager has two very different output, Minimal and Full, see renderMinimal() and renderFull() for more details.
|
|
|
|
*/
|
|
|
|
class Pager
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var integer
|
|
|
|
*/
|
|
|
|
private $page = 1;
|
|
|
|
/**
|
|
|
|
* @var integer
|
|
|
|
*/
|
2020-02-16 09:23:27 +01:00
|
|
|
protected $itemsPerPage = 50;
|
2018-10-24 08:07:21 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
2020-02-16 09:23:27 +01:00
|
|
|
protected $baseQueryString = '';
|
2018-10-24 08:07:21 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Instantiates a new Pager with the base parameters.
|
|
|
|
*
|
|
|
|
* Guesses the page number from the GET parameter 'page'.
|
|
|
|
*
|
|
|
|
* @param string $queryString The query string of the current page
|
|
|
|
* @param integer $itemsPerPage An optional number of items per page to override the default value
|
|
|
|
*/
|
2018-10-24 17:42:59 +02:00
|
|
|
public function __construct($queryString, $itemsPerPage = 50)
|
2018-10-24 08:07:21 +02:00
|
|
|
{
|
|
|
|
$this->setQueryString($queryString);
|
|
|
|
$this->setItemsPerPage($itemsPerPage);
|
2019-10-16 14:35:14 +02:00
|
|
|
$this->setPage(($_GET['page'] ?? 0) ?: 1);
|
2018-10-24 08:07:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the start offset for a LIMIT clause. Starts at 0.
|
|
|
|
*
|
|
|
|
* @return integer
|
|
|
|
*/
|
|
|
|
public function getStart()
|
|
|
|
{
|
|
|
|
return max(0, ($this->page * $this->itemsPerPage) - $this->itemsPerPage);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the number of items per page
|
|
|
|
*
|
|
|
|
* @return integer
|
|
|
|
*/
|
|
|
|
public function getItemsPerPage()
|
|
|
|
{
|
|
|
|
return $this->itemsPerPage;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current page number
|
|
|
|
*
|
2019-01-06 22:06:53 +01:00
|
|
|
* @return int
|
2018-10-24 08:07:21 +02:00
|
|
|
*/
|
|
|
|
public function getPage()
|
|
|
|
{
|
|
|
|
return $this->page;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the base query string.
|
|
|
|
*
|
|
|
|
* Warning: this isn't the same value as passed to the constructor.
|
2018-10-24 17:42:59 +02:00
|
|
|
* See setQueryString() for the inventory of transformations
|
2018-10-24 08:07:21 +02:00
|
|
|
*
|
|
|
|
* @see setBaseQuery()
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getBaseQueryString()
|
|
|
|
{
|
2019-01-12 01:30:33 +01:00
|
|
|
return Strings::ensureQueryParameter($this->baseQueryString);
|
2018-10-24 08:07:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the number of items per page, 1 minimum.
|
|
|
|
*
|
|
|
|
* @param integer $itemsPerPage
|
|
|
|
*/
|
|
|
|
public function setItemsPerPage($itemsPerPage)
|
|
|
|
{
|
|
|
|
$this->itemsPerPage = max(1, intval($itemsPerPage));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the current page number. Starts at 1.
|
|
|
|
*
|
|
|
|
* @param integer $page
|
|
|
|
*/
|
|
|
|
public function setPage($page)
|
|
|
|
{
|
|
|
|
$this->page = max(1, intval($page));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the base query string from a full query string.
|
|
|
|
*
|
|
|
|
* Strips the 'page' parameter, and remove the 'q=' string for some reason.
|
|
|
|
*
|
|
|
|
* @param string $queryString
|
|
|
|
*/
|
|
|
|
public function setQueryString($queryString)
|
|
|
|
{
|
|
|
|
$stripped = preg_replace('/([&?]page=[0-9]*)/', '', $queryString);
|
|
|
|
|
|
|
|
$stripped = trim($stripped, '/');
|
|
|
|
|
|
|
|
$this->baseQueryString = $stripped;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-01-19 07:05:23 +01:00
|
|
|
* Minimal pager (newer/older)
|
2018-10-24 08:07:21 +02:00
|
|
|
*
|
|
|
|
* This mode is intended for reverse chronological pages and presents only two links, newer (previous) and older (next).
|
|
|
|
* The itemCount is the number of displayed items. If no items are displayed, the older button is disabled.
|
|
|
|
*
|
|
|
|
* Example usage:
|
|
|
|
*
|
|
|
|
* $pager = new Pager($a->query_string);
|
|
|
|
*
|
|
|
|
* $params = ['order' => ['sort_field' => true], 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
|
|
|
|
* $items = DBA::toArray(DBA::select($table, $fields, $condition, $params));
|
|
|
|
*
|
|
|
|
* $html = $pager->renderMinimal(count($items));
|
|
|
|
*
|
2020-02-16 09:23:27 +01:00
|
|
|
* @param int $itemCount The number of displayed items on the page
|
2018-10-24 08:07:21 +02:00
|
|
|
* @return string HTML string of the pager
|
2020-02-16 09:23:27 +01:00
|
|
|
* @throws \Exception
|
2018-10-24 08:07:21 +02:00
|
|
|
*/
|
2020-02-16 09:23:27 +01:00
|
|
|
public function renderMinimal(int $itemCount)
|
2018-10-24 08:07:21 +02:00
|
|
|
{
|
2018-10-24 17:42:59 +02:00
|
|
|
$displayedItemCount = max(0, intval($itemCount));
|
2018-10-24 08:07:21 +02:00
|
|
|
|
|
|
|
$data = [
|
|
|
|
'class' => 'pager',
|
|
|
|
'prev' => [
|
2019-01-12 01:29:39 +01:00
|
|
|
'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() - 1)),
|
2020-01-18 20:52:34 +01:00
|
|
|
'text' => DI::l10n()->t('newer'),
|
2018-10-24 08:07:21 +02:00
|
|
|
'class' => 'previous' . ($this->getPage() == 1 ? ' disabled' : '')
|
|
|
|
],
|
|
|
|
'next' => [
|
2019-01-12 01:29:39 +01:00
|
|
|
'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() + 1)),
|
2020-01-18 20:52:34 +01:00
|
|
|
'text' => DI::l10n()->t('older'),
|
2018-12-24 01:42:50 +01:00
|
|
|
'class' => 'next' . ($displayedItemCount < $this->getItemsPerPage() ? ' disabled' : '')
|
2018-10-24 08:07:21 +02:00
|
|
|
]
|
|
|
|
];
|
|
|
|
|
2018-10-31 15:44:06 +01:00
|
|
|
$tpl = Renderer::getMarkupTemplate('paginate.tpl');
|
2018-10-31 15:35:50 +01:00
|
|
|
return Renderer::replaceMacros($tpl, ['pager' => $data]);
|
2018-10-24 08:07:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-01-19 07:05:23 +01:00
|
|
|
* Full pager (first / prev / 1 / 2 / ... / 14 / 15 / next / last)
|
2018-10-24 08:07:21 +02:00
|
|
|
*
|
|
|
|
* This mode presents page numbers as well as first, previous, next and last links.
|
|
|
|
* The itemCount is the total number of items including those not displayed.
|
|
|
|
*
|
|
|
|
* Example usage:
|
|
|
|
*
|
|
|
|
* $total = DBA::count($table, $condition);
|
|
|
|
*
|
|
|
|
* $pager = new Pager($a->query_string, $total);
|
|
|
|
*
|
|
|
|
* $params = ['limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
|
|
|
|
* $items = DBA::toArray(DBA::select($table, $fields, $condition, $params));
|
|
|
|
*
|
|
|
|
* $html = $pager->renderFull();
|
|
|
|
*
|
2018-10-24 17:42:59 +02:00
|
|
|
* @param integer $itemCount The total number of items including those note displayed on the page
|
2018-10-24 08:07:21 +02:00
|
|
|
* @return string HTML string of the pager
|
2019-01-06 22:06:53 +01:00
|
|
|
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
2018-10-24 08:07:21 +02:00
|
|
|
*/
|
2018-10-24 17:42:59 +02:00
|
|
|
public function renderFull($itemCount)
|
2018-10-24 08:07:21 +02:00
|
|
|
{
|
2018-10-24 17:42:59 +02:00
|
|
|
$totalItemCount = max(0, intval($itemCount));
|
|
|
|
|
2018-10-24 08:07:21 +02:00
|
|
|
$data = [];
|
|
|
|
|
|
|
|
$data['class'] = 'pagination';
|
2018-10-24 17:42:59 +02:00
|
|
|
if ($totalItemCount > $this->getItemsPerPage()) {
|
2018-10-24 08:07:21 +02:00
|
|
|
$data['first'] = [
|
2019-01-12 01:29:39 +01:00
|
|
|
'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=1'),
|
2020-01-18 20:52:34 +01:00
|
|
|
'text' => DI::l10n()->t('first'),
|
2018-10-24 08:07:21 +02:00
|
|
|
'class' => $this->getPage() == 1 ? 'disabled' : ''
|
|
|
|
];
|
|
|
|
$data['prev'] = [
|
2019-01-12 01:29:39 +01:00
|
|
|
'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() - 1)),
|
2020-01-18 20:52:34 +01:00
|
|
|
'text' => DI::l10n()->t('prev'),
|
2018-10-24 08:07:21 +02:00
|
|
|
'class' => $this->getPage() == 1 ? 'disabled' : ''
|
|
|
|
];
|
|
|
|
|
2018-10-24 17:42:59 +02:00
|
|
|
$numpages = $totalItemCount / $this->getItemsPerPage();
|
2018-10-24 08:07:21 +02:00
|
|
|
|
|
|
|
$numstart = 1;
|
|
|
|
$numstop = $numpages;
|
|
|
|
|
|
|
|
// Limit the number of displayed page number buttons.
|
|
|
|
if ($numpages > 8) {
|
|
|
|
$numstart = (($this->getPage() > 4) ? ($this->getPage() - 4) : 1);
|
|
|
|
$numstop = (($this->getPage() > ($numpages - 7)) ? $numpages : ($numstart + 8));
|
|
|
|
}
|
|
|
|
|
|
|
|
$pages = [];
|
|
|
|
|
|
|
|
for ($i = $numstart; $i <= $numstop; $i++) {
|
|
|
|
if ($i == $this->getPage()) {
|
|
|
|
$pages[$i] = [
|
|
|
|
'url' => '#',
|
|
|
|
'text' => $i,
|
|
|
|
'class' => 'current active'
|
|
|
|
];
|
|
|
|
} else {
|
|
|
|
$pages[$i] = [
|
2019-01-12 01:29:39 +01:00
|
|
|
'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . $i),
|
2018-10-24 08:07:21 +02:00
|
|
|
'text' => $i,
|
|
|
|
'class' => 'n'
|
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-24 17:42:59 +02:00
|
|
|
if (($totalItemCount % $this->getItemsPerPage()) != 0) {
|
2018-10-24 08:07:21 +02:00
|
|
|
if ($i == $this->getPage()) {
|
|
|
|
$pages[$i] = [
|
|
|
|
'url' => '#',
|
|
|
|
'text' => $i,
|
|
|
|
'class' => 'current active'
|
|
|
|
];
|
|
|
|
} else {
|
|
|
|
$pages[$i] = [
|
2019-01-12 01:29:39 +01:00
|
|
|
'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . $i),
|
2018-10-24 08:07:21 +02:00
|
|
|
'text' => $i,
|
|
|
|
'class' => 'n'
|
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$data['pages'] = $pages;
|
|
|
|
|
|
|
|
$lastpage = (($numpages > intval($numpages)) ? intval($numpages)+1 : $numpages);
|
|
|
|
|
|
|
|
$data['next'] = [
|
2019-01-12 01:29:39 +01:00
|
|
|
'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() + 1)),
|
2020-01-18 20:52:34 +01:00
|
|
|
'text' => DI::l10n()->t('next'),
|
2018-10-24 08:07:21 +02:00
|
|
|
'class' => $this->getPage() == $lastpage ? 'disabled' : ''
|
|
|
|
];
|
|
|
|
$data['last'] = [
|
2019-01-12 01:29:39 +01:00
|
|
|
'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . $lastpage),
|
2020-01-18 20:52:34 +01:00
|
|
|
'text' => DI::l10n()->t('last'),
|
2018-10-24 08:07:21 +02:00
|
|
|
'class' => $this->getPage() == $lastpage ? 'disabled' : ''
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2018-10-31 15:44:06 +01:00
|
|
|
$tpl = Renderer::getMarkupTemplate('paginate.tpl');
|
2018-10-31 15:35:50 +01:00
|
|
|
return Renderer::replaceMacros($tpl, ['pager' => $data]);
|
2018-10-24 08:07:21 +02:00
|
|
|
}
|
|
|
|
}
|