BxDolPaginate.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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 $_iStart; ///< start display items from this number
  66. protected $_iNum; ///< available results, you need to query per_page + 1 results, so paginate can determine last page
  67. protected $_iPerPage; ///< results per page
  68. protected $_sPageUrl; ///< page url of next/prev page, special markers will be replaced here automatically
  69. protected $_sOnChangePage; ///< on click of next/prev page, special markers will be replaced here automatically
  70. protected $_bInfo; ///< show displayed items info
  71. protected $_sViewAllUrl; ///< view "all results" url, for "simple" paginate
  72. protected $_sViewAllCaption; ///< 'view all' link caption
  73. protected $_sButtonsClass; ///< add this class to buttons class attribute
  74. protected $_sPaginateClass; ///< add this class to whole paginate container div
  75. /**
  76. * Constructor
  77. */
  78. public function __construct($aParams, $oTemplate = null)
  79. {
  80. parent::__construct();
  81. if ($oTemplate)
  82. $this->_oTemplate = $oTemplate;
  83. else
  84. $this->_oTemplate = BxDolTemplate::getInstance();
  85. if (isset($aParams['count']))
  86. trigger_error ('Paginate "count" is deprecated - use "num" instead: ' . get_class($this), E_USER_ERROR);
  87. //--- Main settings ---//
  88. $this->_iStart = isset($aParams['start']) && (int)$aParams['start'] > 0 ? (int)$aParams['start'] : 0;
  89. $this->_iNum = isset($aParams['num']) ? (int)$aParams['num'] : 0;
  90. $this->_iPerPage = isset($aParams['per_page']) && (int)$aParams['per_page'] > 0 ? (int)$aParams['per_page'] : BX_DOL_PAGINATE_PER_PAGE_DEFAULT;
  91. $this->_bInfo = isset($aParams['info']) ? (bool)$aParams['info'] : true;
  92. $this->_sButtonsClass = isset($aParams['buttons_class']) ? $aParams['buttons_class'] : '';
  93. $this->_sViewAllUrl = isset($aParams['view_all_url']) ? $aParams['view_all_url'] : false;
  94. $this->_sViewAllCaption = isset($aParams['view_all_caption']) ? $aParams['view_all_caption'] : _t('_sys_paginate_view_all');
  95. $this->_sPaginateClass = isset($aParams['paginate_class']) ? $aParams['paginate_class'] : '';
  96. // page url
  97. $this->_sPageUrl = isset($aParams['page_url']) ? $aParams['page_url'] : BX_DOL_URL_ROOT;
  98. // on click (js mode)
  99. $this->_sOnChangePage = isset($aParams['on_change_page']) ? $aParams['on_change_page'] : '';
  100. }
  101. /**
  102. * Get number of available results per page. If it is not last page,
  103. * then this number is number of result per page plus one.
  104. * @return integer
  105. */
  106. public function getNum()
  107. {
  108. return $this->_iNum;
  109. }
  110. /**
  111. * Set number of available items on the page directly from data array.
  112. * Since data array should contain additional record - we will pop last item from array automatically.
  113. * @return nothing.
  114. */
  115. public function setNumFromDataArray(&$a, $isAutoPopLastElement = true)
  116. {
  117. if ($a && is_array($a))
  118. $this->_iNum = count($a);
  119. else
  120. $this->_iNum = 0;
  121. if ($this->_iNum > $this->_iPerPage && $isAutoPopLastElement)
  122. array_pop($a);
  123. }
  124. /**
  125. * Set number of available items on the page,
  126. * it should be number of items per page + 1 (+1 is needed to correctly determine last page).
  127. * It is possible to set this value automatically @see setNumFromDataArray.
  128. * @param $i positive integer.
  129. * @return true on success or false if $i param isn't correct.
  130. */
  131. public function setNum($i)
  132. {
  133. if ($i >= 0) {
  134. $this->_iNum = (int)$i;
  135. return true;
  136. }
  137. return false;
  138. }
  139. /**
  140. * Position, the data is showing from.
  141. * @return integer.
  142. */
  143. public function getStart()
  144. {
  145. return $this->_iStart;
  146. }
  147. /**
  148. * Set the starting position, the data is showing from.
  149. * @param $i positive integer.
  150. * @return true on siccess or false on error.
  151. */
  152. public function setStart($i)
  153. {
  154. if ($i >= 0) {
  155. $this->_iStart = (int)$i;
  156. return true;
  157. }
  158. return false;
  159. }
  160. /**
  161. * Get number of records per page.
  162. * @return integer.
  163. */
  164. public function getPerPage()
  165. {
  166. return $this->_iPerPage;
  167. }
  168. /**
  169. * Set number of records per page.
  170. * @param $i positive integer.
  171. * @return integer.
  172. */
  173. public function setPerPage($i)
  174. {
  175. if ((int)$i > 0) {
  176. $this->_iPerPage = $i;
  177. return true;
  178. }
  179. return false;
  180. }
  181. /**
  182. * Set string to pass to 'onclick' for change page button.
  183. * The following markers are replaced automatically:
  184. * - {per_page}
  185. * - {start}
  186. *
  187. * @param $i positive integer.
  188. * @return integer.
  189. */
  190. public function setOnChangePage($s)
  191. {
  192. $this->_sOnChangePage = $s;
  193. }
  194. /**
  195. * @return true if previous page is available, or false if not
  196. */
  197. public function isPrevAvail ()
  198. {
  199. return $this->_iStart > 0 ? true : false;
  200. }
  201. /**
  202. * @return true if next page is available, or false if not
  203. */
  204. public function isNextAvail ()
  205. {
  206. return $this->_iNum > $this->_iPerPage ? true : false;
  207. }
  208. /**
  209. * Get default paginate, it is better to use it on the whole page.
  210. * @param $iStart - @see setStart.
  211. * @param $iNum - @see setNum and @see setNumFromDataArray.
  212. * @param $iPerPage - @see setPerPage.
  213. * @return HTML string.
  214. */
  215. public function getPaginate($iStart = -1, $iNum = -1, $iPerPage = -1)
  216. {
  217. $this->setNum($iNum);
  218. if (!$this->_iNum)
  219. return '';
  220. $this->setStart($iStart);
  221. $this->setPerPage($iPerPage);
  222. if (0 == $this->getStart() && !$this->isNextAvail ())
  223. return '';
  224. $aReplacement = $this->_getReplacement();
  225. //--- Previous Page button ---//
  226. $sPrevLnkUrl = 'javascript:void(0);';
  227. $sPrevLnkClick = '';
  228. $sPrevClassAdd = ' bx-btn-disabled';
  229. if ($this->isPrevAvail()) {
  230. $iStartPrev = $this->_iStart - $this->_iPerPage > 0 ? $this->_iStart - $this->_iPerPage : 0;
  231. $aReplacementLink = array_merge($aReplacement, array('start' => $iStartPrev));
  232. $sPrevLnkUrl = $this->_getPageChangeUrl($aReplacementLink);
  233. $sPrevLnkClick = $this->_getPageChangeOnClick($aReplacementLink);
  234. $sPrevClassAdd = '';
  235. }
  236. //--- Next Page button ---//
  237. $sNextLnkUrl = 'javascript:void(0);';
  238. $sNextLnkClick = '';
  239. $sNextClassAdd = ' bx-btn-disabled';
  240. if ($this->isNextAvail()) {
  241. $aReplacementLink = array_merge($aReplacement, array('start' => $this->_iStart + $this->_iPerPage));
  242. $sNextLnkUrl = $this->_getPageChangeUrl($aReplacementLink);
  243. $sNextLnkClick = $this->_getPageChangeOnClick($aReplacementLink);
  244. $sNextClassAdd = '';
  245. }
  246. $sClassAdd = ($this->_sButtonsClass ? ' ' . $this->_sButtonsClass : '');
  247. $aVariables = array(
  248. 'bx_if:info' => array (
  249. 'condition' => (bool)$this->_bInfo,
  250. 'content' => array(
  251. 'text' => _t('_sys_paginate_info', $this->_iStart + 1, $this->_iStart + ($this->isNextAvail () ? $this->_iPerPage : $this->_iNum)),
  252. ),
  253. ),
  254. 'bx_if:view_all' => array(
  255. 'condition' => (bool)$this->_sViewAllUrl,
  256. 'content' => array(
  257. 'lnk_url' => $this->_sViewAllUrl,
  258. 'lnk_title' => $this->_sViewAllCaption,
  259. 'lnk_content' => $this->_sViewAllCaption,
  260. ),
  261. ),
  262. 'btn_prev' => '<a href="' . $sPrevLnkUrl . '" ' . $sPrevLnkClick . ' class="bx-paginate-btn-prev bx-btn' . $sClassAdd . $sPrevClassAdd . '"><i class="sys-icon sys-icon-bigger angle-double-left"></i></a>',
  263. 'btn_next' => '<a href="' . $sNextLnkUrl . '" ' . $sNextLnkClick . ' class="bx-paginate-btn-next bx-btn' . $sClassAdd . $sNextClassAdd . '"><i class="sys-icon sys-icon-bigger angle-double-right"></i></a>',
  264. 'paginate_class' => $this->_sPaginateClass,
  265. 'bx_repeat:attrs' => array(
  266. array('key' => 'bx-data-start', 'value' => $this->_iStart),
  267. array('key' => 'bx-data-perpage', 'value' => $this->_iPerPage)
  268. )
  269. );
  270. $this->addCssJs();
  271. return $this->_oTemplate->parseHtmlByName('paginate.html', $aVariables);
  272. }
  273. /**
  274. * Get limited paginate, it is better to use in some boxes, where availabel space is limited or for ajax paginate.
  275. * @param $sViewAllUrl - url to page for 'view all' link.
  276. * @param $iStart - @see setStart.
  277. * @param $iNum - @see setNum and @see setNumFromDataArray.
  278. * @param $iPerPage - @see setPerPage.
  279. * @return HTML string.
  280. */
  281. public function getSimplePaginate($sViewAllUrl = '', $iStart = -1, $iNum = -1, $iPerPage = -1)
  282. {
  283. if ($sViewAllUrl)
  284. $this->_sViewAllUrl = $sViewAllUrl;
  285. $this->_bInfo = false;
  286. $this->_sButtonsClass .= ($this->_sButtonsClass ? ' ' : '') . 'bx-btn-small bx-btn-symbol-small';
  287. $this->_sPaginateClass = 'bx-paginate-simple';
  288. return $this->getPaginate($iStart, $iNum, $iPerPage);
  289. }
  290. public function addCssJs ()
  291. {
  292. if (self::$_isCssAdded)
  293. return false;
  294. $this->_oTemplate->addCss('paginate.css');
  295. self::$_isCssAdded = true;
  296. return true;
  297. }
  298. protected function _getReplacement()
  299. {
  300. return array(
  301. 'start' => $this->_iStart,
  302. 'per_page' => $this->_iPerPage,
  303. );
  304. }
  305. protected function _getPageChangeUrl($aReplacement)
  306. {
  307. return $this->_oTemplate->parseHtmlByContent($this->_sPageUrl, $aReplacement, array('{', '}'));
  308. }
  309. protected function _getPageChangeOnClick($aReplacement)
  310. {
  311. return !empty($this->_sOnChangePage) ? 'onclick="javascript:' . $this->_oTemplate->parseHtmlByContent($this->_sOnChangePage, $aReplacement, array('{', '}')) . '; return false;"' : '';
  312. }
  313. }
  314. /** @} */