1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
19: abstract class QPaginatorBase extends QControl {
20:
21: protected $strLabelForPrevious;
22:
23: protected $strLabelForNext;
24:
25:
26:
27: protected $intItemsPerPage = 15;
28:
29: protected $intPageNumber = 1;
30:
31: protected $intTotalItemCount = 0;
32:
33: protected $blnUseAjax = true;
34:
35: protected $objPaginatedControl;
36:
37: protected $objWaitIcon = 'default';
38:
39: protected $intIndexCount = 10;
40:
41:
42:
43: protected $prxPagination = null;
44:
45:
46:
47: protected $blnIsBlockElement = false;
48:
49: protected $strTag = 'span';
50:
51:
52:
53:
54: 55: 56: 57: 58: 59: 60: 61: 62:
63: public function __construct($objParentObject, $strControlId = null) {
64: try {
65: parent::__construct($objParentObject, $strControlId);
66: } catch (QCallerException $objExc) {
67: $objExc->IncrementOffset();
68: throw $objExc;
69: }
70:
71: $this->prxPagination = new QControlProxy($this);
72: $this->strLabelForPrevious = QApplication::Translate('Previous');
73: $this->strLabelForNext = QApplication::Translate('Next');
74:
75: $this->Setup();
76: }
77:
78: 79: 80:
81: protected function Setup() {
82:
83: $this->prxPagination->RemoveAllActions(QClickEvent::EventName);
84: if ($this->blnUseAjax) {
85: $this->prxPagination->AddAction(new QClickEvent(), new QAjaxControlAction($this, 'Page_Click'));
86: }
87: else {
88: $this->prxPagination->AddAction(new QClickEvent(), new QServerControlAction($this, 'Page_Click'));
89: }
90: $this->prxPagination->AddAction(new QClickEvent, new QTerminateAction());
91: }
92:
93: public function ParsePostData() {}
94:
95: 96: 97: 98: 99: 100: 101:
102: public function Validate() {return true;}
103:
104: 105: 106: 107: 108: 109: 110:
111: public function Page_Click($strFormId, $strControlId, $strParameter) {
112: $this->objPaginatedControl->PageNumber = QType::Cast($strParameter, QType::Integer);
113: }
114:
115: 116: 117: 118: 119:
120: public function SetPaginatedControl(QPaginatedControl $objPaginatedControl) {
121: $this->objPaginatedControl = $objPaginatedControl;
122:
123: $this->UseAjax = $objPaginatedControl->UseAjax;
124: $this->ItemsPerPage = $objPaginatedControl->ItemsPerPage;
125: $this->PageNumber = $objPaginatedControl->PageNumber;
126: $this->TotalItemCount = $objPaginatedControl->TotalItemCount;
127: }
128:
129:
130: 131: 132: 133: 134: 135: 136:
137: protected function GetPreviousButtonsHtml () {
138: if ($this->intPageNumber <= 1) {
139: $strPrevious = $this->strLabelForPrevious;
140: } else {
141: $mixActionParameter = $this->intPageNumber - 1;
142: $strPrevious = $this->prxPagination->RenderAsLink($this->strLabelForPrevious, $mixActionParameter, ['id'=>$this->ControlId . "_arrow_" . $mixActionParameter]);
143: }
144:
145: $strToReturn = sprintf('<span class="arrow previous">%s</span><span class="break">|</span>', $strPrevious);
146:
147: list($intPageStart, $intPageEnd) = $this->CalcBunch();
148:
149: if ($intPageStart != 1) {
150: $strToReturn .= $this->GetPageButtonHtml(1);
151: $strToReturn .= '<span class="ellipsis">…</span>';
152: }
153:
154: return $strToReturn;
155: }
156:
157:
158: 159: 160: 161: 162: 163:
164: protected function GetPageButtonHtml ($intIndex) {
165: if ($this->intPageNumber == $intIndex) {
166: $strToReturn = sprintf('<span class="selected">%s</span>', $intIndex);
167: } else {
168: $mixActionParameter = $intIndex;
169: $strToReturn = $this->prxPagination->RenderAsLink($intIndex, $mixActionParameter, ['id'=>$this->ControlId . "_page_" . $mixActionParameter]);
170: $strToReturn = sprintf('<span class="page">%s</span>',$strToReturn);
171: }
172: return $strToReturn;
173: }
174:
175: 176: 177: 178:
179: protected function GetNextButtonsHtml() {
180: list($intPageStart, $intPageEnd) = $this->CalcBunch();
181:
182:
183:
184: $intPageCount = $this->PageCount;
185: if ($this->intPageNumber >= $intPageCount) {
186: $strNext = $this->strLabelForNext;
187: } else {
188: $mixActionParameter = $this->intPageNumber + 1;
189: $strNext = $this->prxPagination->RenderAsLink($this->strLabelForNext, $mixActionParameter, ['id'=>$this->ControlId . "_arrow_" . $mixActionParameter]);
190: }
191:
192: $strToReturn = sprintf('<span class="arrow next">%s</span>', $strNext);
193:
194: $strToReturn = '<span class="break">|</span>' . $strToReturn;
195:
196: if ($intPageEnd != $intPageCount) {
197: $strToReturn = $this->GetPageButtonHtml($intPageCount) . $strToReturn;
198: $strToReturn = '<span class="ellipsis">…</span>' . $strToReturn;
199: }
200:
201: return $strToReturn;
202: }
203:
204: 205: 206: 207: 208: 209: 210:
211: public function GetControlHtml() {
212: $this->objPaginatedControl->DataBind();
213:
214: $strToReturn = $this->GetPreviousButtonsHtml();
215:
216: list($intPageStart, $intPageEnd) = $this->CalcBunch();
217:
218: for ($intIndex = $intPageStart; $intIndex <= $intPageEnd; $intIndex++) {
219: $strToReturn .= $this->GetPageButtonHtml($intIndex);
220: }
221:
222: $strToReturn .= $this->GetNextButtonsHtml();
223:
224: $strStyle = $this->GetStyleAttributes();
225: if ($strStyle)
226: $strStyle = sprintf(' style="%s"', $strStyle);
227:
228:
229: $strToReturn = sprintf('<%s id="%s" %s%s>%s</%s>', $this->strTag, $this->strControlId, $strStyle, $this->RenderHtmlAttributes(), $strToReturn, $this->strTag);
230:
231: return $strToReturn;
232: }
233:
234: 235: 236: 237: 238: 239:
240: protected function CalcBunch() {
241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289:
290:
291: $intPageCount = $this->PageCount;
292:
293: if ($intPageCount <= $this->intIndexCount) {
294:
295: $intPageStart = 1;
296: $intPageEnd = $intPageCount;
297: } else {
298: $intMinimumEndOfBunch = min($this->intIndexCount - 2, $intPageCount);
299: $intMaximumStartOfBunch = max($intPageCount - $this->intIndexCount + 3, 1);
300:
301: $intLeftOfBunchCount = floor(($this->intIndexCount - 5) / 2);
302: $intRightOfBunchCount = round(($this->intIndexCount - 5.0) / 2.0);
303:
304: $intLeftBunchTrigger = 4 + $intLeftOfBunchCount;
305: $intRightBunchTrigger = $intMaximumStartOfBunch + round(($this->intIndexCount - 8.0) / 2.0);
306:
307: if ($this->intPageNumber < $intLeftBunchTrigger) {
308: $intPageStart = 1;
309: } else {
310: $intPageStart = min($intMaximumStartOfBunch, $this->intPageNumber - $intLeftOfBunchCount);
311: }
312:
313: if ($this->intPageNumber > $intRightBunchTrigger) {
314: $intPageEnd = $intPageCount;
315: } else {
316: $intPageEnd = max($intMinimumEndOfBunch, $this->intPageNumber + $intRightOfBunchCount);
317: }
318: }
319: return [$intPageStart, $intPageEnd];
320: }
321:
322: 323: 324: 325:
326: public function LimitPageNumber() {
327: $pageCount = $this->CalcPageCount();
328: if ($this->intPageNumber > $pageCount) {
329: if ($pageCount <= 1) {
330: $this->intPageNumber = 1;
331: } else {
332: $this->intPageNumber = $pageCount;
333: }
334: }
335: }
336:
337: 338: 339: 340: 341:
342: public function CalcPageCount() {
343: $intCount = (int) floor($this->intTotalItemCount / $this->intItemsPerPage) +
344: ((($this->intTotalItemCount % $this->intItemsPerPage) != 0) ? 1 : 0);
345: return $intCount;
346:
347: }
348:
349:
350:
351:
352: 353: 354: 355: 356: 357: 358: 359: 360: 361:
362: public function __get($strName) {
363: switch ($strName) {
364:
365: case "ItemsPerPage": return $this->intItemsPerPage;
366: case "PageNumber": return $this->intPageNumber;
367: case "TotalItemCount": return $this->intTotalItemCount;
368: case "UseAjax": return $this->blnUseAjax;
369: case "PageCount":
370: return $this->CalcPageCount();
371: case 'WaitIcon':
372: return $this->objWaitIcon;
373: case "PaginatedControl":
374: return $this->objPaginatedControl;
375: case 'IndexCount':
376: return $this->intIndexCount;
377: case 'LabelForNext':
378: return $this->strLabelForNext;
379: case 'LabelForPrevious':
380: return $this->strLabelForPrevious;
381: default:
382: try {
383: return parent::__get($strName);
384: } catch (QCallerException $objExc) {
385: $objExc->IncrementOffset();
386: throw $objExc;
387: }
388: }
389: }
390:
391:
392:
393:
394:
395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406:
407: public function __set($strName, $mixValue) {
408: $this->blnModified = true;
409:
410: switch ($strName) {
411:
412: case "ItemsPerPage":
413: try {
414: if ($mixValue > 0)
415: return ($this->intItemsPerPage = QType::Cast($mixValue, QType::Integer));
416: else
417: return ($this->intItemsPerPage = 10);
418: break;
419: } catch (QInvalidCastException $objExc) {
420: $objExc->IncrementOffset();
421: throw $objExc;
422: }
423:
424: case "PageNumber":
425: try {
426: $intNewPageNum = QType::Cast($mixValue, QType::Integer);
427: } catch (QInvalidCastException $objExc) {
428: $objExc->IncrementOffset();
429: throw $objExc;
430: }
431: if ($intNewPageNum > 1) {
432: return ($this->intPageNumber = $intNewPageNum);
433: } else {
434: return ($this->intPageNumber = 1);
435: }
436: break;
437:
438: case "TotalItemCount":
439: try {
440: if ($mixValue > 0) {
441: $this->intTotalItemCount = QType::Cast($mixValue, QType::Integer);
442: }
443: else {
444: $this->intTotalItemCount = 0;
445: }
446: $this->LimitPageNumber();
447: return $this->intTotalItemCount;
448: break;
449: } catch (QInvalidCastException $objExc) {
450: $objExc->IncrementOffset();
451: throw $objExc;
452: }
453:
454: case "UseAjax":
455: try {
456: $blnToReturn = ($this->blnUseAjax = QType::Cast($mixValue, QType::Boolean));
457: } catch (QInvalidCastException $objExc) {
458: $objExc->IncrementOffset();
459: throw $objExc;
460: }
461:
462:
463: $this->Setup();
464:
465: return $blnToReturn;
466:
467: case 'WaitIcon':
468: try {
469: $mixToReturn = $this->objWaitIcon = $mixValue;
470:
471: $this->Setup();
472: return $mixToReturn;
473: } catch (QCallerException $objExc) {
474: $objExc->IncrementOffset();
475: throw $objExc;
476: }
477:
478: case 'IndexCount':
479: $this->intIndexCount = QType::Cast($mixValue, QType::Integer);
480: if ($this->intIndexCount < 7)
481: throw new QCallerException('Paginator must have an IndexCount >= 7');
482: return $this->intIndexCount;
483:
484: case 'LabelForNext':
485: try {
486: return ($this->strLabelForNext = QType::Cast($mixValue, QType::String));
487: } catch (QCallerException $objExc) {
488: $objExc->IncrementOffset();
489: throw $objExc;
490: }
491: case 'LabelForPrevious':
492: try {
493: return ($this->strLabelForPrevious = QType::Cast($mixValue, QType::String));
494: } catch (QCallerException $objExc) {
495: $objExc->IncrementOffset();
496: throw $objExc;
497: }
498:
499: default:
500: try {
501: return (parent::__set($strName, $mixValue));
502: } catch (QCallerException $objExc) {
503: $objExc->IncrementOffset();
504: throw $objExc;
505: }
506: break;
507: }
508: }
509: }
510: