Skip to content

Commit

Permalink
ENH Update page number in the state on reaching the first or the last…
Browse files Browse the repository at this point in the history
… element in a list
  • Loading branch information
Sabina Talipova committed Aug 17, 2022
1 parent a57eeb6 commit b2affc1
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 24 deletions.
126 changes: 102 additions & 24 deletions src/Forms/GridField/GridFieldDetailForm_ItemRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace SilverStripe\Forms\GridField;

use LogicException;
use SilverStripe\Admin\LeftAndMain;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
Expand Down Expand Up @@ -328,7 +329,7 @@ protected function getRightGroupField()
/** @var GridFieldDetailForm $component */
$component = $this->gridField->getConfig()->getComponentByType(GridFieldDetailForm::class);
$paginator = $this->getGridField()->getConfig()->getComponentByType(GridFieldPaginator::class);
$gridState = $this->getStateManager()->getStateFromRequest($this->gridField, $this->getRequest());
$gridState = $this->getGridField()->getState();
if ($component && $paginator && $component->getShowPagination()) {
$previousIsDisabled = !$this->getPreviousRecordID();
$nextIsDisabled = !$this->getNextRecordID();
Expand All @@ -337,8 +338,8 @@ protected function getRightGroupField()
LiteralField::create(
'previous-record',
HTML::createTag($previousIsDisabled ? 'span' : 'a', [
'href' => $previousIsDisabled ? '#' : $this->getEditLink($this->getPreviousRecordID()),
'data-grid-state' => $gridState,
'href' => $previousIsDisabled ? '#' : $this->getEditLinkForAdjacentRecord(-1),
'data-grid-state' => $previousIsDisabled ? $gridState : $this->getGridStateForAdjacentRecord(-1),
'title' => _t(__CLASS__ . '.PREVIOUS', 'Go to previous record'),
'aria-label' => _t(__CLASS__ . '.PREVIOUS', 'Go to previous record'),
'class' => 'btn btn-secondary font-icon-left-open action--previous discard-confirmation'
Expand All @@ -351,8 +352,8 @@ protected function getRightGroupField()
LiteralField::create(
'next-record',
HTML::createTag($nextIsDisabled ? 'span' : 'a', [
'href' => $nextIsDisabled ? '#' : $this->getEditLink($this->getNextRecordID()),
'data-grid-state' => $gridState,
'href' => $nextIsDisabled ? '#' : $this->getEditLinkForAdjacentRecord(+1),
'data-grid-state' => $nextIsDisabled ? $gridState : $this->getGridStateForAdjacentRecord(+1),
'title' => _t(__CLASS__ . '.NEXT', 'Go to next record'),
'aria-label' => _t(__CLASS__ . '.NEXT', 'Go to next record'),
'class' => 'btn btn-secondary font-icon-right-open action--next discard-confirmation'
Expand Down Expand Up @@ -413,8 +414,7 @@ protected function getFormActions()
->addExtraClass('btn-outline-danger btn-hide-outline font-icon-trash-bin action--delete'));
}

$gridState = $manager->getStateFromRequest($this->gridField, $this->getRequest());
$this->gridField->getState(false)->setValue($gridState);
$gridState = $this->gridField->getState(false);
$actions->push(HiddenField::create($manager->getStateKey($this->gridField), null, $gridState));

$actions->push($this->getRightGroupField());
Expand Down Expand Up @@ -561,37 +561,115 @@ public function getEditLink($id)
$id
);

return $this->getStateManager()->addStateToURL($this->gridField, $link);
return $this->gridField->addAllStateToUrl($link);
}

/**
* @param int $offset The offset from the current record
* @return int|bool
* Return array of GridField items on current page plus
* first item on the next page and last item on the previous page
*/
private function getAdjacentRecordID($offset)
private function getGridFieldItemAdjacencies(): array
{
$gridField = $this->getGridField();
$list = $gridField->getManipulatedList();
$state = $gridField->getState(false);
$gridStateStr = $this->getStateManager()->getStateFromRequest($this->gridField, $this->getRequest());
if (!empty($gridStateStr)) {
$state->setValue($gridStateStr);
}
$data = $state->getData();
$paginator = $data->getData('GridFieldPaginator');
$list = $this->getGridField()->getManipulatedList();
$paginator = $this->getGridFieldPaginatorState();
if (!$paginator) {
return false;
return [];
}

$currentPage = $paginator->getData('currentPage');
$itemsPerPage = $paginator->getData('itemsPerPage');

$limit = $itemsPerPage + 2;
$limitOffset = max(0, $itemsPerPage * ($currentPage-1) -1);

$map = $list->limit($limit, $limitOffset)->column('ID');
return $list->limit($limit, $limitOffset)->column('ID');
}

/**
* Get the current paginator state
*/
private function getGridFieldPaginatorState(): GridState_Data
{
$state = $this->getGridField()->getState(false);
$gridStateStr = $this->getStateManager()->getStateFromRequest($this->gridField, $this->getRequest());
if (!empty($gridStateStr)) {
$state->setValue($gridStateStr);
}

return $state->getData()->getData('GridFieldPaginator');
}

/**
* Get the grid state for an adjacent record
*/
private function getGridStateForAdjacentRecord(int $offset): GridState_Data
{
$gridField = $this->getGridField();
$map = $this->getGridFieldItemAdjacencies();
if (empty($map)) {
throw new LogicException('No adjacent records exist');
}

$state = clone $gridField->getState();
$index = array_search($this->record->ID, $map);
$position = $index + $offset;

$currentPage = $this->getGridFieldPaginatorState()->getData('currentPage');
$itemsPerPage = $this->getGridFieldPaginatorState()->getData('itemsPerPage');
$page = $currentPage;
$hasMorePages = $this->getNumPages($gridField) > $currentPage;

if ($position === 0 && $currentPage > 1) {
$page = $currentPage - 1;
} elseif ($hasMorePages && $position >= $itemsPerPage + 1) {
$page = $currentPage + 1;
}
$state->GridFieldPaginator->currentPage = (int)$page;

return $state;
}

/**
* Get the edit link for an adjacent record
*/
private function getEditLinkForAdjacentRecord(int $offset): string
{
$link = Controller::join_links(
$this->gridField->Link(),
'item',
$this->getAdjacentRecordID($offset)
);
$state = $this->getGridStateForAdjacentRecord($offset);
// Get a dummy gridfield so we can set some future state without affecting the current gridfield
$gridField = clone $this->gridField;
$gridField->getState(false)->setValue($state);
return $gridField->addAllStateToUrl($link);
}

/**
* @param int $offset The offset from the current record
* @return int|bool
*/
private function getAdjacentRecordID($offset)
{
$map = $this->getGridFieldItemAdjacencies();
if (empty($map)) {
return false;
}
$index = array_search($this->record->ID, $map ?? []);
return isset($map[$index+$offset]) ? $map[$index+$offset] : false;
$position = $index + $offset;
return isset($map[$position]) ? $map[$position] : false;
}

/**
* Gets the number of GridField pages
*/
public function getNumPages(GridField $gridField): int
{
return $gridField
->getConfig()
->getComponentByType(GridFieldPaginator::class)
->getTemplateParameters($gridField)
->toMap()['NumPages'];
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/Forms/GridField/GridState_Data.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public function __call($name, $arguments)
return $this->getData($name, $default);
}

public function __clone()
{
$this->data = $this->toArray();
}

/**
* Initialise the defaults values for the grid field state
* These values won't be included in getChangesArray()
Expand Down

0 comments on commit b2affc1

Please sign in to comment.