PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/html/pagination.php

https://github.com/joebushi/joomla
PHP | 618 lines | 363 code | 75 blank | 180 comment | 63 complexity | c8bdadac836b3a6ae270a81ae73a7fce MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
  1. <?php
  2. /**
  3. * @version $Id$
  4. * @package Joomla.Framework
  5. * @subpackage HTML
  6. * @copyright Copyright (C) 2005 - 2010 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE.txt
  8. */
  9. // No direct access.
  10. defined('JPATH_BASE') or die;
  11. /**
  12. * Pagination Class. Provides a common interface for content pagination for the
  13. * Joomla! Framework.
  14. *
  15. * @package Joomla.Framework
  16. * @subpackage HTML
  17. * @since 1.5
  18. */
  19. class JPagination extends JObject
  20. {
  21. /**
  22. * The record number to start dislpaying from.
  23. *
  24. * @var int
  25. */
  26. public $limitstart = null;
  27. /**
  28. * Number of rows to display per page.
  29. *
  30. * @var int
  31. */
  32. public $limit = null;
  33. /**
  34. * Total number of rows.
  35. *
  36. * @var int
  37. */
  38. public $total = null;
  39. /**
  40. * Prefix used for request variables.
  41. *
  42. * @var int
  43. */
  44. public $prefix = null;
  45. /**
  46. * View all flag
  47. *
  48. * @var boolean
  49. */
  50. protected $_viewall = false;
  51. /**
  52. * Additional URL parameters to be added to the pagination URLs generated by the class. These
  53. * may be useful for filters and extra values when dealing with lists and GET requests.
  54. *
  55. * @var array
  56. * @since 1.6
  57. */
  58. protected $_additionalUrlParams = array();
  59. /**
  60. * Constructor.
  61. *
  62. * @param int The total number of items.
  63. * @param int The offset of the item to start at.
  64. * @param int The number of items to display per page.
  65. * @param string The prefix used for request variables.
  66. */
  67. function __construct($total, $limitstart, $limit, $prefix = '')
  68. {
  69. // Value/type checking.
  70. $this->total = (int) $total;
  71. $this->limitstart = (int) max($limitstart, 0);
  72. $this->limit = (int) max($limit, 0);
  73. $this->prefix = $prefix;
  74. if ($this->limit > $this->total) {
  75. $this->limitstart = 0;
  76. }
  77. if (!$this->limit)
  78. {
  79. $this->limit = $total;
  80. $this->limitstart = 0;
  81. }
  82. /*
  83. * If limitstart is greater than total (i.e. we are asked to display records that don't exist)
  84. * then set limitstart to display the last natural page of results
  85. */
  86. if ($this->limitstart > $this->total - $this->limit) {
  87. $this->limitstart = max(0, (int)(ceil($this->total / $this->limit) - 1) * $this->limit);
  88. }
  89. // Set the total pages and current page values.
  90. if ($this->limit > 0)
  91. {
  92. $this->set('pages.total', ceil($this->total / $this->limit));
  93. $this->set('pages.current', ceil(($this->limitstart + 1) / $this->limit));
  94. }
  95. // Set the pagination iteration loop values.
  96. $displayedPages = 10;
  97. $this->set('pages.start', (floor(($this->get('pages.current') -1) / $displayedPages)) * $displayedPages +1);
  98. if ($this->get('pages.start') + $displayedPages -1 < $this->get('pages.total')) {
  99. $this->set('pages.stop', $this->get('pages.start') + $displayedPages -1);
  100. }
  101. else {
  102. $this->set('pages.stop', $this->get('pages.total'));
  103. }
  104. // If we are viewing all records set the view all flag to true.
  105. if ($this->limit == $total) {
  106. $this->_viewall = true;
  107. }
  108. }
  109. /**
  110. * Method to set an additional URL parameter to be added to all pagination class generated
  111. * links.
  112. *
  113. * @param string $key The name of the URL parameter for which to set a value.
  114. * @param mixed $value The value to set for the URL parameter.
  115. *
  116. * @return mixed The old value for the parameter.
  117. *
  118. * @since 1.6
  119. */
  120. public function setAdditionalUrlParam($key, $value)
  121. {
  122. // Get the old value to return and set the new one for the URL parameter.
  123. $result = isset($this->_additionalUrlParams[$key]) ? $this->_additionalUrlParams[$key] : null;
  124. // If the passed parameter value is null unset the parameter, otherwise set it to the given value.
  125. if ($value === null) {
  126. unset($this->_additionalUrlParams[$key]);
  127. }
  128. else {
  129. $this->_additionalUrlParams[$key] = $value;
  130. }
  131. return $result;
  132. }
  133. /**
  134. * Method to get an additional URL parameter to be added to all pagination class generated
  135. * links if it exists.
  136. *
  137. * @param string $key The name of the URL parameter for which to get the value.
  138. *
  139. * @return mixed The value if it exists or null if it does not.
  140. *
  141. * @since 1.6
  142. */
  143. public function getAdditionalUrlParam($key)
  144. {
  145. $result = isset($this->_additionalUrlParams[$key]) ? $this->_additionalUrlParams[$key] : null;
  146. return $result;
  147. }
  148. /**
  149. * Return the rationalised offset for a row with a given index.
  150. *
  151. * @param int $index The row index
  152. * @return int Rationalised offset for a row with a given index.
  153. * @since 1.5
  154. */
  155. public function getRowOffset($index)
  156. {
  157. return $index +1 + $this->limitstart;
  158. }
  159. /**
  160. * Return the pagination data object, only creating it if it doesn't already exist.
  161. *
  162. * @return object Pagination data object.
  163. * @since 1.5
  164. */
  165. public function getData()
  166. {
  167. static $data;
  168. if (!is_object($data)) {
  169. $data = $this->_buildDataObject();
  170. }
  171. return $data;
  172. }
  173. /**
  174. * Create and return the pagination pages counter string, ie. Page 2 of 4.
  175. *
  176. * @return string Pagination pages counter string.
  177. * @since 1.5
  178. */
  179. public function getPagesCounter()
  180. {
  181. // Initialise variables.
  182. $html = null;
  183. if ($this->get('pages.total') > 1) {
  184. $html .= JText::sprintf('JPAGE_CURRENT_OF_TOTAL', $this->get('pages.current'), $this->get('pages.total'));
  185. }
  186. return $html;
  187. }
  188. /**
  189. * Create and return the pagination result set counter string, ie. Results 1-10 of 42
  190. *
  191. * @return string Pagination result set counter string.
  192. * @since 1.5
  193. */
  194. public function getResultsCounter()
  195. {
  196. // Initialise variables.
  197. $html = null;
  198. $fromResult = $this->limitstart + 1;
  199. // If the limit is reached before the end of the list.
  200. if ($this->limitstart + $this->limit < $this->total) {
  201. $toResult = $this->limitstart + $this->limit;
  202. }
  203. else {
  204. $toResult = $this->total;
  205. }
  206. // If there are results found.
  207. if ($this->total > 0) {
  208. $msg = JText::sprintf('RESULTS_OF', $fromResult, $toResult, $this->total);
  209. $html .= "\n".$msg;
  210. }
  211. else {
  212. $html .= "\n".JText::_('No_records_found');
  213. }
  214. return $html;
  215. }
  216. /**
  217. * Create and return the pagination page list string, ie. Previous, Next, 1 2 3 ... x.
  218. *
  219. * @return string Pagination page list string.
  220. * @since 1.0
  221. */
  222. public function getPagesLinks()
  223. {
  224. $app = &JFactory::getApplication();
  225. // Build the page navigation list.
  226. $data = $this->_buildDataObject();
  227. $list = array();
  228. $list['prefix'] = $this->prefix;
  229. $itemOverride = false;
  230. $listOverride = false;
  231. $chromePath = JPATH_THEMES.DS.$app->getTemplate().DS.'html'.DS.'pagination.php';
  232. if (file_exists($chromePath))
  233. {
  234. require_once $chromePath;
  235. if (function_exists('pagination_item_active') && function_exists('pagination_item_inactive')) {
  236. $itemOverride = true;
  237. }
  238. if (function_exists('pagination_list_render')) {
  239. $listOverride = true;
  240. }
  241. }
  242. // Build the select list
  243. if ($data->all->base !== null) {
  244. $list['all']['active'] = true;
  245. $list['all']['data'] = ($itemOverride) ? pagination_item_active($data->all) : $this->_item_active($data->all);
  246. } else {
  247. $list['all']['active'] = false;
  248. $list['all']['data'] = ($itemOverride) ? pagination_item_inactive($data->all) : $this->_item_inactive($data->all);
  249. }
  250. if ($data->start->base !== null) {
  251. $list['start']['active'] = true;
  252. $list['start']['data'] = ($itemOverride) ? pagination_item_active($data->start) : $this->_item_active($data->start);
  253. } else {
  254. $list['start']['active'] = false;
  255. $list['start']['data'] = ($itemOverride) ? pagination_item_inactive($data->start) : $this->_item_inactive($data->start);
  256. }
  257. if ($data->previous->base !== null) {
  258. $list['previous']['active'] = true;
  259. $list['previous']['data'] = ($itemOverride) ? pagination_item_active($data->previous) : $this->_item_active($data->previous);
  260. } else {
  261. $list['previous']['active'] = false;
  262. $list['previous']['data'] = ($itemOverride) ? pagination_item_inactive($data->previous) : $this->_item_inactive($data->previous);
  263. }
  264. $list['pages'] = array(); //make sure it exists
  265. foreach ($data->pages as $i => $page)
  266. {
  267. if ($page->base !== null) {
  268. $list['pages'][$i]['active'] = true;
  269. $list['pages'][$i]['data'] = ($itemOverride) ? pagination_item_active($page) : $this->_item_active($page);
  270. } else {
  271. $list['pages'][$i]['active'] = false;
  272. $list['pages'][$i]['data'] = ($itemOverride) ? pagination_item_inactive($page) : $this->_item_inactive($page);
  273. }
  274. }
  275. if ($data->next->base !== null) {
  276. $list['next']['active'] = true;
  277. $list['next']['data'] = ($itemOverride) ? pagination_item_active($data->next) : $this->_item_active($data->next);
  278. }
  279. else {
  280. $list['next']['active'] = false;
  281. $list['next']['data'] = ($itemOverride) ? pagination_item_inactive($data->next) : $this->_item_inactive($data->next);
  282. }
  283. if ($data->end->base !== null) {
  284. $list['end']['active'] = true;
  285. $list['end']['data'] = ($itemOverride) ? pagination_item_active($data->end) : $this->_item_active($data->end);
  286. }
  287. else {
  288. $list['end']['active'] = false;
  289. $list['end']['data'] = ($itemOverride) ? pagination_item_inactive($data->end) : $this->_item_inactive($data->end);
  290. }
  291. if ($this->total > $this->limit){
  292. return ($listOverride) ? pagination_list_render($list) : $this->_list_render($list);
  293. }
  294. else {
  295. return '';
  296. }
  297. }
  298. /**
  299. * Return the pagination footer.
  300. *
  301. * @return string Pagination footer.
  302. * @since 1.0
  303. */
  304. public function getListFooter()
  305. {
  306. $app = JFactory::getApplication();
  307. $list = array();
  308. $list['prefix'] = $this->prefix;
  309. $list['limit'] = $this->limit;
  310. $list['limitstart'] = $this->limitstart;
  311. $list['total'] = $this->total;
  312. $list['limitfield'] = $this->getLimitBox();
  313. $list['pagescounter'] = $this->getPagesCounter();
  314. $list['pageslinks'] = $this->getPagesLinks();
  315. $chromePath = JPATH_THEMES.DS.$app->getTemplate().DS.'html'.DS.'pagination.php';
  316. if (file_exists($chromePath))
  317. {
  318. require_once $chromePath;
  319. if (function_exists('pagination_list_footer')) {
  320. return pagination_list_footer($list);
  321. }
  322. }
  323. return $this->_list_footer($list);
  324. }
  325. /**
  326. * Creates a dropdown box for selecting how many records to show per page.
  327. *
  328. * @return string The html for the limit # input box.
  329. * @since 1.0
  330. */
  331. public function getLimitBox()
  332. {
  333. $app = JFactory::getApplication();
  334. // Initialise variables.
  335. $limits = array ();
  336. // Make the option list.
  337. for ($i = 5; $i <= 30; $i += 5) {
  338. $limits[] = JHtml::_('select.option', "$i");
  339. }
  340. $limits[] = JHtml::_('select.option', '50');
  341. $limits[] = JHtml::_('select.option', '100');
  342. $limits[] = JHtml::_('select.option', '0', JText::_('all'));
  343. $selected = $this->_viewall ? 0 : $this->limit;
  344. // Build the select list.
  345. if ($app->isAdmin()) {
  346. $html = JHtml::_('select.genericlist', $limits, $this->prefix . 'limit', 'class="inputbox" size="1" onchange="submitform();"', 'value', 'text', $selected);
  347. }
  348. else {
  349. $html = JHtml::_('select.genericlist', $limits, $this->prefix . 'limit', 'class="inputbox" size="1" onchange="this.form.submit()"', 'value', 'text', $selected);
  350. }
  351. return $html;
  352. }
  353. /**
  354. * Return the icon to move an item UP.
  355. *
  356. * @param integer The row index.
  357. * @param boolean True to show the icon.
  358. * @param string The task to fire.
  359. * @param string The image alternate text string.
  360. * @return string Either the icon to move an item up or a space.
  361. * @since 1.0
  362. */
  363. public function orderUpIcon($i, $condition = true, $task = 'orderup', $alt = 'JGrid_Move_Up', $enabled = true)
  364. {
  365. $alt = JText::_($alt);
  366. $html = '&nbsp;';
  367. if (($i > 0 || ($i + $this->limitstart > 0)) && $condition)
  368. {
  369. if ($enabled) {
  370. $html = '<a href="#reorder" onclick="return listItemTask(\'cb'.$i.'\',\''.$task.'\')" title="'.$alt.'">';
  371. $html .= JHTML::_('image', 'admin/uparrow.png', $alt, array( 'width' => 16, 'height' => 16, 'border' => 0), true);
  372. $html .= '</a>';
  373. }
  374. else {
  375. $html = JHTML::_('image', 'admin/uparrow0.png', $alt, array( 'width' => 16, 'height' => 16, 'border' => 0), true);
  376. }
  377. }
  378. return $html;
  379. }
  380. /**
  381. * Return the icon to move an item DOWN.
  382. *
  383. * @param int The row index.
  384. * @param int The number of items in the list.
  385. * @param boolean True to show the icon.
  386. * @param string The task to fire.
  387. * @param string The image alternate text string.
  388. * @return string Either the icon to move an item down or a space.
  389. * @since 1.0
  390. */
  391. public function orderDownIcon($i, $n, $condition = true, $task = 'orderdown', $alt = 'JGrid_Move_Down', $enabled = true)
  392. {
  393. $alt = JText::_($alt);
  394. $html = '&nbsp;';
  395. if (($i < $n -1 || $i + $this->limitstart < $this->total - 1) && $condition)
  396. {
  397. if ($enabled) {
  398. $html = '<a href="#reorder" onclick="return listItemTask(\'cb'.$i.'\',\''.$task.'\')" title="'.$alt.'">';
  399. $html .= JHTML::_('image', 'admin/downarrow.png', $alt, array( 'width' => 16, 'height' => 16, 'border' =>0), true);
  400. $html .= '</a>';
  401. } else {
  402. $html = JHTML::_('image', 'admin/downarrow0.png', $alt, array( 'width' => 16, 'height' => 16, 'border' => 0), true);
  403. }
  404. }
  405. return $html;
  406. }
  407. protected function _list_footer($list)
  408. {
  409. $html = "<div class=\"list-footer\">\n";
  410. $html .= "\n<div class=\"limit\">".JText::_('DISPLAY_NUM').$list['limitfield']."</div>";
  411. $html .= $list['pageslinks'];
  412. $html .= "\n<div class=\"counter\">".$list['pagescounter']."</div>";
  413. $html .= "\n<input type=\"hidden\" name=\"" . $list['prefix'] . "limitstart\" value=\"".$list['limitstart']."\" />";
  414. $html .= "\n</div>";
  415. return $html;
  416. }
  417. protected function _list_render($list)
  418. {
  419. // Reverse output rendering for right-to-left display.
  420. $html = '&lt;&lt; ';
  421. $html .= $list['start']['data'];
  422. $html .= ' &lt; ';
  423. $html .= $list['previous']['data'];
  424. foreach($list['pages'] as $page) {
  425. $html .= ' '.$page['data'];
  426. }
  427. $html .= ' '. $list['next']['data'];
  428. $html .= ' &gt;';
  429. $html .= ' '. $list['end']['data'];
  430. $html .= ' &gt;&gt;';
  431. return $html;
  432. }
  433. protected function _item_active(&$item)
  434. {
  435. $app = &JFactory::getApplication();
  436. if ($app->isAdmin())
  437. {
  438. if ($item->base > 0) {
  439. return "<a title=\"".$item->text."\" onclick=\"javascript: document.adminForm.." . $this->prefix . "limitstart.value=".$item->base."; submitform();return false;\">".$item->text."</a>";
  440. }
  441. else {
  442. return "<a title=\"".$item->text."\" onclick=\"javascript: document.adminForm.." . $this->prefix . "limitstart.value=0; submitform();return false;\">".$item->text."</a>";
  443. }
  444. }
  445. else {
  446. return "<a title=\"".$item->text."\" href=\"".$item->link."\" class=\"pagenav\">".$item->text."</a>";
  447. }
  448. }
  449. protected function _item_inactive(&$item)
  450. {
  451. $app = &JFactory::getApplication();
  452. if ($app->isAdmin()) {
  453. return "<span>".$item->text."</span>";
  454. }
  455. else {
  456. return "<span class=\"pagenav\">".$item->text."</span>";
  457. }
  458. }
  459. /**
  460. * Create and return the pagination data object.
  461. *
  462. * @return object Pagination data object.
  463. * @since 1.5
  464. */
  465. protected function _buildDataObject()
  466. {
  467. // Initialise variables.
  468. $data = new stdClass();
  469. // Build the additional URL parameters string.
  470. $params = '';
  471. if (!empty($this->_additionalUrlParams))
  472. {
  473. foreach($this->_additionalUrlParams as $key => $value)
  474. {
  475. $params .= '&'.$key.'='.$value;
  476. }
  477. }
  478. $data->all = new JPaginationObject(JText::_('VIEW_ALL'), $this->prefix);
  479. if (!$this->_viewall) {
  480. $data->all->base = '0';
  481. $data->all->link = JRoute::_($params.'&'.$this->prefix.'limitstart=');
  482. }
  483. // Set the start and previous data objects.
  484. $data->start = new JPaginationObject(JText::_('Start'), $this->prefix);
  485. $data->previous = new JPaginationObject(JText::_('Prev'), $this->prefix);
  486. if ($this->get('pages.current') > 1)
  487. {
  488. $page = ($this->get('pages.current') -2) * $this->limit;
  489. //$page = $page == 0 ? '' : $page; //set the empty for removal from route
  490. $data->start->base = '0';
  491. $data->start->link = JRoute::_($params.'&'.$this->prefix.'limitstart=0');
  492. $data->previous->base = $page;
  493. $data->previous->link = JRoute::_($params.'&'.$this->prefix.'limitstart='.$page);
  494. }
  495. // Set the next and end data objects.
  496. $data->next = new JPaginationObject(JText::_('Next'), $this->prefix);
  497. $data->end = new JPaginationObject(JText::_('End'), $this->prefix);
  498. if ($this->get('pages.current') < $this->get('pages.total'))
  499. {
  500. $next = $this->get('pages.current') * $this->limit;
  501. $end = ($this->get('pages.total') -1) * $this->limit;
  502. $data->next->base = $next;
  503. $data->next->link = JRoute::_($params.'&'.$this->prefix.'limitstart='.$next);
  504. $data->end->base = $end;
  505. $data->end->link = JRoute::_($params.'&'.$this->prefix.'limitstart='.$end);
  506. }
  507. $data->pages = array();
  508. $stop = $this->get('pages.stop');
  509. for ($i = $this->get('pages.start'); $i <= $stop; $i ++)
  510. {
  511. $offset = ($i -1) * $this->limit;
  512. //$offset = $offset == 0 ? '' : $offset; //set the empty for removal from route
  513. $data->pages[$i] = new JPaginationObject($i, $this->prefix);
  514. if ($i != $this->get('pages.current') || $this->_viewall)
  515. {
  516. $data->pages[$i]->base = $offset;
  517. $data->pages[$i]->link = JRoute::_($params.'&'.$this->prefix.'limitstart='.$offset);
  518. }
  519. }
  520. return $data;
  521. }
  522. }
  523. /**
  524. * Pagination object representing a particular item in the pagination lists.
  525. *
  526. * @package Joomla.Framework
  527. * @subpackage HTML
  528. * @since 1.5
  529. */
  530. class JPaginationObject extends JObject
  531. {
  532. public $text;
  533. public $base;
  534. public $link;
  535. public $prefix;
  536. public function __construct($text, $prefix = '', $base = null, $link = null)
  537. {
  538. $this->text = $text;
  539. $this->prefix = $prefix;
  540. $this->base = $base;
  541. $this->link = $link;
  542. }
  543. }