Skip to content

Commit

Permalink
UI/DataTable: View Controls for the Table (ILIAS-eLearning#6222)
Browse files Browse the repository at this point in the history
* UI: minor format fix in roadmap

* UI/DataTable: integrate ViewControls

---------

Co-authored-by: Richard Klees <[email protected]>
Co-authored-by: Timon Amstutz <[email protected]>
  • Loading branch information
3 people authored Oct 26, 2023
1 parent 7c7dfd5 commit e49f115
Show file tree
Hide file tree
Showing 29 changed files with 585 additions and 209 deletions.
2 changes: 2 additions & 0 deletions Services/Init/classes/Dependencies/InitUIFramework.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ public function init(\ILIAS\DI\Container $c): void
$row_builder = new ILIAS\UI\Implementation\Component\Table\DataRowBuilder();
return new ILIAS\UI\Implementation\Component\Table\Factory(
$c["ui.signal_generator"],
$c['ui.factory.input.viewcontrol'],
$c['ui.factory.input.container.viewcontrol'],
$c["ui.data_factory"],
$c["ui.factory.table.column"],
$c["ui.factory.table.action"],
Expand Down
20 changes: 20 additions & 0 deletions src/Data/Range.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*
*********************************************************************/

declare(strict_types=1);

namespace ILIAS\Data;
Expand Down Expand Up @@ -53,6 +69,10 @@ public function getLength(): int

public function getEnd(): int
{
if ($this->length === PHP_INT_MAX) {
return PHP_INT_MAX;
}

return $this->start + $this->length;
}

Expand Down
4 changes: 2 additions & 2 deletions src/UI/Component/Table/Data.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ public function withNumberOfRows(int $number_of_rows): self;
*/
public function withSelectedOptionalColumns(array $selected_optional_column_ids): self;

public function withOrder(Order $order): self;
public function withRange(Range $range): self;
public function withOrder(?Order $order): self;
public function withRange(?Range $range): self;
public function withFilter(?array $filter): self;
public function withAdditionalParameters(?array $additional_parameters): self;
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,23 @@ function(event, signalData) {
fn($k) => ! in_array($k, $input_names),
ARRAY_FILTER_USE_KEY
);
// The remaining parameters for the view controls need to be stuffed into
// hidden fields, so the browser passes them as query parameters once the
// form is submitted.
foreach ($query_params as $k => $v) {
$tpl->setCurrentBlock('param');
$tpl->setVariable("PARAM_NAME", $k);
$tpl->setVariable("VALUE", $v);
$tpl->parseCurrentBlock();
if (is_array($v)) {
foreach (array_values($v) as $arrv) {
$tpl->setCurrentBlock('param');
$tpl->setVariable("PARAM_NAME", $k . '[]');
$tpl->setVariable("VALUE", $arrv);
$tpl->parseCurrentBlock();
}
} else {
$tpl->setCurrentBlock('param');
$tpl->setVariable("PARAM_NAME", $k);
$tpl->setVariable("VALUE", $v);
$tpl->parseCurrentBlock();
}
}

$inputs = array_map(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Pagination extends ViewControlInput implements VCInterface\Pagination, Has
use ComponentHelper;
use GroupDecorator;

protected const DEFAULT_LIMITS = [5, 10, 25, 50, 100, 250, 500, \PHP_INT_MAX];
public const DEFAULT_LIMITS = [5, 10, 25, 50, 100, 250, 500, \PHP_INT_MAX];
protected const NUMBER_OF_VISIBLE_SECTIONS = 7;

protected Signal $internal_selection_signal;
Expand Down
13 changes: 10 additions & 3 deletions src/UI/Implementation/Component/Input/ViewControl/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,16 @@ protected function renderSortation(Sortation $component, RendererInterface $defa
$component = $component->withAdditionalOnLoadCode(
fn($id) => "$(document).on('{$internal_signal}',
function(event, signal_data) {
let inputs = event.target
.closest('.il-viewcontrol-sortation')
.querySelectorAll('.il-viewcontrol-value > input');
let container;
if(signal_data.options.parent_container) {
container = document.querySelector(
'#' + signal_data.options.parent_container
+ ' .il-viewcontrol-sortation'
);
} else {
container = event.target.closest('.il-viewcontrol-sortation');
}
let inputs = container.querySelectorAll('.il-viewcontrol-value > input');
let val = signal_data.options.value.split(':');
inputs[0].value = val[0];
inputs[1].value = val[1];
Expand Down
124 changes: 106 additions & 18 deletions src/UI/Implementation/Component/Table/Data.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
use ILIAS\UI\Component\Table as T;
use ILIAS\UI\Component\Table\Column\Column;
use ILIAS\UI\Component\Table\Action\Action;
use ILIAS\UI\Component\Input\ViewControl\ViewControl;
use Psr\Http\Message\ServerRequestInterface;
use ILIAS\UI\Implementation\Component\SignalGeneratorInterface;
use ILIAS\UI\Component\Signal;
Expand All @@ -32,11 +31,18 @@
use ILIAS\Data\Factory as DataFactory;
use ILIAS\Data\Order;
use ILIAS\Data\Range;
use ILIAS\UI\Component\Input\ViewControl;
use ILIAS\UI\Component\Input\Container\ViewControl as ViewControlContainer;

class Data extends Table implements T\Data, JSBindable
{
use JavaScriptBindable;

public const VIEWCONTROL_KEY_PAGINATION = 'range';
public const VIEWCONTROL_KEY_ORDERING = 'order';
public const VIEWCONTROL_KEY_FIELDSELECTION = 'selected_optional';


/**
* @var array<string, Column>
*/
Expand Down Expand Up @@ -66,8 +72,8 @@ class Data extends Table implements T\Data, JSBindable
* @var string[]
*/
protected array $selected_optional_column_ids = [];
protected Range $range;
protected Order $order;
protected ?Range $range = null;
protected ?Order $order = null;
protected ?array $filter = null;
protected ?array $additional_parameters = null;

Expand All @@ -76,6 +82,8 @@ class Data extends Table implements T\Data, JSBindable
*/
public function __construct(
SignalGeneratorInterface $signal_generator,
protected ViewControl\Factory $view_control_factory,
protected ViewControlContainer\Factory $view_control_container_factory,
protected DataFactory $data_factory,
protected DataRowBuilder $data_row_builder,
string $title,
Expand All @@ -94,8 +102,6 @@ public function __construct(

$this->columns = $this->enumerateColumns($columns);
$this->selected_optional_column_ids = $this->filterVisibleColumnIds($columns);
$this->order = $this->data_factory->order($this->initialOrder(), Order::ASC);
$this->range = $data_factory->range(0, $this->number_of_rows);
}

/**
Expand Down Expand Up @@ -182,6 +188,7 @@ public function withRequest(ServerRequestInterface $request): self
$clone->request = $request;
return $clone;
}

public function getRequest(): ?ServerRequestInterface
{
return $this->request;
Expand All @@ -193,31 +200,34 @@ public function withNumberOfRows(int $number_of_rows): self
$clone->number_of_rows = $number_of_rows;
return $clone;
}

public function getNumberOfRows(): int
{
return $this->number_of_rows;
}

public function withOrder(Order $order): self
public function withOrder(?Order $order): self
{
$clone = clone $this;
$clone->order = $order;
return $clone;
}

public function getOrder(): Order
{
return $this->order;
return $this->order ?? $this->data_factory->order($this->initialOrder(), Order::ASC);
}

public function withRange(Range $range): self
public function withRange(?Range $range): self
{
$clone = clone $this;
$clone->range = $range;
return $clone;
}

public function getRange(): Range
{
return $this->range;
return $this->range ?? $this->data_factory->range(0, $this->number_of_rows);
}

public function withFilter(?array $filter): self
Expand All @@ -226,6 +236,7 @@ public function withFilter(?array $filter): self
$clone->filter = $filter;
return $clone;
}

public function getFilter(): ?array
{
return $this->filter;
Expand All @@ -237,20 +248,12 @@ public function withAdditionalParameters(?array $additional_parameters): self
$clone->additional_parameters = $additional_parameters;
return $clone;
}

public function getAdditionalParameters(): ?array
{
return $this->additional_parameters;
}

/**
* @return ViewControl[]
*/
public function getViewControls(): array
{
//NYI
return [];
}

public function getMultiActionSignal(): Signal
{
return $this->multi_action_signal;
Expand Down Expand Up @@ -342,4 +345,89 @@ public function getRowBuilder(): DataRowBuilder
->withSingleActions($this->getSingleActions())
->withVisibleColumns($this->getVisibleColumns());
}

/**
* @return array<self, ViewControlContainer\ViewControl>
*/
public function applyViewControls(
array $filter_data,
array $additional_parameters
): array {
$table = $this;
$total_count = $this->getDataRetrieval()->getTotalRowCount($filter_data, $additional_parameters);
$view_controls = $this->getViewControls($total_count);

if ($request = $this->getRequest()) {
$view_controls = $view_controls->withRequest($request);
$data = $view_controls->getData();
$table = $table
->withRange(($data[self::VIEWCONTROL_KEY_PAGINATION] ?? null)?->croppedTo($total_count ?? PHP_INT_MAX))
->withOrder($data[self::VIEWCONTROL_KEY_ORDERING] ?? null)
->withSelectedOptionalColumns($data[self::VIEWCONTROL_KEY_FIELDSELECTION] ?? []);
}

return [
$table
->withFilter($filter_data)
->withAdditionalParameters($additional_parameters),
$view_controls
];
}

protected function getViewControls(?int $total_count = null): ViewControlContainer\ViewControl
{
$view_controls = [
self::VIEWCONTROL_KEY_PAGINATION => $this->getViewControlPagination($total_count),
self::VIEWCONTROL_KEY_ORDERING => $this->getViewControlOrdering(),
self::VIEWCONTROL_KEY_FIELDSELECTION => $this->getViewControlFieldSelection(),
];
$view_controls = array_filter($view_controls);
return $this->view_control_container_factory->standard($view_controls);
}

protected function getViewControlPagination(?int $total_count = null): ?ViewControl\Pagination
{
$smallest_option = current(\ILIAS\UI\Implementation\Component\Input\ViewControl\Pagination::DEFAULT_LIMITS);
if (is_null($total_count) || $total_count >= $smallest_option) {
return $this->view_control_factory->pagination()->withTotalCount($total_count);
}
return null;
}

protected function getViewControlOrdering(): ?ViewControl\Sortation
{
$sortable_visible_cols = array_filter(
$this->getVisibleColumns(),
static fn($c): bool => $c->isSortable()
);
$sort_options = [];
foreach ($sortable_visible_cols as $id => $col) {
$sort_options[$col->getTitle() . ', ' . 'ascending'] = $this->data_factory->order($id, 'ASC');
$sort_options[$col->getTitle() . ', ' . 'decending'] = $this->data_factory->order($id, 'DESC');
}

if ($sort_options !== []) {
return $this->view_control_factory->sortation($sort_options);
}
return null;
}

protected function getViewControlFieldSelection(): ?ViewControl\FieldSelection
{
$optional_cols = array_filter(
$this->getColumns(),
static fn($c): bool => $c->isOptional()
);
if ($optional_cols === []) {
return null;
}

$aspect_options = [];
foreach ($optional_cols as $id => $col) {
$aspect_options[$id] = $col->getTitle();
}

return $this->view_control_factory
->fieldSelection($aspect_options);
}
}
6 changes: 6 additions & 0 deletions src/UI/Implementation/Component/Table/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

use ILIAS\UI\Component\Table as T;
use ILIAS\UI\Implementation\Component\SignalGeneratorInterface;
use ILIAS\UI\Component\Input\ViewControl\Factory as ViewControlFactory;
use ILIAS\UI\Component\Input\Container\ViewControl\Factory as ViewControlContainerFactory;
use ILIAS\Data\Factory as DataFactory;
use Closure;

Expand All @@ -32,6 +34,8 @@ class Factory implements T\Factory
{
public function __construct(
protected SignalGeneratorInterface $signal_generator,
protected ViewControlFactory $view_control_factory,
protected ViewControlContainerFactory $view_control_container_factory,
protected DataFactory $data_factory,
protected T\Column\Factory $column_factory,
protected T\Action\Factory $action_factory,
Expand All @@ -57,6 +61,8 @@ public function data(
): T\Data {
return new Data(
$this->signal_generator,
$this->view_control_factory,
$this->view_control_container_factory,
$this->data_factory,
$this->data_row_builder,
$title,
Expand Down
Loading

0 comments on commit e49f115

Please sign in to comment.