├── LICENSE ├── README.md ├── SortableGridAction.php ├── SortableGridAsset.php ├── SortableGridBehavior.php ├── SortableGridView.php ├── assets └── js │ └── jquery.sortable.gridview.js └── composer.json /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 HimikLab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sortable GridView Widget for Yii2 2 | ======================== 3 | Sortable modification of standard Yii2 GridView widget. 4 | 5 | [![Packagist](https://img.shields.io/packagist/dt/himiklab/yii2-sortable-grid-view-widget.svg)]() [![Packagist](https://img.shields.io/packagist/v/himiklab/yii2-sortable-grid-view-widget.svg)]() [![license](https://img.shields.io/badge/License-MIT-yellow.svg)]() 6 | 7 | Installation 8 | ------------ 9 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 10 | 11 | * Either run 12 | 13 | ``` 14 | php composer.phar require --prefer-dist "himiklab/yii2-sortable-grid-view-widget" "*" 15 | ``` 16 | 17 | or add 18 | 19 | ```json 20 | "himiklab/yii2-sortable-grid-view-widget" : "*" 21 | ``` 22 | 23 | to the `require` section of your application's `composer.json` file. 24 | 25 | * Add to your database new `unsigned int` attribute, such `sortOrder`. 26 | 27 | * Add new behavior in the AR model, for example: 28 | 29 | ```php 30 | use himiklab\sortablegrid\SortableGridBehavior; 31 | 32 | public function behaviors() 33 | { 34 | return [ 35 | 'sort' => [ 36 | 'class' => SortableGridBehavior::className(), 37 | 'sortableAttribute' => 'sortOrder' 38 | ], 39 | ]; 40 | } 41 | ``` 42 | 43 | * Add action in the controller, for example: 44 | 45 | ```php 46 | use himiklab\sortablegrid\SortableGridAction; 47 | 48 | public function actions() 49 | { 50 | return [ 51 | 'sort' => [ 52 | 'class' => SortableGridAction::className(), 53 | 'modelName' => Model::className(), 54 | ], 55 | ]; 56 | } 57 | ``` 58 | 59 | Usage 60 | ----- 61 | * Use SortableGridView as standard GridView with `sortableAction` option. 62 | You can also subscribe to the JS event 'sortableSuccess' generated widget after a successful sorting. 63 | -------------------------------------------------------------------------------- /SortableGridAction.php: -------------------------------------------------------------------------------- 1 | [ 26 | * 'class' => SortableGridAction::className(), 27 | * 'modelName' => Model::className(), 28 | * ], 29 | * ]; 30 | * } 31 | * ``` 32 | * 33 | * @author HimikLab 34 | * @package himiklab\sortablegrid 35 | */ 36 | class SortableGridAction extends Action 37 | { 38 | public $modelName; 39 | 40 | public function run() 41 | { 42 | if (!$items = Yii::$app->request->post('items')) { 43 | throw new BadRequestHttpException('Don\'t received POST param `items`.'); 44 | } 45 | /** @var \yii\db\ActiveRecord $model */ 46 | $model = new $this->modelName; 47 | if (!$model->hasMethod('gridSort')) { 48 | throw new InvalidConfigException( 49 | "Not found right `SortableGridBehavior` behavior in `{$this->modelName}`." 50 | ); 51 | } 52 | 53 | $model->gridSort(Json::decode($items)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /SortableGridAsset.php: -------------------------------------------------------------------------------- 1 | [ 24 | * 'class' => SortableGridBehavior::className(), 25 | * 'sortableAttribute' => 'sortOrder', 26 | * 'scope' => function ($query) { 27 | * $query->andWhere(['group_id' => $this->group_id]); 28 | * }, 29 | * ], 30 | * ]; 31 | * } 32 | * ``` 33 | * 34 | * @author HimikLab 35 | * @package himiklab\sortablegrid 36 | */ 37 | class SortableGridBehavior extends Behavior 38 | { 39 | /** @var string database field name for row sorting */ 40 | public $sortableAttribute = 'sortOrder'; 41 | 42 | /** @var callable */ 43 | public $scope; 44 | 45 | /** @var callable */ 46 | public $afterGridSort; 47 | 48 | public function events() 49 | { 50 | return [ActiveRecord::EVENT_BEFORE_INSERT => 'beforeInsert']; 51 | } 52 | 53 | public function gridSort($items) 54 | { 55 | /** @var ActiveRecord $model */ 56 | $model = $this->owner; 57 | if (!$model->hasAttribute($this->sortableAttribute)) { 58 | throw new InvalidConfigException("Model does not have sortable attribute `{$this->sortableAttribute}`."); 59 | } 60 | 61 | $newOrder = []; 62 | $models = []; 63 | foreach ($items as $old => $new) { 64 | $models[$new] = $model::findOne($new); 65 | $newOrder[$old] = $models[$new]->{$this->sortableAttribute} ? $models[$new]->{$this->sortableAttribute} : $new; 66 | } 67 | $model::getDb()->transaction(function () use ($models, $newOrder) { 68 | foreach ($newOrder as $modelId => $orderValue) { 69 | /** @var ActiveRecord[] $models */ 70 | $models[$modelId]->updateAttributes([$this->sortableAttribute => $orderValue]); 71 | } 72 | }); 73 | 74 | if (is_callable($this->afterGridSort)) { 75 | call_user_func($this->afterGridSort, $model); 76 | } 77 | } 78 | 79 | public function beforeInsert() 80 | { 81 | /** @var ActiveRecord $model */ 82 | $model = $this->owner; 83 | if (!$model->hasAttribute($this->sortableAttribute)) { 84 | throw new InvalidConfigException("Invalid sortable attribute `{$this->sortableAttribute}`."); 85 | } 86 | 87 | $query = $model::find(); 88 | if (is_callable($this->scope)) { 89 | call_user_func($this->scope, $query); 90 | } 91 | 92 | /* Override model alias if defined in the model's class */ 93 | $query->from([$model::tableName() => $model::tableName()]); 94 | 95 | $maxOrder = $query->max('{{' . trim($model::tableName(), '{}') . '}}.[[' . $this->sortableAttribute . ']]'); 96 | $model->{$this->sortableAttribute} = $maxOrder + 1; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /SortableGridView.php: -------------------------------------------------------------------------------- 1 | sortableAction = Url::to($this->sortableAction); 28 | } 29 | 30 | public function run() 31 | { 32 | $this->registerWidget(); 33 | parent::run(); 34 | } 35 | 36 | protected function registerWidget() 37 | { 38 | $view = $this->getView(); 39 | $view->registerJs("jQuery('#{$this->options['id']}').SortableGridView('{$this->sortableAction}');"); 40 | SortableGridAsset::register($view); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /assets/js/jquery.sortable.gridview.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | var fixHelper = function (e, ui) { 3 | ui.children().each(function () { 4 | $(this).width($(this).width()); 5 | }); 6 | return ui; 7 | }; 8 | 9 | $.fn.SortableGridView = function (action) { 10 | var widget = this; 11 | var grid = $('tbody', this); 12 | 13 | var initialIndex = []; 14 | $('tr', grid).each(function () { 15 | initialIndex.push($(this).data('key')); 16 | }); 17 | 18 | grid.sortable({ 19 | items: 'tr', 20 | axis: 'y', 21 | update: function () { 22 | var items = {}; 23 | var i = 0; 24 | $('tr', grid).each(function () { 25 | var currentKey = $(this).data('key'); 26 | if (initialIndex[i] != currentKey) { 27 | items[currentKey] = initialIndex[i]; 28 | initialIndex[i] = currentKey; 29 | } 30 | ++i; 31 | }); 32 | 33 | $.ajax({ 34 | 'url': action, 35 | 'type': 'post', 36 | 'data': {'items': JSON.stringify(items)}, 37 | 'success': function () { 38 | widget.trigger('sortableSuccess'); 39 | }, 40 | 'error': function (request, status, error) { 41 | alert(status + ' ' + error); 42 | } 43 | }); 44 | }, 45 | helper: fixHelper 46 | }).disableSelection(); 47 | }; 48 | })(jQuery); 49 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "himiklab/yii2-sortable-grid-view-widget", 3 | "description": "Sortable modification of standard Yii2 GridView widget", 4 | "keywords": ["yii2", "sortable", "gridview", "grid", "widget"], 5 | "type": "yii2-extension", 6 | "license": "MIT", 7 | "support": { 8 | "source": "https://github.com/himiklab/yii2-sortable-grid-view-widget", 9 | "issues": "https://github.com/himiklab/yii2-sortable-grid-view-widget/issues" 10 | }, 11 | "authors": [ 12 | { 13 | "name": "HimikLab", 14 | "homepage": "https://github.com/himiklab" 15 | } 16 | ], 17 | "require": { 18 | "yiisoft/yii2": "*", 19 | "yiisoft/yii2-jui": "*" 20 | }, 21 | "autoload": { 22 | "psr-4": {"himiklab\\sortablegrid\\": ""} 23 | } 24 | } 25 | --------------------------------------------------------------------------------