Widget\Filter*: rudimentary filter widgets

Initial implementation, more to come
This commit is contained in:
Thomas Gelf 2014-06-17 14:00:38 +00:00
parent 54e97f114d
commit 21febddad2
4 changed files with 310 additions and 0 deletions

View File

@ -0,0 +1,193 @@
<?php
namespace Icinga\Web\Widget;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterExpression;
use Icinga\Data\Filter\FilterChain;
use Icinga\Web\Url;
/**
* Filter
*/
class FilterEditor extends AbstractWidget
{
/**
* The filter
*
* @var Filter
*/
private $filter;
protected $query;
/**
* @var string
*/
private $selectedIdx;
/**
* Create a new FilterWidget
*
* @param Filter $filter Your filter
*/
public function __construct($props)
{
$this->filter = $props['filter'];
if (array_key_exists('query', $props)) {
$this->query = $props['query'];
}
}
protected function select($name, $list, $selected)
{
$view = $this->view();
$html = '<select name="' . $view->escape($name) . '">';
foreach ($list as $k => $v) {
$active = '';
if ($k === $selected) {
$active = ' selected="selected"';
}
$html .= sprintf(
'<option value="%s"%s>%s</option>',
$view->escape($k),
$active,
$v
);
}
$html .= '</select>';
return $html;
}
public function markIndex($idx)
{
$this->selectedIdx = $idx;
return $this;
}
public function removeIndex($idx)
{
$this->selectedIdx = $idx;
return $this;
}
protected function renderFilter($filter, $level = 0)
{
$html = '';
$url = Url::fromRequest();
$view = $this->view();
$idx = $filter->getId();
$markUrl = clone($url);
$markUrl->setParam('fIdx', $idx);
$removeUrl = clone($url);
$removeUrl->setParam('removeId', $idx);
$removeLink = ' <a href="' . $removeUrl . '" title="'
. $view->escape(t('Click to remove this part of your filter'))
. '">' . $view->icon('remove.png') . '</a>';
$addUrl = clone($url);
$addUrl->setParam('addToId', $idx);
$addLink = ' <a href="' . $addUrl . '" title="'
. $view->escape(t('Click to add... filter'))
. '">' . $view->icon('create.png') . '</a>';
$selectedIndex = ($idx === $this->selectedIdx ? ' -&lt;--' : '');
$selectIndex = ' <a href="' . $markUrl . '">o</a>';
if ($filter instanceof FilterChain) {
$parts = array();
$i = 0;
foreach ($filter->filters() as $f) {
$i++;
$parts[] = $this->renderFilter($f, $level + 1);
}
if (empty($parts)) {
return $html;
}
$op = $this->select(
'operator',
array(
'OR' => 'OR',
'AND' => 'AND',
'NOT' => 'NOT'
),
$filter->getOperatorName()
) . $addLink . $removeLink;
$html .= '<span class="handle"> </span>';
if ($level === 0) {
$html .= $op
. '<ul class="datafilter"><li>'
. implode('</li><li>', $parts)
. '</li></ul>';
} else {
$html .= $op . '<ul><li>' . implode('</li><li>', $parts) . '</li></ul>';
}
return $html;
} elseif ($filter instanceof FilterExpression) {
$u = $url->without($filter->getColumn());
} else {
throw new \Exception('WTF');
}
$value = $filter->getExpression();
if (is_array($value)) {
$value = implode('|', $value);
}
$html .= $this->selectColumn($filter) . ' = <input type="text" name="'
. 'value_' . $idx
. '" value="'
. $value
. '" /> ' . $removeLink;
return $html;
}
protected function arrayForSelect($array)
{
$res = array();
foreach ($array as $k => $v) {
if (is_int($k)) {
$res[$v] = $v;
} else {
$res[$k] = $v;
}
}
// sort($res);
return $res;
}
protected function selectColumn($filter)
{
$name = 'column_' . $filter->getId();
if ($this->query === null) {
return sprintf(
'<input type="text" name="%s" value="%s" />',
$name,
$filter->getColumn()
);
} else {
return $this->select(
$name,
$this->arrayForSelect($this->query->getColumns()),
$filter->getColumn()
);
}
}
public function render()
{
return '<form action="'
. Url::fromRequest()->without('modifyFilter')
. '">'
. $this->renderFilter($this->filter)
. '<input type="submit" name="submit" value="Apply" />'
. '</form>';
}
}

View File

@ -0,0 +1,107 @@
<?php
namespace Icinga\Web\Widget;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterExpression;
use Icinga\Data\Filter\FilterChain;
use Icinga\Web\Url;
/**
* Filter
*/
class FilterWidget extends AbstractWidget
{
/**
* The filter
*
* @var Filter
*/
private $filter;
/**
* The domain of the filter, set in the data-icinga-filter-domain attribute
* @var string
*/
private $domain;
/**
* Create a new FilterWidget
*
* @param Filter $filter Your filter
*/
public function __construct(Filter $filter)
{
$this->filter = $filter;
}
protected function renderFilter($filter, $level = 0)
{
$html = '';
$url = Url::fromRequest();
if ($filter instanceof FilterChain) {
if ($level === 0) {
$op = '</li><li>)' . $filter->getOperatorName() . ' (';
} else {
$op = '</li><li>) ' . $filter->getOperatorName() . ' ( ';
}
$parts = array();
foreach ($filter->filters() as $f) {
$parts[] = $this->renderFilter($f, $level + 1);
}
if (empty($parts)) {
return $html;
}
if ($level === 0) {
$html .= '<ul class="datafilter"><li>( ' . implode($op, $parts) . ' )</li></ul>';
} else {
$html .= '<ul><li>( ' . implode($op, $parts) . ' )</li></ul>';
}
return $html;
} elseif ($filter instanceof FilterExpression) {
$u = $url->without($filter->getColumn());
} else {
$u = $url . '--';
}
$html .= '<a href="' . $url . '" title="'
. $this->view()->escape(t('Click to remove this part of your filter'))
. '">' . $filter . '</a> ';
return $html;
}
public function render()
{
$url = Url::fromRequest();
$html = ' <form method="get" class="inline" action="'
. $url
. '"><input type="text" name="q" style="width: 8em" class="search" value="" placeholder="'
. t('Add filter...')
. '" /></form><br />';
// $html .= $this->renderFilter($this->filter);
$editorUrl = clone $url;
$editorUrl->setParam('modifyFilter', true);
if ($this->filter->isEmpty()) {
$txt = t('Filter');
$title = t('Filter this list');
$remove = '';
} else {
$txt = t('Filtered');
$title = t('Modify this filter');
$remove = ' <a href="'
. Url::fromRequest()->setParams(array())
. '" title="'
. t('Remove this filter')
. '">'
. t('remove')
. '</a>';
}
$filter = $this->filter->isEmpty() ? '' : ': ' . $this->filter;
$html .= '<a href="' . $editorUrl . '">' . $this->view()->escape($txt) . '</a>'
. $filter . $remove;
return $html;
}
}

View File

@ -451,6 +451,15 @@ class Monitoring_ListController extends Controller
$filter = Filter::fromQueryString((string) $params);
$query->applyFilter($filter);
if ($modifyFilter) {
$this->view->filterWidget = Widget::create('filterEditor', array(
'filter' => $filter,
'query' => $query
));
} else {
$this->view->filterWidget = Widget::create('filterWidget', $filter);
}
$this->view->filter = $filter;
if ($sort) {
$query->order($sort, $dir);
}

View File

@ -6,6 +6,7 @@ if (!$this->compact): ?>
<?= $this->tabs ?>
<div style="margin: 1em;" class="dontprint">
<?= $this->translate('Sort by') ?> <?= $this->sortControl ?>
<?= $this->filterWidget ?><br />
</div>
<?= $this->paginationControl($services, null, null, array('preserve' => $this->preserve)) ?>