Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
db36df1
Added ReorderRelationController
tobias-kuendig Oct 6, 2020
c40f5e2
Set the config only if a reorderRelationConfig is available
tobias-kuendig Oct 6, 2020
07535b2
Fixed code style
tobias-kuendig Oct 6, 2020
7c8e0f3
First version of sortable Lists
tobias-kuendig Oct 15, 2020
3df94b6
Code cleanup
tobias-kuendig Oct 16, 2020
ae712c3
Removed superfluous request parameter
tobias-kuendig Oct 16, 2020
9ece79a
Removed another request parameter that is not needed
tobias-kuendig Oct 16, 2020
f320576
Fixed typo in comment
tobias-kuendig Oct 16, 2020
c4bd6b8
force showTree to be false if the List is sortable
tobias-kuendig Oct 20, 2020
ff15a29
Merge commit 'refs/pull/5298/head' of https://github.com/octobercms/o…
mjauvin Mar 29, 2022
53ee030
use winter namespace
mjauvin Mar 29, 2022
0de4167
replace remaining october references for winter
mjauvin Mar 29, 2022
b9e25f8
fix oc -> wn object in js code
mjauvin Mar 29, 2022
a1872ec
fix js object name
mjauvin Mar 29, 2022
cfa712d
account for one to many relations (no pivot table)
mjauvin Mar 31, 2022
036547d
rename methods to avoid namespace conflict with ReorderController beh…
mjauvin Mar 31, 2022
c0a3cb2
- avoid namespace conflict
mjauvin Mar 31, 2022
70b0b9b
Merge branch 'wip/1.2' into reorder-relations
mjauvin Mar 31, 2022
ba01ee1
recompile storm.js asset
mjauvin Mar 31, 2022
10f9c83
latest recompiled version of storm.js
mjauvin Mar 31, 2022
b75e40a
use new trait name "HasSortableRelations"
mjauvin Apr 1, 2022
817dc38
Merge branch 'wip/1.2' into reorder-relations
mjauvin Apr 5, 2022
208d614
remove reorder modal, all done in place within the relation view
mjauvin May 11, 2022
ebae63b
use relationRefresh() method
mjauvin May 11, 2022
22a0bd2
Merge branch 'wip/1.2' into test
mjauvin May 24, 2022
0067f2a
Merge branch 'wip/1.2' into reorder-relations
mjauvin Jun 4, 2022
0c21381
Merge branch 'wip/1.2' into reorder-relations
mjauvin Jun 5, 2022
e8895bb
Merge branch 'wip/1.2' into reorder-relations
mjauvin Jun 20, 2022
34d4c9f
Merge branch 'wip/1.2' into reorder-relations
mjauvin Jun 22, 2022
063a71c
Merge branch 'wip/1.2' into reorder-relations
mjauvin Jun 23, 2022
0e3a23d
Merge branch 'wip/1.2' into reorder-relations
mjauvin Jun 25, 2022
edf2a5b
Merge branch 'wip/1.2' into reorder-relations
mjauvin Jul 5, 2022
6d57257
Merge branch 'wip/1.2' into reorder-relations
mjauvin Jul 8, 2022
2e687eb
Merge branch 'wip/1.2' into reorder-relations
mjauvin Jul 10, 2022
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
18 changes: 18 additions & 0 deletions modules/backend/behaviors/ListController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Flash;
use ApplicationException;
use Backend\Classes\ControllerBehavior;
use Winter\Storm\Database\Traits\HasSortableRelations;

/**
* Adds features for working with backend lists.
Expand Down Expand Up @@ -150,6 +151,7 @@ public function makeList($definition = null)
'showCheckboxes',
'showTree',
'treeExpanded',
'sortable',
'customViewPath',
];

Expand Down Expand Up @@ -431,6 +433,22 @@ public function listRefresh(string $definition = null)
return $this->listWidgets[$definition]->onRefresh();
}

/**
* Returns the sort order value for a specific record.
*/
public function getRecordSortOrder($record, $relation = '')
{
if ($relation) {
/** @var HasSortableRelations $modelInstance */
$modelInstance = new $this->config->modelClass;
$reorderColumn = $modelInstance->getRelationSortOrderColumn($relation);

return $this->controller->asExtension('ReorderRelationController')->getRelationRecordSortOrder($record, $reorderColumn);
}

return $record->{$record->getSortOrderColumn()};
}

/**
* Returns the widget used by this behavior.
* @return \Backend\Classes\WidgetBase
Expand Down
4 changes: 4 additions & 0 deletions modules/backend/behaviors/RelationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,10 @@ protected function makeViewWidget()
$config->alias = $this->alias . 'ViewList';
$config->showSorting = $this->getConfig('view[showSorting]', true);
$config->defaultSort = $this->getConfig('view[defaultSort]');
$config->sortable = $this->getConfig('view[sortable]', false);
$config->reorderRelation = $this->relationName;
$config->reorderModel = get_class($this->model);
$config->reorderParentId = $this->model->getKey();
$config->recordsPerPage = $this->getConfig('view[recordsPerPage]');
$config->showCheckboxes = $this->getConfig('view[showCheckboxes]', !$this->readOnly);
$config->recordUrl = $this->getConfig('view[recordUrl]');
Expand Down
245 changes: 245 additions & 0 deletions modules/backend/behaviors/ReorderRelationController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
<?php namespace Backend\Behaviors;

use ApplicationException;
use Backend;
use Backend\Classes\ControllerBehavior;
use Lang;
use Winter\Storm\Database\Model;
use Winter\Storm\Database\Traits\HasSortableRelations;

/**
* Used for reordering and sorting related records.
*
* This behavior is implemented in the controller like so:
*
* public $implement = [
* 'Backend.Behaviors.ReorderRelationController',
* ];
* // Optional:
* public $reorderRelationConfig = 'config_reorder_relation.yaml';
*
* The `$reorderRelationConfig` property makes reference to the configuration
* values as either a YAML file, located in the controller view directory,
* or directly as a PHP array.
*
* @package winter\wn-backend-module
*/
class ReorderRelationController extends ControllerBehavior
{
/**
* @var Model The related sort model
*/
public $model;

/**
* @var HasSortableRelations|Model The parent/form model
*/
public $parentModel;

/**
* @var string The relation that is being sorted
*/
public $relation;

/**
* Behavior constructor
* @param Backend\Classes\Controller $controller
*/
public function __construct($controller)
{
parent::__construct($controller);

// The configuration is optional for this behavior.
$this->config = [];
if ($controller->reorderRelationConfig) {
$this->config = $this->makeConfig($controller->reorderRelationConfig, []);
}
}

//
// AJAX
//

/**
* Updates the relation order.
* @throws \Exception
*/
public function onReorderRelation()
{
$this->reorderRelationGetModel();
$this->validateModel();

if (
(!$ids = post('record_ids')) ||
(!$orders = post('sort_orders'))
) {
return;
}

/** @var HasSortableRelations $instance */
$instance = $this->parentModel->newQuery()->find($this->postValue('_reorder_parent_id'));
$instance->setRelationOrder($this->relation, $ids, $orders);

// refresh the relation view after reorder
$this->controller->initRelation(
$this->parentModel->newQuery()->findOrFail($this->postValue('_reorder_parent_id')),
$this->relation
);
return $this->controller->relationRefresh($this->relation);
}

//
// Reordering
//

/**
* Sets all required model properties.
*/
public function reorderRelationGetModel()
{
$this->parentModel = $this->reorderRelationGetParentModel();
$this->relation = post('_reorder_relation_name');

$relationModelClass = array_get($this->parentModel->getRelationDefinition($this->relation), 0);
if (!$relationModelClass) {
throw new ApplicationException(
sprintf('Could not determine model class for relation "%s"', $this->relation)
);
}

return $this->model = new $relationModelClass;
}

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

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

return $query
->with([$this->relation => function ($q) {
$q->orderBy($this->parentModel->getRelationSortOrderColumn($this->relation), 'ASC');
}])
->findOrFail($this->postValue('_reorder_parent_id'))
->{$this->relation};
}

/**
* Extend the relation 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 reorderExtendRelationQuery($query)
{
}

//
// Helpers
//

/**
* Prepares common partial variables.
*/
protected function prepareVars()
{
$this->vars['reorderRecords'] = $this->getRecords();
$this->vars['reorderModel'] = $this->model;
}

/**
* Return a model instance based on the _reorder_model post value.
* @return Model
*/
public function reorderRelationGetParentModel()
{
$model = $this->postValue('_reorder_model');

if (!class_exists($model)) {
throw new ApplicationException(
sprintf('Model class "%s" does not exist', $model)
);
}

return new $model;
}

public function getRelationRecordSortOrder($record, $sortColumn)
{
return $record->pivot ? $record->pivot->{$sortColumn} : $record->{$sortColumn};
}

/**
* Validate the supplied form model.
* @return void
*/
protected function validateModel()
{
$modelTraits = class_uses($this->parentModel);

if (!isset($modelTraits[\Winter\Storm\Database\Traits\HasSortableRelations::class])) {
throw new ApplicationException(
sprintf('The "%s" model must implement the HasSortableRelations trait.', get_class($this->parentModel))
);
}
}

/**
* Returns the name attribute for a given $record. The attribute
* defined in the behaviour config is used here.
*
* @param Model $record
* @param $relation
*
* @return string
*/
public function reorderRelationGetRecordName(Model $record, $relation)
{
$attribute = array_get((array)$this->config, "$relation.nameFrom");
if ($attribute) {
return (string)$record->$attribute;
}

// Take a guess if no "nameFrom" config is set.
return (string)($record->name ?: $record->title);
}

/**
* Controller accessor for making partials within this behavior.
* @param string $partial
* @param array $params
* @return string Partial contents
*/
public function reorderRelationMakePartial($partial, $params = [])
{
$contents = $this->controller->makePartial(
'reorder_' . $partial,
$params + $this->vars,
false
);

if (!$contents) {
$contents = $this->makePartial($partial, $params);
}

return $contents;
}

/**
* Fetch a post value for the current relation.
*
* @param string $key
*
* @return mixed
*/
private function postValue(string $key)
{
$relation = post('_reorder_relation_name');

return post($key. '.' . $relation);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php $relationName = $this->vars['relationField']; ?>
<a
data-control="popup"
data-size="huge"
data-handler="onRelationButtonReorder"
data-request-data="
_reorder_parent_id[<?= e($relationName) ?>]: '<?= e($this->vars['formModel']->id) ?>',
_reorder_model[<?= e($relationName) ?>]: '<?= e(addslashes(get_class($this->vars['formModel']))) ?>',
_reorder_relation_name: '<?= e($relationName) ?>'
"
href="javascript:;"
class="btn btn-sm btn-secondary oc-icon-reorder">
<?= e(trans('backend::lang.reorder.default_title')) ?>
</a>
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
* - Nested sorting: Post back source and target nodes IDs and the move positioning.
*/
+function ($) { "use strict";

var ReorderBehavior = function() {

this.sortMode = null
this.context = 'default'

this.simpleSortOrders = []

this.initSorting = function (mode) {
this.initSorting = function (mode, context) {
this.sortMode = mode
this.context = context

if (mode == 'simple') {
this.initSortingSimple()
Expand All @@ -34,7 +35,9 @@
postData = this.getNestedMoveData(sortData)
}

$('#reorderTreeList').request('onReorder', {
var handler = this.context === 'relation' ? 'onReorderRelation' : 'onReorder'

$('#reorderTreeList').request(handler, {
data: postData
})
}
Expand Down Expand Up @@ -79,4 +82,4 @@
}

$.wn.reorderBehavior = new ReorderBehavior;
}(window.jQuery);
}(window.jQuery);
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!-- Reorder List -->
<?= Form::open() ?>

<input type="hidden" name="_reorder_relation_name" value="<?= e($reorderRelation) ?>">
<input type="hidden" name="_reorder_model[<?= e($reorderRelation) ?>]" value="<?= e($reorderModel) ?>">
<input type="hidden" name="_reorder_parent_id[<?= e($reorderRelation) ?>]" value="<?= e($reorderParentId) ?>">

<div
id="reorderTreeList"
class="control-treelist"
data-control="treelist"
data-handle="> li > .record > a.move"
data-stripe-load-indicator>
<?php if ($reorderRecords): ?>
<ol id="reorderRecords">
<?= $this->reorderRelationMakePartial('records', [
'records' => $reorderRecords,
'sortColumn' => $reorderSortColumn,
'relation' => $reorderRelation
]) ?>
</ol>
<?php else: ?>
<p><?= Lang::get('backend::lang.reorder.no_records') ?></p>
<?php endif ?>
</div>
<?= Form::close() ?>

<script>
$.wn.reorderBehavior.initSorting('simple', 'relation')
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php foreach ($records as $record): ?>

<li data-record-id="<?= $record->getKey() ?>"
data-record-sort-order="<?= $this->getRelationRecordSortOrder($record, $sortColumn) ?>"
>
<div class="record">
<a href="javascript:;" class="move"></a>
<span><?= e($this->reorderRelationGetRecordName($record, $relation)) ?></span>
<input name="record_ids[]" type="hidden" value="<?= $record->getKey() ?>" />
</div>
</li>

<?php endforeach ?>
Loading