Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions modules/backend/behaviors/ListController.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ public function makeList($definition = null)
'showPageNumbers',
'noRecordsMessage',
'defaultSort',
'reorder',
'showSorting',
'showSetup',
'showCheckboxes',
Expand All @@ -164,6 +165,9 @@ public function makeList($definition = null)
*/
$widget = $this->makeWidget(\Backend\Widgets\Lists::class, $columnConfig);

$widget->definition = $definition;
$widget->reorderSortMode = $this->reorderGetSortMode($model);

$widget->bindEvent('list.extendColumns', function () use ($widget) {
$this->controller->listExtendColumns($widget);
});
Expand Down Expand Up @@ -599,4 +603,129 @@ public static function extendListFilterScopes($callback)
call_user_func_array($callback, [$widget]);
});
}

protected function reorderGetSortMode($model)
{
$modelTraits = class_uses($model);

if (
isset($modelTraits[\Winter\Storm\Database\Traits\Sortable::class]) ||
$model->isClassExtendedWith(\Winter\Storm\Database\Behaviors\Sortable::class) ||
isset($modelTraits[\October\Rain\Database\Traits\Sortable::class]) ||
$model->isClassExtendedWith(\October\Rain\Database\Behaviors\Sortable::class)
) {
return 'simple';
}
elseif (
isset($modelTraits[\Winter\Storm\Database\Traits\NestedTree::class]) ||
isset($modelTraits[\October\Rain\Database\Traits\NestedTree::class])
) {
return 'nested';
}
else {
return null;
}
}

public function onReorder()
{
$definition = post('definition', $this->primaryDefinition);
$model = $this->listGetModel($definition);
$sortMode = $this->reorderGetSortMode($model);

/*
* Simple
*/
if ($sortMode == 'simple') {
if (
(!$ids = post('record_ids')) ||
(!$orders = post('sort_orders'))
) {
return;
}

$model->setSortableOrder($ids, $orders);
}
/*
* Nested set
*/
elseif ($sortMode == 'nested') {
$sourceNode = $model->find(post('sourceNode'));
$targetNode = post('targetNode') ? $model->find(post('targetNode')) : null;

if ($sourceNode == $targetNode) {
return;
}

switch (post('position')) {
case 'before':
$sourceNode->moveBefore($targetNode);
break;

case 'after':
$sourceNode->moveAfter($targetNode);
break;

case 'child':
$sourceNode->makeChildOf($targetNode);
break;

default:
$sourceNode->makeRoot();
break;
}
}

return $this->listRefresh($definition);
}

public function listGetModel($definition = null)
{
$listConfig = $this->controller->listGetConfig($definition);
$class = $listConfig->modelClass;
return new $class;
}

/**
* Extend the query used for finding reorder records. Extra conditions
* can be applied to the query, for example, $query->withTrashed();
* @param Winter\Storm\Database\Builder $query
* @return void
*/
public function reorderExtendQuery($query)
{
}

/**
* Returns all the records from the supplied model.
* @return Collection
*/
protected function getRecords()
{
$records = null;
$model = $this->controller->listGetModel();
$query = $model->newQuery();

$this->controller->reorderExtendQuery($query);

if ($this->sortMode == 'simple') {
$records = $query
->orderBy($model->getSortOrderColumn())
->get()
;
}
elseif ($this->sortMode == 'nested') {
$records = $query->getNested();
}

return $records;
}

/**
* Returns the sort order value for a specific record.
*/
public function getRecordSortOrder($record)
{
return $record->{$record->getSortOrderColumn()};
}
}
1 change: 1 addition & 0 deletions modules/backend/behaviors/RelationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,7 @@ protected function makeManageWidget()
$config->showCheckboxes = $this->getConfig('manage[showCheckboxes]', !$isPivot);
$config->showSorting = $this->getConfig('manage[showSorting]', !$isPivot);
$config->defaultSort = $this->getConfig('manage[defaultSort]');
$config->sortable = $this->getConfig('view[sortable]', false);
$config->recordsPerPage = $this->getConfig('manage[recordsPerPage]');
$config->noRecordsMessage = $this->getConfig('manage[noRecordsMessage]');

Expand Down
31 changes: 31 additions & 0 deletions modules/backend/widgets/Lists.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Carbon\Carbon;
use Winter\Storm\Html\Helper as HtmlHelper;
use Winter\Storm\Router\Helper as RouterHelper;
use Winter\Storm\Database\Traits\Sortable;
use System\Helpers\DateTime as DateTimeHelper;
use System\Classes\PluginManager;
use System\Classes\MediaLibrary;
Expand Down Expand Up @@ -44,6 +45,11 @@ class Lists extends WidgetBase
*/
public $model;

/**
* @var List config definition
*/
public $definition;

/**
* @var string Link for each record row. Replace :id with the record id.
*/
Expand Down Expand Up @@ -74,6 +80,16 @@ class Lists extends WidgetBase
*/
public $showSorting = true;

/**
* @var bool Allow this list to be reordered in-place.
*/
public $reorder = false;

/**
* @var string reorder sort mode (simple|nested)
*/
public $reorderSortMode;

/**
* @var mixed A default sort column to look for.
*/
Expand Down Expand Up @@ -206,6 +222,8 @@ public function init()
'showPageNumbers',
'recordsPerPage',
'perPageOptions',
'reorder',
'definition',
'showSorting',
'defaultSort',
'showCheckboxes',
Expand Down Expand Up @@ -233,6 +251,11 @@ public function init()

$this->validateModel();
$this->validateTree();

if ($this->reorder) {
$this->addJs('/modules/system/assets/ui/js/list.sortable.js', 'core');
$this->showSorting = false;
}
}

/**
Expand Down Expand Up @@ -267,6 +290,9 @@ public function prepareVars()
$this->vars['showPagination'] = $this->showPagination;
$this->vars['showPageNumbers'] = $this->showPageNumbers;
$this->vars['showSorting'] = $this->showSorting;
$this->vars['reorder'] = $this->reorder;
$this->vars['reorderSortMode'] = $this->reorderSortMode;
$this->vars['definition'] = $this->definition;
$this->vars['sortColumn'] = $this->getSortColumn();
$this->vars['sortDirection'] = $this->sortDirection;
$this->vars['showTree'] = $this->showTree;
Expand Down Expand Up @@ -543,6 +569,11 @@ public function prepareQuery()
$sortColumn = Str::snake($column->relation) . '_count';
}

if ($this->reorder) {
$sortColumn = $this->model->getSortOrderColumn();
$this->sortDirection = 'ASC';
}

$query->orderBy($sortColumn, $this->sortDirection);
}

Expand Down
62 changes: 61 additions & 1 deletion modules/backend/widgets/lists/assets/js/winter.list.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
var $el = this.$el = $(element);

this.options = options || {};
this.sortOrders = []
this.definition = $el.data('definition')
this.sortMode = $el.data('sort-mode')

var scrollClassContainer = options.scrollClassContainer !== undefined
? options.scrollClassContainer
Expand All @@ -22,12 +25,69 @@
dragSelector: 'thead'
})

if (element.dataset.hasOwnProperty('sortable')) {
this.$el.find('.control-list-tbody').listSortable()
this.$el.on('dragged.list.sortable', $.proxy(this.processReorder, this))

this.$el.find('[data-record-sort-order]').each(function (index, el) {
this.sortOrders.push(el.dataset.recordSortOrder)
}.bind(this))
}

this.update()
}

ListWidget.DEFAULTS = {
}

ListWidget.prototype.processReorder = function (ev, sortData) {
var recordIds = []
var postData

if (this.sortMode == 'simple') {
this.$el.find('[data-record-id]').each(function (index, el) {
recordIds.push(el.dataset.recordId)
}.bind(this))

postData = { definition: this.definition, sort_orders: this.sortOrders, record_ids: recordIds }
}
else if (this.sortMode == 'nested') {
postData = this.getNestedMoveData(sortData)
}

this.$el.request('onReorder', {
data: postData,
loading: $.wn.stripeLoadIndicator,
})
}

ListWidget.prototype.getNestedMoveData = function (sortData) {
var $el,
$item = $(sortData.item),
moveData = {
targetNode: 0,
sourceNode: $item.data('recordId'),
position: 'root'
}

if (($el = $item.next()) && $el.length) {
moveData.position = 'before'
}
else if (($el = $item.prev()) && $el.length) {
moveData.position = 'after'
}
else if (($el = $item.parents('tr:first')) && $el.length) {
moveData.position = 'child'
}

if ($el.length) {
moveData.targetNode = $el.data('recordId')
}

console.log(moveData)
return moveData
}

ListWidget.prototype.update = function() {
var
list = this.$el,
Expand Down Expand Up @@ -143,4 +203,4 @@
$('[data-control="listwidget"]').listWidget();
})

}(window.jQuery);
}(window.jQuery);
2 changes: 1 addition & 1 deletion modules/backend/widgets/lists/partials/_list-container.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div class="list-widget list-scrollable-container <?= $cssClasses ?>" id="<?= $this->getId() ?>">
<?= $this->makePartial('list') ?>
</div>
</div>
9 changes: 7 additions & 2 deletions modules/backend/widgets/lists/partials/_list.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
<div class="control-list list-scrollable" data-control="listwidget">
<div class="control-list list-scrollable"
data-control="listwidget"
data-definition="<?= $definition ?>"
<?= $reorder ? 'data-sort-mode="' . e($reorderSortMode) . '"' : '' ?>
<?= $reorder ? 'data-sortable' : '' ?>
>
<table class="table data" data-control="rowlink">
<thead>
<?= $this->makePartial('list_head_row') ?>
</thead>
<tbody>
<tbody class="control-list-tbody">
<?php if (count($records)): ?>
<?= $this->makePartial('list_body_rows') ?>
<?php else: ?>
Expand Down
9 changes: 8 additions & 1 deletion modules/backend/widgets/lists/partials/_list_body_row.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@
$expanded = $showTree ? $this->isTreeNodeExpanded($record) : null;
$childRecords = $showTree ? $record->getChildren() : null;
$treeLevelClass = $showTree ? 'list-tree-level-'.$treeLevel : '';
$hasCheckboxesClass = $showCheckboxes ? 'has-list-checkbox' : '';
$draggable = ($reorder && $showTree) ? ($reorderSortMode !== 'nested' && $treeLevel === 0) : $reorder;
?>
<tr class="<?= $treeLevelClass ?> <?= $this->getRowClass($record) ?>">
<tr
class="<?= $treeLevelClass ?> <?= $hasCheckboxesClass ?> <?= $this->getRowClass($record) ?>"
data-record-id="<?= e($record->getKey()) ?>"
<?= $reorderSortMode === 'simple' ? 'data-record-sort-order="' . e($this->controller->getRecordSortOrder($record)) . '"' : '' ?>
<?= $draggable ? 'draggable="true"' : '' ?>
>
<?php if ($showCheckboxes): ?>
<?= $this->makePartial('list_body_checkbox', ['record' => $record]) ?>
<?php endif ?>
Expand Down
Loading