What is the logic behind google's pagination behaviour?
My paginator goes something like this:
[1] 2 3 ... 184 >
< 1 [2] 3 4 ... 184 >
< 1 2 [3] 4 5 ... 184 >
< 1 2 3 [4] 5 6 ... 184 >
< 1 ... 3 4 [5] 6 7 ... 184 >
< 1 ... 4 5 [6] 7 8 ... 184 >
< 1 ... 5 6 [7] 8 9 ... 184 >
< 1 ... 6 7 [8] 9 10 ... 184 >
Here is a live version of the above example: http://www.dev.thomaskile.me/?page=test-zone&module=Paginator.
I know why this is happening; I've set the amount of page numbers to be shown on each side of current page to two (2).
I would rather have the range of numbers to be equal like this:
[1] 2 3 4 5 6 7 8 ... 184 >
< 1 [2] 3 4 5 6 7 ... 184 >
< 1 2 [3] 4 5 6 7 ... 184 >
< 1 2 3 [4] 5 6 7 ... 184 >
< 1 ... 3 4 [5] 6 7 ... 184 >
< 1 ... 4 5 [6] 7 8 ... 184 >
< 1 ... 5 6 [7] 8 9 ... 184 >
< 1 ... 6 7 [8] 9 10 ... 184 >
It's at the beginning and the end I need to make some changes, but can't figure out how to make it an easy operation...
I would like to make it flexible as well. Meaning I would like to be able to change the number of wanted pages on each side, and have the script expand and calculate it all...
Here is my code so far:
/**
* page controller buttons
* @param str $this->querySting href="URL string"
* @param str $this->pageIdentifier $_GET['this-name']
* @param int $this->numPages Total amount of pages
* @param int $this->midRange Number of pages to show on each side of current page
*/
public function prevPage()
{
if ($this->currentPage > 1){
$prevPage = ($this->currentPage - 1);
return '<a href="'.$this->queryString.'&'.$this->pageIdentifier.'='.$prevPage.'" class="prev">prev</a>';
}
}
public function nextPage()
{
if ($this->currentPage < $this->numPages) {
$nextPage = $this->currentPage + 1;
return '<a href="'.$this->queryString.'&'.$this->pageIdentifier.'='.$nextPage.'" class="next">next</a>';
}
}
public function firstPage()
{
if ($this->currentPage > ($this->midRange + 1)) { // if number of pages between "currentPage" and "firstPage" exceeds $midRange with 1...
$firstPage .= '<a href="'.$this->queryString.'&'.$this->pageIdentifier.'=1" class="first">1</a>'; // ...show "first page"-link
if ($this->currentPage > ($this->midRange + 2)) { // if number of pages between $currentPage and "first page" exceeds $midRange with more than 1
$firstPage .= '…'; // add "..." between "1st page"-link and first page in $range
}
}
return $firstPage;
}
public function lastPage()
{
if ($this->currentPage < ($this->numPages - $this->midRange)) { // if number of pages between "currentPage" and "last page" is equal to $midRange
if (($this->currentPage < ($this->numPages - $this->midRange) - 1)) { // if number of pages between $currentPage and "last page" exceeds $range with more than two
$lastPage .= '…'; // add "..." between "last page"-link and last page in $range
}
$lastPage .= '<a href="'.$this->queryString.'&'.$this->pageIdentifier.'='.$this->numPages.'" class="last">'.$this->numPages.'</a>'; // show "last page"-link
}
return $lastPage;
}
# Range of pages between (prev first ...) and (... last next)
public function listPages()
{
for ($i = ($this->currentPage - $this->midRange); $i < (($this->currentPage + $this->midRange) + 1); $i++){
if (($i > 0) && ($i <= $this->numPages)) // if page number are within page range
{
if ($i == $this->currentPage) { $listPages .= '<a class="current">'.$i.'</a>'; } // if we're on current page
else { $listPages .= '<a href="'.$this->queryString.'&'.$this->pageIdentifier.'='.$i.'">'.$i.'</a>'; } // if not current page
}
}
return $listPages;
}
This is what I do for my Pagination.
I believe my code is self-explained, but I will try to explain it in plain English. First of all, you need to know two things before you can generate Pagination: $totalPage and $currentPage.
Step 1: Assuming that the current page is in mid-range. $startPage and $endPage store range of page that pagination try to generate.
Step 2: If $startPage is negative, then you need to make-up for $endPage.
Step 3: If $endPage excess $totalPage, then $endPage is the last page.
Step 4: Generating Pagination into HTML. (it is up to you how you want your pagination to look. I will simply use plain text to represent my pagination)
Fixed flaw to my previous logic
This conversation was a great start for me! But I wanted a paginator closer to the intentions of the original question, that:
1) Could be contained in a function with variables to alter the total pages, current page, and number of pages on each side of the current to show.
2) Maintains a constant width, similar to the original post:
3) Continues to display the number "2" rather than "..." in cases where you would have 1 ... 3
4) Same thing for the end.
So here's what I did. I am coding in a different language (coffeescript), but it should function as good sudo-code anyway:
I am using this code for each_side = 2, so that's where I'm sure it works.
EDIT: fixed logic as per @Vextil
This is pure awesome! I think I got this paginator to work the way I described.
Please, have a look and try it out here http://dev.thomaskile.me/?page=test-zone&module=Paginator and let me know...
After a lot of logical math studying I finally came to this conclusion:
In order to make this act so differently on different levels, there have to be some
if
,elsef
-s to handle the logic on each level seperatly. I'll try to explain, but find it hard to do in a good way...These are the levels I'm talking about:
If currentPage == firstPage :
Calculate how many pages to show after currentPage starting from 2nd page.
This calculation needed to be done based on how many page boxes there would be at the most. (midRange value is a key factor here)
elseif currentPage is in between firstPage and midRange value maxed out.
Reduce pages in range by one to prevent moving the whole paginator to the right once prevPage is added. Calculate pages to show before and after currentPage to keep the amount of pages equal trough the whole thing.
elseif midRange value is maxed out on each side. Meaning we're in the middle somewhere.
midRange pages + the current page + midRange pages. Quite straight forward i guess...
elseif currentPage is in between midRange value and lastPage
Almost the same as in the beginning. Difference was to calculate a static pagenumber to start pages from, then calculate pages to show before/after current page...
(this, by the way, has been my headache this weekend)
elseif currentPage == numPages (number of tatal pages). Pretty much same as firstPage operation... calculating how many pages needed to fill the whole thing up and calculate where to start from...
What I need to do now is to make the code itself better...
The "problem" in my case was that the whole paginator should calculate everything based on the midRange value and nothing else. For me to execute this paginator in any of my future project, all I have to do is:
I might in most cases need to add a personal querystring to make sure the
a href
is working:And that's pretty much all. I've set up a couple of optional functions like this:
Finally i display the paginator page controller like this:
If non of these are good enough, i could just call each button like this:
This is the pagination logic I have
The result would be look like this:
Here's a Python program that shows how to do this correctly:
I assume your pagination have this structure:
number_of_active_page + separate(...) + page(184) + next_page(>)
You can set number_of_active_page become 8 ( include prev_page(<) + pages ( ... and page number )