1515class Pagination extends HtmlElement
1616{
1717 private $ currentPage ;
18- private $ itemTotal ;
18+ private $ totalItems ;
1919 private $ linkPrefix ;
20- private $ itemLimit ;
21- private $ pageLimit ;
22-
23- public function __construct ($ currentPage , $ itemTotal , $ linkPrefix = "/feed/page " , $ itemLimit = 10 , $ pageLimit = 7 )
20+ private $ totalItemsPerPage ;
21+ private $ middleLimit ;
22+
23+ public function __construct (
24+ $ currentPage ,
25+ $ totalItems ,
26+ $ linkPrefix = "/feed/page " ,
27+ $ totalItemsPerPage = 10 ,
28+ $ middleLimit = 5
29+ )
2430 {
31+ $ this ->totalItems = Type::sanitizeType ($ totalItems , ESInt::class);
32+ $ this ->totalItemsPerPage = Type::sanitizeType ($ totalItemsPerPage , ESInt::class);
33+ $ this ->middleLimit = Type::sanitizeType ($ middleLimit , ESInt::class)
34+ ->isOdd (function ($ result , $ int ) {
35+ return ($ result ) ? $ int : $ int ->plus (1 );
36+ });
37+
2538 $ this ->currentPage = Type::sanitizeType ($ currentPage , ESInt::class);
26- $ this -> itemTotal = Type:: sanitizeType ( $ itemTotal , ESInt::class);
39+
2740 $ this ->linkPrefix = Type::sanitizeType ($ linkPrefix , ESString::class);
28- $ this ->itemLimit = Type::sanitizeType ($ itemLimit , ESInt::class);
29- $ this ->pageLimit = Type::sanitizeType ($ pageLimit , ESInt::class);
3041 }
3142
32- public function pageCount (): ESInt
43+ public function totalItems (): ESInt
44+ {
45+ return $ this ->totalItems ;
46+ }
47+
48+ public function totalItemsPerPage (): ESInt
49+ {
50+ return $ this ->totalItemsPerPage ;
51+ }
52+
53+ public function middleLimit ()
54+ {
55+ return $ this ->middleLimit ;
56+ }
57+
58+ public function currentPage (): ESInt
59+ {
60+ return $ this ->currentPage ;
61+ }
62+
63+ public function linkPrefix (): ESString
3364 {
34- return Shoop:: int ( $ this ->itemTotal )-> roundUp ( $ this -> itemLimit ) ;
65+ return $ this ->linkPrefix ;
3566 }
3667
37- public function hasHiddenPages (): ESBool
68+ public function totalPages (): ESInt
3869 {
39- return $ this ->pageCount ()->isGreaterThan ($ this ->pageLimit );
70+ return Shoop::int ($ this ->totalItems ())->roundUp ($ this ->totalItemsPerPage );
71+ }
72+
73+ public function totalLinksToDisplay ()
74+ {
75+ $ total = $ this ->totalItems ()->roundDown ($ this ->totalItemsPerPage ());
76+ if ($ total ->isGreaterThanUnfolded ($ this ->middleLimit ())) {
77+ return $ this ->middleLimit ()->plus (2 );
78+ }
79+ return $ this ->totalItems ()->roundDown ($ this ->totalItemsPerPage ());
80+ }
81+
82+ public function totalMiddleSurrounding ()
83+ {
84+ return $ this ->middleLimit ()->roundDown (2 );
85+ }
86+ public function firstPageNumber ()
87+ {
88+ return Shoop::int (1 );
89+ }
90+
91+ public function lastPageNumber ()
92+ {
93+ return $ this ->totalPages ();
94+ }
95+
96+ public function secondPageNumber ()
97+ {
98+ if ($ this ->totalLinksToDisplay ()->isLessThanOrEqualUnfolded (2 )) {
99+ // if the number of pages is less than or equal to 2 always return 0
100+ return Shoop::int (0 );
101+
102+ } elseif ($ this ->currentPage ()->minus ($ this ->totalMiddleSurrounding ())->isLessThanOrEqualUnfolded (2 )) {
103+ // if the number of pages is less than middleLimit + 2 always return 2
104+ // 1 2 3 4 5* 6 ... 10
105+ return Shoop::int (2 );
106+
107+ } elseif ($ this ->currentPage ()->isGreaterThanUnfolded ($ this ->totalPages ()->minus ($ this ->middleLimit ())->plus (1 ))) {
108+ // if the current page is greater than or equal to totalPages - middleLimit + 1 always return
109+ // totalPages - middleLimit + 1
110+ // 1 ... 5 6 7 8* 9 10
111+ return $ this ->totalPages ()->minus ($ this ->middleLimit ());
112+
113+ } else {
114+ // 1 ... 4 5 6* 7 8 ... 10
115+ return $ this ->currentPage ()->minus ($ this ->totalMiddleSurrounding ());
116+
117+ }
118+ }
119+
120+ public function penultimatePageNumber ()
121+ {
122+ if ($ this ->totalLinksToDisplay ()->isLessThanOrEqualUnfolded (2 )) {
123+ // if the number of pages is less than or equal to 2 always return 0
124+ return Shoop::int (0 );
125+
126+ } elseif ($ this ->totalPages ()->isLessThanOrEqualUnfolded ($ this ->firstPageNumber ()->plus ($ this ->totalMiddleSurrounding ()))) {
127+ return $ this ->totalPages ()->minus (1 );
128+
129+ } else {
130+ return $ this ->secondPageNumber ()->plus ($ this ->middleLimit ()->minus (1 ))
131+ ->isGreaterThanOrEqual ($ this ->totalPages (), function ($ result , $ int ) {
132+ if ($ result ) {
133+ return $ this ->totalPages ()->minus (1 );
134+ }
135+ return $ this ->secondPageNumber ()->plus ($ this ->middleLimit ()->minus (1 ));
136+ });
137+ }
138+ }
139+
140+ public function middleRange ()
141+ {
142+ return $ this ->secondPageNumber ()->range ($ this ->penultimatePageNumber ())->noEmpties ();
40143 }
41144
42145 public function unfold (): string
43146 {
44- if ($ this ->pageCount ()->isUnfolded (1 )) {
147+ if ($ this ->totalPages ()->isUnfolded (1 )) {
45148 return "" ;
46149
150+ } elseif ($ this ->totalPages ()->isUnfolded (2 )) {
151+ return UIKit::nav (
152+ UIKit::listWith (...
153+ Shoop::array ([$ this ->anchorFor (1 ), $ this ->anchorFor (2 )])
154+ )
155+ );
156+
47157 }
48158
49- if ($ this ->hasHiddenPages ()->unfold ()) {
50- $ start = 0 ;
51- $ end = 0 ;
52- $ links = Shoop::array ([
53- $ this ->anchorFor ($ this ->currentPage ->plus (1 )),
54- $ this ->anchorFor ($ this ->currentPage ->minus (1 )),
55- $ this ->anchorFor (1 )
56-
57- ])->plus (...
58- $ this ->pageCount ()->minus (2 )->roundDown (2 )
59- ->isOdd (function ($ result , $ int ) use (&$ start , &$ end ) {
60- $ midCount = ($ result ) ? $ int : $ int ->plus (1 );
61- $ endCapCount = $ midCount ->roundDown (2 );
62- $ start = $ this ->currentPage ->minus ($ endCapCount );
63- $ end = $ this ->currentPage ->plus ($ endCapCount );
64- return Shoop::int ($ start )->range ($ end );
65-
66- })->each (function ($ pageNumber ) {
67- return $ this ->anchorFor ($ pageNumber );
68-
69- })
70- )->plus (
71- $ this ->anchorFor ($ this ->pageCount ())
159+ $ previous = $ this ->anchorFor (1 );
160+ if ($ this ->currentPage ()->minus (1 )->isGreaterThanUnfolded (1 )) {
161+ $ previous = $ this ->anchorFor ($ this ->currentPage ()->minus (1 ));
72162
73- );
74- $ class = "has-hidden-pages " ;
75- if ($ start ->minus (1 )->is (1 )->unfold () and $ end ->plus (1 )->isNot ($ this ->pageCount ())->unfold ()) {
76- $ class = "has-hidden-pages-next " ;
163+ } elseif ($ this ->currentPage ()->isUnfolded (1 )) {
164+ $ previous = "" ;
77165
78- } elseif ($ start ->minus (1 )->isNot (1 )->unfold () and $ end ->plus (1 )->is ($ this ->pageCount ())->unfold ()) {
79- $ class = "has-hidden-pages-previous " ;
166+ }
80167
81- }
82- return UIKit:: nav (UIKit:: listWith (... $ links ))
83- -> attr ( " class { $ class }" , " aria-label Pagination navigation " , " role navigation " );
168+ $ next = $ this -> anchorFor ( $ this -> currentPage ()-> plus ( 1 ));
169+ if ( $ this -> currentPage ()-> plus ( 1 )-> isGreaterThanUnfolded ( $ this -> totalPages ())) {
170+ $ next = $ this -> anchorFor ( $ this -> totalPages () );
84171
85- } else {
86- $ links = $ this ->pageCount ()->range (1 )->each (function ($ pageNumber ) {
172+ } elseif ($ this ->currentPage ()->isUnfolded ($ this ->totalPages ())) {
173+ $ next = "" ;
174+
175+ }
176+
177+ $ links = $ this ->secondPageNumber ()->range ($ this ->penultimatePageNumber ())
178+ ->each (function ($ pageNumber ) {
87179 return $ this ->anchorFor ($ pageNumber );
88- });
180+ })->start ($ this ->anchorFor (1 ))->end ($ this ->anchorFor ($ this ->totalPages ()));
181+
182+ $ hasPrevious = $ this ->currentPage ()->isGreaterThanUnfolded (1 );
183+ $ hasNext = $ this ->currentPage ()->isLessThanUnfolded ($ this ->totalPages ());
184+
185+ $ navClass = "class pagination " ; // both
186+ if (! $ hasNext and $ hasPrevious ) {
187+ $ navClass = "class pagination-previous " ;
188+
189+ } elseif ($ hasNext and ! $ hasPrevious ) {
190+ $ navClass = "class pagination-next " ;
89191
90192 }
91- return UIKit::nav (UIKit::listWith (...$ links ))
92- ->attr ("aria-label Pagination navigation " , "role navigation " );
193+
194+ return UIKit::nav (
195+ UIKit::listWith (...
196+ Shoop::array ([$ previous , $ next ])->plus (...$ links )->noEmpties ()
197+ )
198+ )->attr ($ navClass );
93199 }
94200
95- private function anchorFor ($ pageNumber )
201+ private function anchorFor ($ pageNumber, $ isNext = false , $ isPrevious = false )
96202 {
97203 $ pageNumber = Type::sanitizeType ($ pageNumber , ESInt::class)->unfold ();
204+ $ isNext = Type::sanitizeType ($ isNext , ESBool::class)->unfold ();
205+ $ isPrevious = Type::sanitizeType ($ isPrevious , ESBool::class)->unfold ();
98206 $ link = UIKit::anchor (
99207 $ pageNumber ,
100208 $ this ->linkPrefix ->plus ("/ {$ pageNumber }" )
@@ -105,6 +213,13 @@ private function anchorFor($pageNumber)
105213 "aria-current true " ,
106214 "class current "
107215 );
216+
217+ } elseif ($ isNext and ! $ isPrevious ) {
218+ $ link = $ link ->attr ("class next " );
219+
220+ } elseif (! $ isNext and $ isPrevious ) {
221+ $ link = $ link ->attr ("class previous " );
222+
108223 }
109224 return $ link ;
110225 }
0 commit comments