BxDolPaginate.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaCore UNA Core
  7. * @{
  8. */
  9. define('BX_DOL_PAGINATE_PER_PAGE_DEFAULT', 10);
  10. /**
  11. * Paginage for any content.
  12. * It is used to create paginate, configuring it via input parameters.
  13. * Paginate don't support total number of pages, moreover it is not recommended to count all records - it slows down the site.
  14. * To correctly determine last page we need to pass number of available records on the current page plus one - so we always know if next page is available.
  15. *
  16. *
  17. * Two types of paginate presentation is supported:
  18. * - getPaginate() - to get default paginate, it is better to use it on the whole page.
  19. * - getSimplePaginate() - to get limited paginate, it is better to use in some boxes, where availabel space is limited or for ajax paginate.
  20. *
  21. *
  22. * The list of available input parameters:
  23. *
  24. *
  25. * Parameters:
  26. * - start - position of the first item.
  27. * - num - number of available items on the page, it should be number of items per page + 1 (+1 is needed to correctly determine last page). It is possible to set this value automatically @see setNumFromDataArray.
  28. * - per_page - number of items displayed on the page.
  29. * - page_url - page URL to go through pages, special markers are automatically replaced.
  30. * - on_change_page - JavaScript code to be called on change page.
  31. * - info - display info.
  32. * - view_all_url - URL for 'view all' page. This url is not showed by default. It is convinient to use with @see getSimplePaginate.
  33. * - view_all_caption - optional caption for 'view all' link.
  34. *
  35. *
  36. * Available markers to replace in 'page_url' and 'on_change_page' parameters:
  37. * - {per_page} - current number of items to display per page.
  38. * - {start} - the number to display items starting from.
  39. *
  40. *
  41. * Example of usage:
  42. * @code
  43. * $oPaginate = new BxDolPaginate(array(
  44. * 'start' => 0,
  45. * 'num' => 11,
  46. * 'per_page' => 10,
  47. * 'on_change_page' => 'changePage({start}, {per_page})'
  48. * ));
  49. * $oPaginate->getPaginate();
  50. * @endcode
  51. *
  52. *
  53. * Memberships/ACL:
  54. * Doesn't depend on user's membership.
  55. *
  56. *
  57. * Alerts:
  58. * no alerts available
  59. *
  60. */
  61. abstract class BxDolPaginate extends BxDol
  62. {
  63. protected static $_isCssAdded = false;
  64. protected $_oTemplate;
  65. protected $_aParams; ///< an array with initially provided params
  66. protected $_iStart; ///< start display items from this number
  67. protected $_iPerPage; ///< results per page
  68. protected $_iNum; ///< available results, you need to query per_page + 1 results, so paginate can determine last page
  69. protected $_iTotal; ///< total number of results. (Optional)
  70. protected $_bTotal; ///< show displayed items info with total value
  71. protected $_sPageUrl; ///< page url of next/prev page, special markers will be replaced here automatically
  72. protected $_sOnChangePage; ///< on click of next/prev page, special markers will be replaced here automatically
  73. protected $_bInfo; ///< show displayed items info
  74. protected $_sViewAllUrl; ///< view "all results" url, for "simple" paginate
  75. protected $_sViewAllCaption; ///< 'view all' link caption
  76. protected $_sButtonsClass; ///< add this class to buttons class attribute
  77. protected $_sPaginateClass; ///< add this class to whole paginate container div
  78. /**
  79. * Constructor
  80. */
  81. public function __construct($aParams, $oTemplate = null)
  82. {
  83. parent::__construct();
  84. if ($oTemplate)
  85. $this->_oTemplate = $oTemplate;
  86. else
  87. $this->_oTemplate = BxDolTemplate::getInstance();
  88. if (isset($aParams['count']))
  89. trigger_error ('Paginate "count" is deprecated - use "num" instead: ' . get_class($this), E_USER_ERROR);
  90. //--- Main settings ---//
  91. $this->_aParams = $aParams;
  92. $this->_iStart = isset($aParams['start']) && (int)$aParams['start'] > 0 ? (int)$aParams['start'] : 0;
  93. $this->_iPerPage = isset($aParams['per_page']) && (int)$aParams['per_page'] > 0 ? (int)$aParams['per_page'] : BX_DOL_PAGINATE_PER_PAGE_DEFAULT;
  94. $this->_iNum = isset($aParams['num']) ? (int)$aParams['num'] : 0;
  95. $this->_iTotal = isset($aParams['total']) ? (int)$aParams['total'] : 0;
  96. $this->_bTotal = $this->_iTotal > 0;
  97. $this->_bInfo = isset($aParams['info']) ? (bool)$aParams['info'] : true;
  98. $this->_sButtonsClass = isset($aParams['buttons_class']) ? $aParams['buttons_class'] : '';
  99. $this->_sViewAllUrl = isset($aParams['view_all_url']) ? $aParams['view_all_url'] : false;
  100. $this->_sViewAllCaption = isset($aParams['view_all_caption']) ? $aParams['view_all_caption'] : _t('_sys_paginate_view_all');
  101. $this->_sPaginateClass = isset($aParams['paginate_class']) ? $aParams['paginate_class'] : '';
  102. // page url
  103. $this->_sPageUrl = isset($aParams['page_url']) ? $aParams['page_url'] : BX_DOL_URL_ROOT;
  104. // on click (js mode)
  105. $this->_sOnChangePage = isset($aParams['on_change_page']) ? $aParams['on_change_page'] : '';
  106. }
  107. /**
  108. * Get number of available results per page. If it is not last page,
  109. * then this number is number of result per page plus one.
  110. * @return integer
  111. */
  112. public function getNum()
  113. {
  114. return $this->_iNum;
  115. }
  116. /**
  117. * Set number of available items on the page directly from data array.
  118. * Since data array should contain additional record - we will pop last item from array automatically.
  119. * @return nothing.
  120. */
  121. public function setNumFromDataArray(&$a, $isAutoPopLastElement = true)
  122. {
  123. if ($a && is_array($a))
  124. $this->_iNum = count($a);
  125. else
  126. $this->_iNum = 0;
  127. if ($this->_iNum > $this->_iPerPage && $isAutoPopLastElement)
  128. array_pop($a);
  129. }
  130. /**
  131. * Set number of available items on the page,
  132. * it should be number of items per page + 1 (+1 is needed to correctly determine last page).
  133. * It is possible to set this value automatically @see setNumFromDataArray.
  134. * @param $i positive integer.
  135. * @return true on success or false if $i param isn't correct.
  136. */
  137. public function setNum($i)
  138. {
  139. if ($i >= 0) {
  140. $this->_iNum = (int)$i;
  141. return true;
  142. }
  143. return false;
  144. }
  145. /**
  146. * Position, the data is showing from.
  147. * @return integer.
  148. */
  149. public function getStart()
  150. {
  151. return $this->_iStart;
  152. }
  153. /**
  154. * Set the starting position, the data is showing from.
  155. * @param $i positive integer.
  156. * @return true on siccess or false on error.
  157. */
  158. public function setStart($i)
  159. {
  160. if ($i >= 0) {
  161. $this->_iStart = (int)$i;
  162. return true;
  163. }
  164. return false;
  165. }
  166. /**
  167. * Get number of records per page.
  168. * @return integer.
  169. */
  170. public function getPerPage()
  171. {
  172. return $this->_iPerPage;
  173. }
  174. /**
  175. * Set number of records per page.
  176. * @param $i positive integer.
  177. * @return integer.
  178. */
  179. public function setPerPage($i)
  180. {
  181. if ((int)$i > 0) {
  182. $this->_iPerPage = $i;
  183. return true;
  184. }
  185. return false;
  186. }
  187. /**
  188. * Set string to pass to 'onclick' for change page button.
  189. * The following markers are replaced automatically:
  190. * - {per_page}
  191. * - {start}
  192. *
  193. * @param $i positive integer.
  194. * @return integer.
  195. */
  196. public function setOnChangePage($s)
  197. {
  198. $this->_sOnChangePage = $s;
  199. }
  200. /**
  201. * @return true if previous page is available, or false if not
  202. */
  203. public function isPrevAvail ()
  204. {
  205. return $this->_iStart > 0 ? true : false;
  206. }
  207. /**
  208. * @return true if next page is available, or false if not
  209. */
  210. public function isNextAvail ()
  211. {
  212. return $this->_iNum > $this->_iPerPage ? true : false;
  213. }
  214. /**
  215. * Get default paginate, it is better to use it on the whole page.
  216. * @param $iStart - @see setStart.
  217. * @param $iNum - @see setNum and @see setNumFromDataArray.
  218. * @param $iPerPage - @see setPerPage.
  219. * @return HTML string.
  220. */
  221. public function getPaginate($iStart = -1, $iNum = -1, $iPerPage = -1)
  222. {
  223. $this->setNum($iNum);
  224. if (!$this->_iNum)
  225. return '';
  226. $this->setStart($iStart);
  227. $this->setPerPage($iPerPage);
  228. if (0 == $this->getStart() && !$this->isNextAvail ())
  229. return '';
  230. $aReplacement = $this->_getReplacement();
  231. //--- Previous Page button ---//
  232. $sPrevLnkUrl = 'javascript:void(0);';
  233. $sPrevLnkClick = '';
  234. $sPrevClassAdd = ' bx-btn-disabled';
  235. if ($this->isPrevAvail()) {
  236. $iStartPrev = $this->_iStart - $this->_iPerPage > 0 ? $this->_iStart - $this->_iPerPage : 0;
  237. $aReplacementLink = array_merge($aReplacement, array('start' => $iStartPrev));
  238. $sPrevLnkUrl = $this->_getPageChangeUrl($aReplacementLink);
  239. $sPrevLnkClick = $this->_getPageChangeOnClick($aReplacementLink);
  240. $sPrevClassAdd = '';
  241. }
  242. //--- Next Page button ---//
  243. $sNextLnkUrl = 'javascript:void(0);';
  244. $sNextLnkClick = '';
  245. $sNextClassAdd = ' bx-btn-disabled';
  246. if ($this->isNextAvail()) {
  247. $aReplacementLink = array_merge($aReplacement, array('start' => $this->_iStart + $this->_iPerPage));
  248. $sNextLnkUrl = $this->_getPageChangeUrl($aReplacementLink);
  249. $sNextLnkClick = $this->_getPageChangeOnClick($aReplacementLink);
  250. $sNextClassAdd = '';
  251. }
  252. $sClassAdd = ($this->_sButtonsClass ? ' ' . $this->_sButtonsClass : '');
  253. $aVariables = [
  254. 'bx_if:info' => [
  255. 'condition' => $this->_bInfo && !$this->_bTotal,
  256. 'content' => [
  257. 'text' => _t('_sys_paginate_info', $this->_iStart + 1, $this->_iStart + ($this->isNextAvail () ? $this->_iPerPage : $this->_iNum)),
  258. ],
  259. ],
  260. 'bx_if:total' => [
  261. 'condition' => $this->_bTotal,
  262. 'content' => [
  263. 'text' => _t('_sys_paginate_total', $this->_iStart + 1, $this->_iStart + ($this->isNextAvail() ? $this->_iPerPage : $this->_iNum), $this->_iTotal),
  264. ],
  265. ],
  266. 'bx_if:view_all' => [
  267. 'condition' => (bool)$this->_sViewAllUrl,
  268. 'content' => [
  269. 'lnk_url' => $this->_sViewAllUrl,
  270. 'lnk_title' => $this->_sViewAllCaption,
  271. 'lnk_content' => $this->_sViewAllCaption,
  272. ],
  273. ],
  274. 'btn_prev' => $this->_getButton('prev', [
  275. 'class' => $sClassAdd . $sPrevClassAdd,
  276. 'href' => $sPrevLnkUrl,
  277. 'onclick' => $sPrevLnkClick,
  278. ]),
  279. 'btn_next' => $this->_getButton('next', [
  280. 'class' => $sClassAdd . $sNextClassAdd,
  281. 'href' => $sNextLnkUrl,
  282. 'onclick' => $sNextLnkClick,
  283. ]),
  284. 'paginate_class' => $this->_sPaginateClass,
  285. 'bx_repeat:attrs' => [
  286. ['key' => 'bx-data-start', 'value' => $this->_iStart],
  287. ['key' => 'bx-data-perpage', 'value' => $this->_iPerPage]
  288. ]
  289. ];
  290. $this->addCssJs();
  291. return $this->_oTemplate->parseHtmlByName('paginate.html', $aVariables);
  292. }
  293. /**
  294. * Get limited paginate, it is better to use in some boxes, where availabel space is limited or for ajax paginate.
  295. * @param $sViewAllUrl - url to page for 'view all' link.
  296. * @param $iStart - @see setStart.
  297. * @param $iNum - @see setNum and @see setNumFromDataArray.
  298. * @param $iPerPage - @see setPerPage.
  299. * @return HTML string.
  300. */
  301. public function getSimplePaginate($sViewAllUrl = '', $iStart = -1, $iNum = -1, $iPerPage = -1)
  302. {
  303. if($sViewAllUrl)
  304. $this->_sViewAllUrl = $sViewAllUrl;
  305. if(!isset($this->_aParams['info']))
  306. $this->_bInfo = false;
  307. $this->_sButtonsClass .= ($this->_sButtonsClass ? ' ' : '') . 'bx-btn-small bx-btn-symbol-small';
  308. $this->_sPaginateClass = 'bx-paginate-simple';
  309. return $this->getPaginate($iStart, $iNum, $iPerPage);
  310. }
  311. public function addCssJs ()
  312. {
  313. if (self::$_isCssAdded)
  314. return false;
  315. $this->_oTemplate->addCss('paginate.css');
  316. self::$_isCssAdded = true;
  317. return true;
  318. }
  319. protected function _getReplacement()
  320. {
  321. return array(
  322. 'start' => $this->_iStart,
  323. 'per_page' => $this->_iPerPage,
  324. );
  325. }
  326. protected function _getPageChangeUrl($aReplacement)
  327. {
  328. return $this->_oTemplate->parseHtmlByContent($this->_sPageUrl, $aReplacement, array('{', '}'));
  329. }
  330. protected function _getPageChangeOnClick($aReplacement)
  331. {
  332. return !empty($this->_sOnChangePage) ? 'onclick="javascript:' . $this->_oTemplate->parseHtmlByContent($this->_sOnChangePage, $aReplacement, array('{', '}')) . '; return false;"' : '';
  333. }
  334. protected function _getButtonIconPrev()
  335. {
  336. return 'angle-double-left';
  337. }
  338. protected function _getButtonIconNext()
  339. {
  340. return 'angle-double-right';
  341. }
  342. }
  343. /** @} */