1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace Atk4\Ui;
6:
7: use Atk4\Data\Field;
8: use Atk4\Ui\Js\JsExpression;
9:
10: /**
11: * Implement an item per page length selector.
12: * Set as a dropdown menu which contains the number of items per page need.
13: */
14: class ItemsPerPageSelector extends View
15: {
16: public $defaultTemplate = 'pagelength.html';
17: public $ui = 'selection compact dropdown';
18:
19: /** @var list<int> Default page length menu items. */
20: public $pageLengthItems = [10, 100, 1000];
21:
22: /** @var string */
23: public $label = 'Items per page:';
24:
25: /** @var int The current number of item per page. */
26: public $currentIpp;
27:
28: /** @var Callback|null The callback function. */
29: public $cb;
30:
31: private function formatInteger(int $value): string
32: {
33: return $this->getApp()->uiPersistence->typecastSaveField(new Field(['type' => 'integer']), $value);
34: }
35:
36: #[\Override]
37: protected function init(): void
38: {
39: parent::init();
40:
41: Icon::addTo($this)->set('dropdown');
42: $this->template->trySet('Label', $this->label);
43:
44: // CallbackLater will give us time to properly render menu item before final output
45: $this->cb = CallbackLater::addTo($this);
46:
47: if (!$this->currentIpp) {
48: $this->currentIpp = $this->pageLengthItems[0];
49: }
50: $this->set($this->formatInteger($this->currentIpp));
51: }
52:
53: /**
54: * Run callback when an item is select via dropdown menu.
55: * The callback should return a View to be reloaded after an item
56: * has been select.
57: *
58: * @param \Closure(int): (View|void) $fx
59: */
60: public function onPageLengthSelect(\Closure $fx): void
61: {
62: $this->cb->set(function () use ($fx) {
63: $ipp = $this->getApp()->hasRequestQueryParam('ipp') ? (int) $this->getApp()->getRequestQueryParam('ipp') : null;
64: $this->set($this->formatInteger($ipp));
65: $reload = $fx($ipp);
66: if ($reload) {
67: $this->getApp()->terminateJson($reload);
68: }
69: });
70: }
71:
72: #[\Override]
73: protected function renderView(): void
74: {
75: $menuItems = [];
76: foreach ($this->pageLengthItems as $item) {
77: $menuItems[] = ['name' => $this->formatInteger($item), 'value' => $item];
78: }
79:
80: $function = new JsExpression('function (value, text, item) {
81: if (value === undefined || value === \'\' || value === null) {
82: return;
83: }
84: $(this).api({
85: on: \'now\',
86: url: \'' . $this->cb->getUrl() . '\',
87: data: {ipp:value}
88: });
89: }');
90:
91: $this->js(true)->dropdown([
92: 'values' => $menuItems,
93: 'onChange' => $function,
94: ]);
95:
96: parent::renderView();
97: }
98: }
99: