├── LinkPager.php ├── README.md └── composer.json /LinkPager.php: -------------------------------------------------------------------------------- 1 | 22 | */ 23 | class LinkPager extends \yii\widgets\LinkPager 24 | { 25 | /** 26 | * @var string the name of the input checkbox input fields. This will be appended with `[]` to ensure it is an array. 27 | */ 28 | public $separator = '...'; 29 | 30 | /** 31 | * @var boolean turns on|off the tag for the active page. Defaults to true (will be a link). 32 | */ 33 | public $activePageAsLink = true; 34 | 35 | /** 36 | * @inheritdoc 37 | */ 38 | protected function renderPageButtons() 39 | { 40 | $pageCount = $this->pagination->getPageCount(); 41 | if ($pageCount < 2 && $this->hideOnSinglePage) { 42 | return ''; 43 | } 44 | 45 | $buttons = []; 46 | $currentPage = $this->pagination->getPage(); 47 | 48 | // first page 49 | if ($this->firstPageLabel !== false) { 50 | $buttons[] = $this->renderPageButton($this->firstPageLabel, 0, $this->firstPageCssClass, $currentPage <= 0, 51 | false); 52 | } 53 | 54 | // prev page 55 | if ($this->prevPageLabel !== false) { 56 | if (($page = $currentPage - 1) < 0) { 57 | $page = 0; 58 | } 59 | $buttons[] = $this->renderPageButton($this->prevPageLabel, $page, $this->prevPageCssClass, 60 | $currentPage <= 0, false); 61 | } 62 | 63 | // page calculations 64 | list($beginPage, $endPage) = $this->getPageRange(); 65 | $startSeparator = false; 66 | $endSeparator = false; 67 | $beginPage++; 68 | $endPage--; 69 | if ($beginPage != 1) { 70 | $startSeparator = true; 71 | $beginPage++; 72 | } 73 | if ($endPage + 1 != $pageCount - 1) { 74 | $endSeparator = true; 75 | $endPage--; 76 | } 77 | 78 | // smallest page 79 | $buttons[] = $this->renderPageButton(1, 0, null, false, 0 == $currentPage); 80 | 81 | // separator after smallest page 82 | if ($startSeparator) { 83 | $buttons[] = $this->renderPageButton($this->separator, null, null, true, false); 84 | } 85 | // internal pages 86 | for ($i = $beginPage; $i <= $endPage; ++$i) { 87 | if ($i != 0 && $i != $pageCount - 1) { 88 | $buttons[] = $this->renderPageButton($i + 1, $i, null, false, $i == $currentPage); 89 | } 90 | } 91 | // separator before largest page 92 | if ($endSeparator) { 93 | $buttons[] = $this->renderPageButton($this->separator, null, null, true, false); 94 | } 95 | // largest page 96 | $buttons[] = $this->renderPageButton($pageCount, $pageCount - 1, null, false, 97 | $pageCount - 1 == $currentPage); 98 | 99 | // next page 100 | if ($this->nextPageLabel !== false) { 101 | if (($page = $currentPage + 1) >= $pageCount - 1) { 102 | $page = $pageCount - 1; 103 | } 104 | $buttons[] = $this->renderPageButton($this->nextPageLabel, $page, $this->nextPageCssClass, 105 | $currentPage >= $pageCount - 1, false); 106 | } 107 | 108 | // last page 109 | if ($this->lastPageLabel !== false) { 110 | $buttons[] = $this->renderPageButton($this->lastPageLabel, $pageCount - 1, $this->lastPageCssClass, 111 | $currentPage >= $pageCount - 1, false); 112 | } 113 | 114 | return Html::tag('ul', implode("\n", $buttons), $this->options); 115 | } 116 | 117 | /** 118 | * @inheritdoc 119 | */ 120 | protected function renderPageButton($label, $page, $class, $disabled, $active) 121 | { 122 | $options = ['class' => $class === '' ? null : $class]; 123 | if ($active) { 124 | Html::addCssClass($options, $this->activePageCssClass); 125 | } 126 | if ($disabled) { 127 | Html::addCssClass($options, $this->disabledPageCssClass); 128 | 129 | return Html::tag('li', Html::tag('span', $label), $options); 130 | } 131 | $linkOptions = $this->linkOptions; 132 | $linkOptions['data-page'] = $page; 133 | 134 | // active page as anchor or span 135 | if ($active && !$this->activePageAsLink) { 136 | return Html::tag('li', Html::tag('span', $label, $linkOptions), $options); 137 | } 138 | 139 | return Html::tag('li', Html::a($label, $this->pagination->createUrl($page), $linkOptions), $options); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Separated Pager for Yii2 2 | 3 | A Yii2 LinkPager that displays the first and last pages inline with other pages. 4 | 5 | Rather than having dedicated "First" and "Last" buttons in your LinkPager, **Separated Pager** will show a standard set of page links but will also always include the first and last pages as the first and last page links. No more dedicated first/last buttons and no more guessing how many pages there are. 6 | 7 | ![sample](https://cloud.githubusercontent.com/assets/2441889/6312491/6a89be10-b948-11e4-9ac8-bcd793664e1a.png) 8 | 9 | ## Installation 10 | 11 | ### Install the extension 12 | 13 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 14 | 15 | Either run 16 | 17 | ``` 18 | php composer.phar require --prefer-dist justinvoelker/yii2-separatedpager "*" 19 | ``` 20 | 21 | or add 22 | 23 | ``` 24 | "justinvoelker/yii2-separatedpager": "*" 25 | ``` 26 | 27 | to the require section of your `composer.json` file. 28 | 29 | ## Usage 30 | 31 | Simply add the `pager` property to your GridView and reference this class 32 | 33 | ```php 34 | GridView::widget([ 35 | 'dataProvider' => $dataProvider, 36 | ... 37 | 'pager' => [ 38 | 'class' => 'justinvoelker\separatedpager\LinkPager', 39 | ] 40 | ]); 41 | ``` 42 | 43 | Please note that specifying less than 7 pages won't produce useful results. Less than 7 pages of content is acceptable (will look like the standard LinkPager) but limiting the pager to something less than 7 pages will look and work poorly. Five pages and the pager is almost worthless. Less than 5 and it is worthless. 44 | 45 | ## Available Options 46 | 47 | In addition to all of the standard [LinkPager](www.yiiframework.com/doc-2.0/yii-widgets-linkpager.html) properties, one new property has been added, `separator`, that specifies a string to be used to indicate that multiple pages are being omitted. The default separator is `...`. 48 | 49 | Here is my preferred pager setup. A max of 7 pages, 'Previous' and 'Next' buttons spelled out that are hidden on extra-small screens. 50 | 51 | ```php 52 | 'pager' => [ 53 | 'class' => 'justinvoelker\separatedpager\CustomLinkPager', 54 | 'maxButtonCount' => 7, 55 | 'prevPageLabel' => 'Previous', 56 | 'nextPageLabel' => 'Next', 57 | 'prevPageCssClass' => 'prev hidden-xs', 58 | 'nextPageCssClass' => 'next hidden-xs', 59 | 'activePageAsLink' => false, 60 | ] 61 | ``` 62 | 63 | Keep in mind that setting css classes will overwrite the defaults rather than appending to them. If additional classes should be included (such as the 'hidden-xs' above) the original `prev` and `next` should be included as well (this is the same way the standard LinkPager functions). 64 | 65 | Standard LinkPager functionality uses a link for the active page. By setting `activePageAsLink` to false the link can be replaced with a span that looks the same but cannot be clicked. 66 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "justinvoelker/yii2-separatedpager", 3 | "description": "A Yii2 LinkPager that displays the first and last pages inline with other pages.", 4 | "type": "yii2-extension", 5 | "keywords": ["yii2","linkpager","pagination"], 6 | "license": "BSD-3-Clause", 7 | "authors": [ 8 | { 9 | "name": "Justin Voelker", 10 | "email": "justin@justinvoelker.com" 11 | } 12 | ], 13 | "require": { 14 | "yiisoft/yii2": "*" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "justinvoelker\\separatedpager\\": "" 19 | } 20 | } 21 | } 22 | --------------------------------------------------------------------------------