/** * Builds pagination links for HTML display. * * The pagination is quite configurable, but at the same time gives a consistent * look and feel to all pagination. * * This function takes one array that contains the options to configure the * pagination. Required options include: * * - url: The base URL to use for all links * - count: The total number of results to paginate for * - limit: How many to show per page * - offset: At which result to start showing results * * Optional options include: * * - id: The ID of the div enclosing the pagination * - class: The class of the div enclosing the pagination * - offsetname: The name of the offset parameter in the url * - firsttext: The text to use for the 'first page' link * - previoustext: The text to use for the 'previous page' link * - nexttext: The text to use for the 'next page' link * - lasttext: The text to use for the 'last page' link * - numbersincludefirstlast: Whether the page numbering should include links * for the first and last pages * - resultcounttextsingular: The text to use for 'result' * - resultcounttextplural: The text to use for 'results' * * Optional options to support javascript pagination include: * * - datatable: The ID of the table whose TBODY's rows will be replaced with the * resulting rows * - jsonscript: The script to make a json request to in order to retrieve * both the new rows and the new pagination. See js/artefactchooser.json.php * for an example. Note that the paginator javascript library is NOT * automatically included just because you call this function, so make sure * that your smarty() call hooks it in. * * @param array $params Options for the pagination */ function build_pagination($params) { // Bail if the required attributes are not present $required = array('url', 'count', 'limit', 'offset'); foreach ($required as $option) { if (!isset($params[$option])) { throw new ParameterException('You must supply option "' . $option . '" to build_pagination'); } } // Work out default values for parameters if (!isset($params['id'])) { $params['id'] = substr(md5(microtime()), 0, 4); } $params['offsetname'] = isset($params['offsetname']) ? $params['offsetname'] : 'offset'; if (isset($params['forceoffset']) && !is_null($params['forceoffset'])) { $params['offset'] = (int) $params['forceoffset']; } else { if (!isset($params['offset'])) { $params['offset'] = param_integer($params['offsetname'], 0); } } // Correct for odd offsets $params['offset'] -= $params['offset'] % $params['limit']; $params['firsttext'] = isset($params['firsttext']) ? $params['firsttext'] : get_string('first'); $params['previoustext'] = isset($params['previoustext']) ? $params['previoustext'] : get_string('previous'); $params['nexttext'] = isset($params['nexttext']) ? $params['nexttext'] : get_string('next'); $params['lasttext'] = isset($params['lasttext']) ? $params['lasttext'] : get_string('last'); $params['resultcounttextsingular'] = isset($params['resultcounttextsingular']) ? $params['resultcounttextsingular'] : get_string('result'); $params['resultcounttextplural'] = isset($params['resultcounttextplural']) ? $params['resultcounttextplural'] : get_string('results'); if (!isset($params['numbersincludefirstlast'])) { $params['numbersincludefirstlast'] = true; } if (!isset($params['numbersincludeprevnext'])) { $params['numbersincludeprevnext'] = true; } if (!isset($params['extradata'])) { $params['extradata'] = null; } // Begin building the output $output = '<div id="' . $params['id'] . '" class="pagination'; if (isset($params['class'])) { $output .= ' ' . hsc($params['class']); } $output .= '">'; if ($params['limit'] <= $params['count']) { $pages = ceil($params['count'] / $params['limit']); $page = $params['offset'] / $params['limit']; $last = $pages - 1; if (!empty($params['lastpage'])) { $page = $last; } $next = min($last, $page + 1); $prev = max(0, $page - 1); // Build a list of what pagenumbers will be put between the previous/next links $pagenumbers = array(); if ($params['numbersincludefirstlast']) { $pagenumbers[] = 0; } if ($params['numbersincludeprevnext']) { $pagenumbers[] = $prev; } $pagenumbers[] = $page; if ($params['numbersincludeprevnext']) { $pagenumbers[] = $next; } if ($params['numbersincludefirstlast']) { $pagenumbers[] = $last; } $pagenumbers = array_unique($pagenumbers); // Build the first/previous links $isfirst = $page == 0; $output .= build_pagination_pagelink('first', $params['url'], 0, '« ' . $params['firsttext'], get_string('firstpage'), $isfirst, $params['offsetname']); $output .= build_pagination_pagelink('prev', $params['url'], $params['limit'] * $prev, '← ' . $params['previoustext'], get_string('prevpage'), $isfirst, $params['offsetname']); // Build the pagenumbers in the middle foreach ($pagenumbers as $k => $i) { if ($k != 0 && $prevpagenum < $i - 1) { $output .= '…'; } if ($i == $page) { $output .= '<span class="selected">' . ($i + 1) . '</span>'; } else { $output .= build_pagination_pagelink('', $params['url'], $params['limit'] * $i, $i + 1, '', false, $params['offsetname']); } $prevpagenum = $i; } // Build the next/last links $islast = $page == $last; $output .= build_pagination_pagelink('next', $params['url'], $params['limit'] * $next, $params['nexttext'] . ' →', get_string('nextpage'), $islast, $params['offsetname']); $output .= build_pagination_pagelink('last', $params['url'], $params['limit'] * $last, $params['lasttext'] . ' »', get_string('lastpage'), $islast, $params['offsetname']); } // Work out what javascript we need for the paginator $js = ''; if (isset($params['jsonscript']) && isset($params['datatable'])) { $paginator_js = hsc(get_config('wwwroot') . 'js/paginator.js'); $id = json_encode($params['id']); $datatable = json_encode($params['datatable']); $jsonscript = json_encode($params['jsonscript']); $extradata = json_encode($params['extradata']); $js .= "new Paginator({$id}, {$datatable}, {$jsonscript}, {$extradata});"; } // Output the count of results $resultsstr = $params['count'] == 1 ? $params['resultcounttextsingular'] : $params['resultcounttextplural']; $output .= '<div class="results">' . $params['count'] . ' ' . $resultsstr . '</div>'; // Close the container div $output .= '</div>'; return array('html' => $output, 'javascript' => $js); }
/** * Builds pagination links for HTML display. * * The pagination is quite configurable, but at the same time gives a consistent * look and feel to all pagination. * * This function takes one array that contains the options to configure the * pagination. Required options include: * * - url: The base URL to use for all links (it should not contain special characters) * - count: The total number of results to paginate for * - setlimit: toggle variable for enabling/disabling limit dropbox, default value = false * - limit: How many to show per page * - offset: At which result to start showing results * * Optional options include: * * - id: The ID of the div enclosing the pagination * - class: The class of the div enclosing the pagination * - offsetname: The name of the offset parameter in the url * - firsttext: The text to use for the 'first page' link * - previoustext: The text to use for the 'previous page' link * - nexttext: The text to use for the 'next page' link * - lasttext: The text to use for the 'last page' link * - numbersincludefirstlast: Whether the page numbering should include links * for the first and last pages * - numbersincludeprevnext: The number of pagelinks, adjacent the the current page, * to include per side * - jumplinks: The maximum number of page jump links to have between first- and current-, and current- and last page * - resultcounttextsingular: The text to use for 'result' * - resultcounttextplural: The text to use for 'results' * - limittext: The text to use for the limitoption, e.g. "Max items per page" or "Page size" * * Optional options to support javascript pagination include: * * - datatable: The ID of the table whose TBODY's rows will be replaced with the * resulting rows * - jsonscript: The script to make a json request to in order to retrieve * both the new rows and the new pagination. See js/artefactchooser.json.php * for an example. Note that the paginator javascript library is NOT * automatically included just because you call this function, so make sure * that your smarty() call hooks it in. * * @param array $params Options for the pagination */ function build_pagination($params) { $limitoptions = array(1, 10, 20, 50, 100, 500); // Bail if the required attributes are not present $required = array('url', 'count', 'limit', 'offset'); foreach ($required as $option) { if (!isset($params[$option])) { throw new ParameterException('You must supply option "' . $option . '" to build_pagination'); } } if (isset($params['setlimit']) && $params['setlimit']) { if (!in_array($params['limit'], $limitoptions)) { $params['limit'] = 10; } if (!isset($params['limittext'])) { $params['limittext'] = get_string('maxitemsperpage1'); } } else { $params['setlimit'] = false; } // Work out default values for parameters if (!isset($params['id'])) { $params['id'] = substr(md5(microtime()), 0, 4); } $params['offsetname'] = isset($params['offsetname']) ? $params['offsetname'] : 'offset'; if (isset($params['forceoffset']) && !is_null($params['forceoffset'])) { $params['offset'] = (int) $params['forceoffset']; } else { if (!isset($params['offset'])) { $params['offset'] = param_integer($params['offsetname'], 0); } } // Correct for odd offsets if ($params['limit']) { $params['offset'] -= $params['offset'] % $params['limit']; } $params['firsttext'] = isset($params['firsttext']) ? $params['firsttext'] : get_string('first'); $params['previoustext'] = isset($params['previoustext']) ? $params['previoustext'] : get_string('previous'); $params['nexttext'] = isset($params['nexttext']) ? $params['nexttext'] : get_string('next'); $params['lasttext'] = isset($params['lasttext']) ? $params['lasttext'] : get_string('last'); $params['resultcounttextsingular'] = isset($params['resultcounttextsingular']) ? $params['resultcounttextsingular'] : get_string('result'); $params['resultcounttextplural'] = isset($params['resultcounttextplural']) ? $params['resultcounttextplural'] : get_string('results'); if (!isset($params['numbersincludefirstlast'])) { $params['numbersincludefirstlast'] = true; } if (!isset($params['numbersincludeprevnext'])) { $params['numbersincludeprevnext'] = 1; } else { $params['numbersincludeprevnext'] = (int) $params['numbersincludeprevnext']; } if (!isset($params['extradata'])) { $params['extradata'] = null; } // Begin building the output $output = '<div id="' . $params['id'] . '" class="pagination-wrapper'; if (isset($params['class'])) { $output .= ' ' . hsc($params['class']); } $output .= '">'; // Output the count of results $resultsstr = $params['count'] == 1 ? $params['resultcounttextsingular'] : $params['resultcounttextplural']; if ($params['count'] > 0) { $output .= '<div class="lead text-small results pull-right">' . $params['count'] . ' ' . $resultsstr . '</div>'; } $output .= '<ul class="pagination pagination-xs">'; if ($params['limit'] && $params['limit'] < $params['count']) { $pages = ceil($params['count'] / $params['limit']); $page = $params['offset'] / $params['limit']; $last = $pages - 1; if (!empty($params['lastpage'])) { $page = $last; } $prev = max(0, $page - 1); $next = min($last, $page + 1); // Build a list of what pagenumbers will be put between the previous/next links $pagenumbers = array(); // First page if ($params['numbersincludefirstlast']) { $pagenumbers[] = 0; } $maxjumplinks = isset($params['jumplinks']) ? (int) $params['jumplinks'] : 0; // Jump pages between first page and current page $betweencount = $page; $jumplinks = $pages ? round($maxjumplinks * ($betweencount / $pages)) : 0; $jumpcount = $jumplinks ? round($betweencount / ($jumplinks + 1)) : 0; $gapcount = 1; if ($jumpcount > 1) { for ($bc = 1; $bc < $betweencount; $bc++) { if ($gapcount > $jumpcount) { $pagenumbers[] = $bc; $gapcount = 1; } $gapcount++; } } // Current page with adjacent prev and next pages if ($params['numbersincludeprevnext'] > 0) { for ($i = 1; $i <= $params['numbersincludeprevnext']; $i++) { $prevlink = $page - $i; if ($prevlink < 0) { break; } $pagenumbers[] = $prevlink; } unset($prevlink); } $pagenumbers[] = $page; if ($params['numbersincludeprevnext'] > 0) { for ($i = 1; $i <= $params['numbersincludeprevnext']; $i++) { $nextlink = $page + $i; if ($nextlink > $last) { break; } $pagenumbers[] = $nextlink; } } // Jump pages between current and last $betweencount = $pages - $page; $jumplinks = $pages ? round($maxjumplinks * ($betweencount / $pages)) : 0; $jumpcount = $jumplinks ? round($betweencount / ($jumplinks + 1)) : 0; $gapcount = 1; if ($jumpcount > 1) { for ($bc = $page; $bc < $last; $bc++) { if ($gapcount > $jumpcount) { $pagenumbers[] = $bc; $gapcount = 1; } $gapcount++; } } // Last page if ($params['numbersincludefirstlast']) { $pagenumbers[] = $last; } $pagenumbers = array_unique($pagenumbers); sort($pagenumbers); // Build the first/previous links $isfirst = $page == 0; $output .= build_pagination_pagelink('', '«', get_string('prevpage'), $isfirst, $params['url'], $params['setlimit'], $params['limit'], $params['limit'] * $prev, $params['offsetname']); // Build the pagenumbers in the middle foreach ($pagenumbers as $k => $i) { // add ellipsis if pages skipped $text = $i + 1; if ($k != 0 && $prevpagenum < $i - 1) { $text = $i + 1 . '<span class="metadata hidden-xs">...</span>'; } if ($i == $page) { $output .= build_pagination_pagelink('active', $text, '', true); } else { $output .= build_pagination_pagelink('', $text, '', false, $params['url'], $params['setlimit'], $params['limit'], $params['limit'] * $i, $params['offsetname']); } $prevpagenum = $i; } // Build the next/last links $islast = $page == $last; $output .= build_pagination_pagelink('', ' »', get_string('nextpage'), $islast, $params['url'], $params['setlimit'], $params['limit'], $params['limit'] * $next, $params['offsetname']); } // Build limitoptions dropbox if results are more than 10 (minimum dropbox pagination) if ($params['setlimit'] && $params['count'] > 10) { $strlimitoptions = array(); $limit = $params['limit']; for ($i = 0; $i < count($limitoptions); $i++) { if ($limit == $limitoptions[$i]) { $strlimitoptions[] = "<option value = '{$limit}' selected='selected'> {$limit} </option>"; } else { $strlimitoptions[] = "<option value = '{$limitoptions[$i]}'> {$limitoptions[$i]} </option>"; } } $output .= '</ul>'; $output .= '<form class="form-pagination js-pagination form-inline pagination-page-limit dropdown" action="' . hsc($params['url']) . '" method="POST"> <label for="setlimitselect" class="set-limit"> ' . $params['limittext'] . ' </label>' . '<span class="picker input-sm"><select id="setlimitselect" class="js-pagination input-sm select form-control" name="limit"> ' . join(' ', $strlimitoptions) . '</select></span> <input class="currentoffset" type="hidden" name="' . $params['offsetname'] . '" value="' . $params['offset'] . '"/> <input class="pagination js-hidden hidden" type="submit" name="submit" value="' . get_string('change') . '"/> </form>'; } else { if ($params['setlimit']) { $output .= '<input type="hidden" id="setlimitselect" name="limit" value="' . $params['limit'] . '">'; } } // Work out what javascript we need for the paginator $js = ''; $id = json_encode($params['id']); if (isset($params['jsonscript']) && isset($params['datatable'])) { $paginator_js = hsc(get_config('wwwroot') . 'js/paginator.js'); $datatable = json_encode($params['datatable']); if (!empty($params['searchresultsheading'])) { $heading = json_encode($params['searchresultsheading']); } else { $heading = 'null'; } $jsonscript = json_encode($params['jsonscript']); $extradata = json_encode($params['extradata']); $js .= "new Paginator({$id}, {$datatable}, {$heading}, {$jsonscript}, {$extradata});"; } else { $js .= "new Paginator({$id}, null, null, null, null);"; } // Close the container div $output .= '</div>'; return array('html' => $output, 'javascript' => $js); }