Convert DataGrid form widget in to Grid widget (no longer exclusive to forms)

This commit is contained in:
Sam Georges 2014-07-16 18:48:18 +10:00
parent 3c7c87b338
commit f6fffad37d
19 changed files with 316 additions and 157 deletions

View File

@ -1,5 +1,6 @@
<?php namespace Backend\FormWidgets;
use Backend\Widgets\Grid;
use Backend\Classes\FormWidgetBase;
use System\Classes\ApplicationException;
@ -7,15 +8,6 @@ use System\Classes\ApplicationException;
* Grid
* Renders a grid field.
*
* Supported options:
*
* - allowInsert
* - autoInsertRows
* - allowRemove
* - allowImport
* - allowExport
* - exportFileName
*
* @package october\backend
* @author Alexey Bobkov, Samuel Georges
*/
@ -26,23 +18,24 @@ class DataGrid extends FormWidgetBase
*/
public $defaultAlias = 'datagrid';
/**
* @var array Grid columns
*/
protected $columns = [];
/**
* @var string Grid size
*/
protected $size = 'large';
/**
* @var Backend\Widgets\Grid Grid widget
*/
protected $grid;
/**
* {@inheritDoc}
*/
public function init()
{
$this->columns = $this->getConfig('columns', []);
$this->size = $this->getConfig('size', $this->size);
$this->grid = $this->makeGridWidget();
$this->grid->bindToController();
}
/**
@ -59,125 +52,10 @@ class DataGrid extends FormWidgetBase
*/
public function prepareVars()
{
$this->vars['grid'] = $this->grid;
$this->vars['name'] = $this->formField->getName();
$this->vars['columnHeaders'] = $this->getColumnHeaders();
$this->vars['columnDefinitions'] = $this->getColumnDefinitions();
$this->vars['columnWidths'] = $this->getColumnWidths();
$this->vars['size'] = $this->size;
$this->vars['toolbarWidget'] = $this->makeToolbarWidget();
$this->vars['value'] = json_encode($this->model->{$this->columnName});
}
protected function makeToolbarWidget()
{
$toolbarConfig = $this->makeConfig([
'alias' => $this->alias . 'Toolbar',
'buttons' => $this->getViewPath('_toolbar.htm'),
]);
$toolbarWidget = $this->makeWidget('Backend\Widgets\Toolbar', $toolbarConfig);
return $toolbarWidget;
}
//
// Getters
//
protected function getColumnHeaders()
{
$headers = [];
foreach ($this->columns as $key => $column) {
$headers[] = isset($column['title']) ? $column['title'] : '???';
}
return $headers;
}
protected function getColumnWidths()
{
$widths = [];
foreach ($this->columns as $key => $column) {
$widths[] = isset($column['width']) ? $column['width'] : '0';
}
return $widths;
}
protected function getColumnDefinitions()
{
$definitions = [];
foreach ($this->columns as $key => $column) {
$item = [];
$item['data'] = $key;
if (isset($column['readOnly']))
$item['readOnly'] = $column['readOnly'];
$item = $this->evalColumnType($column, $item);
$definitions[] = $item;
}
return $definitions;
}
protected function evalColumnType($column, $item)
{
if (!isset($column['type']))
return $item;
switch ($column['type']) {
case 'number':
$item['type'] = 'numeric';
break;
case 'currency':
$item['type'] = 'numeric';
$item['format'] = '$0,0.00';
break;
case 'checkbox':
$item['type'] = 'checkbox';
break;
case 'autocomplete':
$item['type'] = 'autocomplete';
if (isset($column['options'])) $item['source'] = $column['options'];
if (isset($column['strict'])) $item['strict'] = $column['strict'];
break;
}
return $item;
}
//
// AJAX
//
public function onAutocomplete()
{
if (!$this->model->methodExists('getGridAutocompleteValues'))
throw new ApplicationException('Model :model does not contain a method getGridAutocompleteValues()');
$field = post('autocomplete_field');
$value = post('autocomplete_value');
$data = post('autocomplete_data', []);
$result = $this->model->getGridAutocompleteValues($field, $value, $data);
if (!is_array($result))
$result = [];
return ['result' => $result];
}
//
// Internals
//
/**
* {@inheritDoc}
*/
public function loadAssets()
{
$this->addCss('vendor/handsontable/jquery.handsontable.css', 'core');
$this->addCss('css/datagrid.css', 'core');
$this->addJs('vendor/handsontable/jquery.handsontable.js', 'core');
$this->addJs('js/datagrid.js', 'core');
$this->vars['value'] = json_encode($this->formField->value);
}
/**
@ -187,4 +65,28 @@ class DataGrid extends FormWidgetBase
{
return json_decode($value);
}
protected function makeGridWidget()
{
$config = $this->makeConfig((array) $this->config);
$config->dataLocker = '#'.$this->getId('dataLocker');
$grid = new Grid($this->controller, $config);
$grid->alias = $this->alias . 'Grid';
$grid->bindEvent('grid.autocomplete', [$this, 'getAutocompleteValues']);
return $grid;
}
public function getAutocompleteValues($field, $value, $data)
{
if (!$this->model->methodExists('getGridAutocompleteValues'))
throw new ApplicationException('Model :model does not contain a method getGridAutocompleteValues()');
$result = $this->model->getGridAutocompleteValues($field, $value, $data);
if (!is_array($result))
$result = [];
return $result;
}
}

View File

@ -2,16 +2,7 @@
id="<?= $this->getId() ?>"
class="field-datagrid size-<?= $size ?>">
<?= $toolbarWidget->render() ?>
<div
id="<?= $this->getId('grid') ?>"
style="width:100%"
class="control-datagrid"
data-control="datagrid"
data-data-locker="#<?= $this->getId('dataLocker') ?>"
data-autocomplete-handler="<?= $this->getEventHandler('onAutocomplete') ?>"
></div>
<?= $grid->render() ?>
<input
type="hidden"
@ -21,9 +12,3 @@
/>
</div>
<script>
$('#<?= $this->getId('grid') ?>')
.data('columns', <?= json_encode($columnDefinitions) ?>)
.data('columnHeaders', <?= json_encode($columnHeaders) ?>)
.data('columnWidths', <?= json_encode($columnWidths) ?>)
</script>

View File

@ -1,6 +0,0 @@
<div data-control="toolbar">
<a href="#" class="btn btn-sm btn-default oc-icon-plus-square" onclick="$(this).closest('.field-datagrid').find('[data-control=datagrid]').dataGrid('insertRow')">Insert Row</a>
<a href="#" class="btn btn-sm btn-default oc-icon-minus-square" onclick="$(this).closest('.field-datagrid').find('[data-control=datagrid]').dataGrid('removeRow')">Delete Row</a>
<!-- <a href="#" class="btn btn-sm btn-default oc-icon-floppy-o">Save as CSV</a> -->
<!-- <a href="#" class="btn btn-sm btn-default oc-icon-upload">Import CSV</a> -->
</div>

View File

@ -0,0 +1,226 @@
<?php namespace Backend\Widgets;
use Backend\Classes\WidgetBase;
/**
* Grid Widget
* Renders a search container used for viewing tabular data
*
* Supported options:
*
* - allowInsert
* - autoInsertRows
* - allowRemove
* - allowImport
* - allowExport
* - exportFileName
*
* @package october\backend
* @author Alexey Bobkov, Samuel Georges
*/
class Grid extends WidgetBase
{
/**
* {@inheritDoc}
*/
public $defaultAlias = 'grid';
/**
* @var array Grid columns
*/
protected $columns = [];
/**
* @var boolean Show data table header
*/
protected $showHeader = true;
/**
* @var boolean Insert row button
*/
protected $allowInsert = true;
/**
* @var boolean Delete row button
*/
protected $allowRemove = true;
/**
* @var boolean Disable the toolbar
*/
protected $disableToolbar = false;
/**
* @var mixed Array of data, or callable for data source.
*/
protected $dataSource;
/**
* @var string HTML element that can [re]store the grid data.
*/
protected $dataLocker;
/**
* Initialize the widget, called by the constructor and free from its parameters.
*/
public function init()
{
$this->columns = $this->getConfig('columns', []);
$this->showHeader = $this->getConfig('showHeader', $this->showHeader);
$this->allowInsert = $this->getConfig('allowInsert', $this->allowInsert);
$this->allowRemove = $this->getConfig('allowRemove', $this->allowRemove);
$this->disableToolbar = $this->getConfig('disableToolbar', $this->disableToolbar);
$this->dataLocker = $this->getConfig('dataLocker', $this->dataLocker);
$this->dataSource = $this->getConfig('dataSource', $this->dataSource);
}
/**
* Renders the widget.
*/
public function render()
{
$this->prepareVars();
return $this->makePartial('grid');
}
/**
* Prepares the view data
*/
public function prepareVars()
{
$this->vars['columnHeaders'] = $this->getColumnHeaders();
$this->vars['columnDefinitions'] = $this->getColumnDefinitions();
$this->vars['columnWidths'] = $this->getColumnWidths();
$this->vars['toolbarWidget'] = $this->makeToolbarWidget();
$this->vars['showHeader'] = $this->showHeader;
$this->vars['allowInsert'] = $this->allowInsert;
$this->vars['allowRemove'] = $this->allowRemove;
$this->vars['disableToolbar'] = $this->disableToolbar;
$this->vars['dataLocker'] = $this->dataLocker;
}
protected function makeToolbarWidget()
{
if ($this->disableToolbar)
return;
$toolbarConfig = $this->makeConfig([
'alias' => $this->alias . 'Toolbar',
'buttons' => $this->getViewPath('_toolbar.htm'),
]);
$toolbarWidget = $this->makeWidget('Backend\Widgets\Toolbar', $toolbarConfig);
$toolbarWidget->vars['allowInsert'] = $this->allowInsert;
$toolbarWidget->vars['allowRemove'] = $this->allowRemove;
return $toolbarWidget;
}
//
// AJAX
//
public function onAutocomplete()
{
$field = post('autocomplete_field');
$value = post('autocomplete_value');
$data = post('autocomplete_data', []);
$result = $this->fireEvent('grid.autocomplete', [$field, $value, $data], true);
return ['result' => $result];
}
public function onDataSource()
{
if ($this->dataLocker)
return;
$result = $this->dataSource;
return ['result' => $result];
}
//
// Getters
//
protected function getColumnHeaders()
{
if (!$this->showHeader)
return false;
$headers = [];
foreach ($this->columns as $key => $column) {
$headers[] = isset($column['title']) ? $column['title'] : '???';
}
return $headers;
}
protected function getColumnWidths()
{
$widths = [];
foreach ($this->columns as $key => $column) {
$widths[] = isset($column['width']) ? $column['width'] : '0';
}
return $widths;
}
protected function getColumnDefinitions()
{
$definitions = [];
foreach ($this->columns as $key => $column) {
$item = [];
$item['data'] = $key;
if (isset($column['readOnly']))
$item['readOnly'] = $column['readOnly'];
$item = $this->evalColumnType($column, $item);
$definitions[] = $item;
}
return $definitions;
}
protected function evalColumnType($column, $item)
{
if (!isset($column['type']))
return $item;
switch ($column['type']) {
case 'number':
$item['type'] = 'numeric';
break;
case 'currency':
$item['type'] = 'numeric';
$item['format'] = '$0,0.00';
break;
case 'checkbox':
$item['type'] = 'checkbox';
break;
case 'autocomplete':
$item['type'] = 'autocomplete';
if (isset($column['options'])) $item['source'] = $column['options'];
if (isset($column['strict'])) $item['strict'] = $column['strict'];
break;
}
return $item;
}
//
// Internals
//
/**
* {@inheritDoc}
*/
public function loadAssets()
{
$this->addCss('vendor/handsontable/jquery.handsontable.css', 'core');
$this->addCss('css/datagrid.css', 'core');
$this->addJs('vendor/handsontable/jquery.handsontable.js', 'core');
$this->addJs('js/datagrid.js', 'core');
}
}

View File

@ -83,6 +83,6 @@ class Toolbar extends WidgetBase
if (!isset($this->config->buttons))
return false;
return $this->controller->makePartial($this->config->buttons);
return $this->controller->makePartial($this->config->buttons, $this->vars);
}
}

View File

@ -37,12 +37,12 @@
startRows: this.options.startRows,
minRows: this.options.minRows,
currentRowClassName: 'currentRow',
// rowHeaders: true,
// rowHeaders: false,
// manualColumnMove: true,
// manualRowMove: true,
fillHandle: false,
multiSelect: false,
removeRowPlugin: true
removeRowPlugin: this.options.allowRemove
}
if (this.options.autoInsertRows)
@ -68,6 +68,13 @@
delete handsontableOptions.data
}
}
else if (this.options.sourceHandler) {
$.request(self.options.sourceHandler, {
success: function(data, textStatus, jqXHR){
self.gridInstance.loadData(data.result)
}
})
}
this.$el.handsontable(handsontableOptions)
this.gridInstance = this.$el.handsontable('getInstance')
@ -138,6 +145,8 @@
columnWidths: null,
columns: null,
autocompleteHandler: null,
sourceHandler: null,
allowRemove: true,
confirmMessage: 'Are you sure?'
}

View File

@ -0,0 +1,23 @@
<div class="datagrid-widget">
<?php if (!$disableToolbar): ?>
<?= $toolbarWidget->render() ?>
<?php endif ?>
<div
id="<?= $this->getId('grid') ?>"
style="width:100%"
class="control-datagrid"
data-control="datagrid"
data-allow-remove="<?= $allowRemove ? 'true' : 'false' ?>"
<?php if ($dataLocker): ?>data-data-locker="<?= $dataLocker ?>"<?php endif ?>
data-autocomplete-handler="<?= $this->getEventHandler('onAutocomplete') ?>"
data-source-handler="<?= $this->getEventHandler('onDataSource') ?>"
></div>
</div>
<script>
$('#<?= $this->getId('grid') ?>')
.data('columns', <?= json_encode($columnDefinitions) ?>)
.data('columnHeaders', <?= json_encode($columnHeaders) ?>)
.data('columnWidths', <?= json_encode($columnWidths) ?>)
</script>

View File

@ -0,0 +1,20 @@
<div data-control="toolbar">
<?php if ($allowInsert): ?>
<a
href="javascript:;"
class="btn btn-sm btn-default oc-icon-plus-square"
onclick="$(this).closest('.datagrid-widget').find('[data-control=datagrid]').dataGrid('insertRow')">
Insert Row
</a>
<?php endif ?>
<?php if ($allowRemove): ?>
<a
href="javascript:;"
class="btn btn-sm btn-default oc-icon-minus-square"
onclick="$(this).closest('.datagrid-widget').find('[data-control=datagrid]').dataGrid('removeRow')">
Delete Row
</a>
<?php endif ?>
<!-- <a href="#" class="btn btn-sm btn-default oc-icon-floppy-o">Save as CSV</a> -->
<!-- <a href="#" class="btn btn-sm btn-default oc-icon-upload">Import CSV</a> -->
</div>