mirror of
https://github.com/UndefinedOffset/SortableGridField.git
synced 2024-10-22 17:05:38 +02:00
Added support for cross page sorting
This commit is contained in:
parent
12f9caca17
commit
4993f6d3e6
@ -53,8 +53,20 @@ class GridFieldSortableRows implements GridField_HTMLProvider, GridField_ActionP
|
|||||||
)->addExtraClass('sortablerows-disablepagenator');
|
)->addExtraClass('sortablerows-disablepagenator');
|
||||||
|
|
||||||
|
|
||||||
|
//Disable Pagenator
|
||||||
|
$sortToPage = Object::create(
|
||||||
|
'GridField_FormAction',
|
||||||
|
$gridField,
|
||||||
|
'sortablerows-sorttopage',
|
||||||
|
_t('GridFieldSortableRows.SORT_TO_PAGE', '_Sort To Page'),
|
||||||
|
'sortToPage',
|
||||||
|
null
|
||||||
|
)->addExtraClass('sortablerows-sorttopage');
|
||||||
|
|
||||||
|
|
||||||
$data = array('SortableToggle' => $sortOrderToggle,
|
$data = array('SortableToggle' => $sortOrderToggle,
|
||||||
'PagenatorToggle' => $disablePagenator,
|
'PagenatorToggle' => $disablePagenator,
|
||||||
|
'SortToPage' => $sortToPage,
|
||||||
'Checked' => ($state->sortableToggle == true ? ' checked = "checked"':''));
|
'Checked' => ($state->sortableToggle == true ? ' checked = "checked"':''));
|
||||||
|
|
||||||
$forTemplate = new ArrayData($data);
|
$forTemplate = new ArrayData($data);
|
||||||
@ -91,7 +103,7 @@ class GridFieldSortableRows implements GridField_HTMLProvider, GridField_ActionP
|
|||||||
* @return Array Array with action identifier strings.
|
* @return Array Array with action identifier strings.
|
||||||
*/
|
*/
|
||||||
public function getActions($gridField) {
|
public function getActions($gridField) {
|
||||||
return array('saveGridRowSort', 'sortableRowsDisablePaginator');
|
return array('saveGridRowSort', 'sortableRowsDisablePaginator', 'sortToPage');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,7 +125,9 @@ class GridFieldSortableRows implements GridField_HTMLProvider, GridField_ActionP
|
|||||||
|
|
||||||
if ($actionName == 'savegridrowsort') {
|
if ($actionName == 'savegridrowsort') {
|
||||||
return $this->saveGridRowSort($gridField, $data);
|
return $this->saveGridRowSort($gridField, $data);
|
||||||
}
|
} else if ($actionName == 'sorttopage') {
|
||||||
|
return $this->sortToPage($gridField, $data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,7 +135,7 @@ class GridFieldSortableRows implements GridField_HTMLProvider, GridField_ActionP
|
|||||||
* @param GridField $gridField Grid Field Reference
|
* @param GridField $gridField Grid Field Reference
|
||||||
* @param Array $data Data submitted in the request
|
* @param Array $data Data submitted in the request
|
||||||
*/
|
*/
|
||||||
private function saveGridRowSort(GridField $gridField, $data) {
|
protected function saveGridRowSort(GridField $gridField, $data) {
|
||||||
if(!singleton($gridField->getModelClass())->canEdit()){
|
if(!singleton($gridField->getModelClass())->canEdit()){
|
||||||
throw new ValidationException(_t('GridFieldSortableRows.EditPermissionsFailure', "No edit permissions"),0);
|
throw new ValidationException(_t('GridFieldSortableRows.EditPermissionsFailure', "No edit permissions"),0);
|
||||||
}
|
}
|
||||||
@ -137,10 +151,10 @@ class GridFieldSortableRows implements GridField_HTMLProvider, GridField_ActionP
|
|||||||
$sortColumn = $this->sortColumn;
|
$sortColumn = $this->sortColumn;
|
||||||
$pageOffset = 0;
|
$pageOffset = 0;
|
||||||
|
|
||||||
if ($paginator=$gridField->getConfig()->getComponentsByType('GridFieldPaginator')->First()) {
|
if ($paginator = $gridField->getConfig()->getComponentsByType('GridFieldPaginator')->First()) {
|
||||||
$pageState=$gridField->State->GridFieldPaginator;
|
$pageState = $gridField->State->GridFieldPaginator;
|
||||||
if($pageState->currentPage && $pageState->currentPage>1) {
|
if($pageState->currentPage && $pageState->currentPage>1) {
|
||||||
$pageOffset=$paginator->getItemsPerPage()*($pageState->currentPage-1);
|
$pageOffset = $paginator->getItemsPerPage() * ($pageState->currentPage - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,16 +169,18 @@ class GridFieldSortableRows implements GridField_HTMLProvider, GridField_ActionP
|
|||||||
DB::getConn()->transactionStart();
|
DB::getConn()->transactionStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//@TODO Need to optimize this to eliminate some of the resource load could use raw queries to be more efficient
|
||||||
$data['Items'] = explode(',', $data['Items']);
|
$data['Items'] = explode(',', $data['Items']);
|
||||||
for($sort = 0;$sort<count($data['Items']);$sort++) {
|
for($sort = 0;$sort<count($data['Items']);$sort++) {
|
||||||
$id = intval($data['Items'][$sort]);
|
$id = intval($data['Items'][$sort]);
|
||||||
if ($many_many) {
|
if ($many_many) {
|
||||||
DB::query('UPDATE "' . $table
|
DB::query('UPDATE "' . $table
|
||||||
. '" SET "' . $sortColumn.'" = ' . (($sort+1)+$pageOffset)
|
. '" SET "' . $sortColumn.'" = ' . (($sort + 1) + $pageOffset)
|
||||||
. ' WHERE "' . $componentField . '" = ' . $id . ' AND "' . $parentField . '" = ' . $owner->ID);
|
. ' WHERE "' . $componentField . '" = ' . $id . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||||
} else {
|
} else {
|
||||||
$obj = $items->byID($data['Items'][$sort]);
|
$obj = $items->byID($data['Items'][$sort]);
|
||||||
$obj->$sortColumn = ($sort+1)+$pageOffset;
|
$obj->$sortColumn = ($sort + 1) + $pageOffset;
|
||||||
$obj->write();
|
$obj->write();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,5 +190,100 @@ class GridFieldSortableRows implements GridField_HTMLProvider, GridField_ActionP
|
|||||||
DB::getConn()->transactionEnd();
|
DB::getConn()->transactionEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles sorting across pages
|
||||||
|
* @param GridField $gridField Grid Field Reference
|
||||||
|
* @param Array $data Data submitted in the request
|
||||||
|
*/
|
||||||
|
protected function sortToPage(GridField $gridField, $data) {
|
||||||
|
if (!$paginator = $gridField->getConfig()->getComponentsByType('GridFieldPaginator')->First()) {
|
||||||
|
user_error('Paginator not detected', E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($data['ItemID'])) {
|
||||||
|
user_error('No item to sort', E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($data['Target'])) {
|
||||||
|
user_error('No target page', E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$className = $gridField->getModelClass();
|
||||||
|
$owner = $gridField->Form->getRecord();
|
||||||
|
$items = $gridField->getList();
|
||||||
|
$many_many = ($items instanceof ManyManyList);
|
||||||
|
$sortColumn = $this->sortColumn;
|
||||||
|
$targetItem = $items->byID(intval($data['ItemID']));
|
||||||
|
|
||||||
|
if (!$targetItem) {
|
||||||
|
user_error('Target item not found', E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sortPosition = $targetItem->$sortColumn;
|
||||||
|
$currentPage = 1;
|
||||||
|
|
||||||
|
|
||||||
|
$pageState = $gridField->State->GridFieldPaginator;
|
||||||
|
if($pageState->currentPage && $pageState->currentPage>1) {
|
||||||
|
$currentPage = $pageState->currentPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($many_many) {
|
||||||
|
list($parentClass, $componentClass, $parentField, $componentField, $table) = $owner->many_many($gridField->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($data['Target'] == 'firstpage') {
|
||||||
|
$sortPosition = $paginator->getItemsPerPage();
|
||||||
|
} else if ($data['Target'] == 'previouspage') {
|
||||||
|
$sortPosition = $paginator->getItemsPerPage() * ($currentPage - 1);
|
||||||
|
} else if ($data['Target'] == 'nextpage') {
|
||||||
|
$sortPosition = ($paginator->getItemsPerPage() * $currentPage) + 1;
|
||||||
|
} else if ($data['Target'] == 'lastpage') {
|
||||||
|
$sortPosition = ($paginator->getItemsPerPage() * (ceil($items->count() / $paginator->getItemsPerPage()) - 1)) + 1;
|
||||||
|
} else {
|
||||||
|
user_error('Not implemented: '.$data['Target'], E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if($targetItem->$sortColumn != $sortPosition) {
|
||||||
|
//Start transaction if supported
|
||||||
|
if(DB::getConn()->supportsTransactions()) {
|
||||||
|
DB::getConn()->transactionStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Swap with the item around the target position
|
||||||
|
$swapItem = $items->where('"'.$sortColumn.'" >= '.$sortPosition)->First();
|
||||||
|
if ($many_many) {
|
||||||
|
DB::query('UPDATE "' . $table
|
||||||
|
. '" SET "' . $sortColumn.'" = ' . $targetItem->$sortColumn
|
||||||
|
. ' WHERE "' . $componentField . '" = ' . $targetItem->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||||
|
} else {
|
||||||
|
$swapItem->$sortColumn = $targetItem->$sortColumn;
|
||||||
|
$swapItem->write();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Update target item position
|
||||||
|
if ($many_many) {
|
||||||
|
DB::query('UPDATE "' . $table
|
||||||
|
. '" SET "' . $sortColumn.'" = ' . $sortPosition
|
||||||
|
. ' WHERE "' . $componentField . '" = ' . $targetItem->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||||
|
} else {
|
||||||
|
$targetItem->$sortColumn = $sortPosition;
|
||||||
|
$targetItem->write();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//End transaction if supported
|
||||||
|
if(DB::getConn()->supportsTransactions()) {
|
||||||
|
DB::getConn()->transactionEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
@ -1,6 +1,7 @@
|
|||||||
(function($) {
|
(function($) {
|
||||||
$('.ss-gridfield .gridfield-sortablerows input').entwine({
|
$('.ss-gridfield .gridfield-sortablerows input').entwine({
|
||||||
onmatch: function() {
|
onmatch: function() {
|
||||||
|
var self=this;
|
||||||
var refCheckbox=$(this);
|
var refCheckbox=$(this);
|
||||||
|
|
||||||
var gridField=$(this).getGridField();
|
var gridField=$(this).getGridField();
|
||||||
@ -12,6 +13,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
gridField.find('tbody').sortable({
|
gridField.find('tbody').sortable({
|
||||||
|
opacity: 0.6,
|
||||||
disabled: ($(this).is(':checked')==false),
|
disabled: ($(this).is(':checked')==false),
|
||||||
helper: function(e, ui) {
|
helper: function(e, ui) {
|
||||||
//Maintains width of the columns
|
//Maintains width of the columns
|
||||||
@ -32,37 +34,64 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var form = gridField.closest('form'),
|
self._makeRequest({data: [
|
||||||
focusedElName = gridField.find(':input:focus').attr('name'); // Save focused element for restoring after refresh
|
{
|
||||||
var ajaxOpts = {data: [
|
name: button.attr('name'),
|
||||||
{
|
value: button.val()
|
||||||
name: button.attr('name'),
|
},
|
||||||
value: button.val()},
|
{
|
||||||
{
|
name: 'Items',
|
||||||
name: 'Items',
|
value: dataRows
|
||||||
value: dataRows
|
}
|
||||||
}
|
]});
|
||||||
]};
|
|
||||||
|
|
||||||
ajaxOpts.data = ajaxOpts.data.concat(form.find(':input').serializeArray());
|
|
||||||
|
|
||||||
// Include any GET parameters from the current URL, as the view state might depend on it.
|
|
||||||
// For example, a list prefiltered through external search criteria might be passed to GridField.
|
|
||||||
if(window.location.search) {
|
|
||||||
ajaxOpts.data = window.location.search.replace(/^\?/, '') + '&' + $.param(ajaxOpts.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
$.ajax($.extend({}, {
|
|
||||||
headers: {"X-Pjax" : 'CurrentField'},
|
|
||||||
type: "POST",
|
|
||||||
url: gridField.data('url'),
|
|
||||||
dataType: 'html',
|
|
||||||
error: function(e) {
|
|
||||||
alert(ss.i18n._t('GRIDFIELD.ERRORINTRANSACTION'));
|
|
||||||
}
|
|
||||||
}, ajaxOpts));
|
|
||||||
}
|
}
|
||||||
}).disableSelection();
|
}).disableSelection();
|
||||||
|
|
||||||
|
gridField.find('.datagrid-pagination button').each(function() {
|
||||||
|
$(this).droppable({
|
||||||
|
disabled: $(this).is(':disabled'),
|
||||||
|
accept: 'tr.ss-gridfield-item',
|
||||||
|
tolerance: 'pointer',
|
||||||
|
drop: function(event, ui) {
|
||||||
|
gridField.find('tbody').sortable('cancel');
|
||||||
|
|
||||||
|
var button=refCheckbox.parent().find('.sortablerows-sorttopage');
|
||||||
|
var itemID=$(ui.draggable).data('id');
|
||||||
|
var target='';
|
||||||
|
|
||||||
|
|
||||||
|
if($(this).hasClass('ss-gridfield-firstpage')) {
|
||||||
|
target='firstpage';
|
||||||
|
}else if($(this).hasClass('ss-gridfield-previouspage')) {
|
||||||
|
target='previouspage';
|
||||||
|
}else if($(this).hasClass('ss-gridfield-nextpage')) {
|
||||||
|
target='nextpage';
|
||||||
|
}else if($(this).hasClass('ss-gridfield-lastpage')) {
|
||||||
|
target='lastpage';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Move and Reload the grid
|
||||||
|
gridField.reload({data: [
|
||||||
|
{
|
||||||
|
name: button.attr('name'),
|
||||||
|
value: button.val()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ItemID',
|
||||||
|
value: itemID
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Target',
|
||||||
|
value: target
|
||||||
|
}
|
||||||
|
]});
|
||||||
|
|
||||||
|
event.stopPropagation();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onchange: function(e) {
|
onchange: function(e) {
|
||||||
@ -73,6 +102,31 @@
|
|||||||
|
|
||||||
var button=$(this).parent().find('.sortablerows-disablepagenator');
|
var button=$(this).parent().find('.sortablerows-disablepagenator');
|
||||||
gridField.reload({data: [{name: button.attr('name'), value: button.val()}]});
|
gridField.reload({data: [{name: button.attr('name'), value: button.val()}]});
|
||||||
}
|
},
|
||||||
|
|
||||||
|
_makeRequest: function(ajaxOpts, callback) {
|
||||||
|
var gridField=$(this).getGridField();
|
||||||
|
var form = gridField.closest('form'),
|
||||||
|
focusedElName = gridField.find(':input:focus').attr('name'); // Save focused element for restoring after refresh
|
||||||
|
|
||||||
|
ajaxOpts.data = ajaxOpts.data.concat(form.find(':input').serializeArray());
|
||||||
|
|
||||||
|
// Include any GET parameters from the current URL, as the view state might depend on it.
|
||||||
|
// For example, a list prefiltered through external search criteria might be passed to GridField.
|
||||||
|
if(window.location.search) {
|
||||||
|
ajaxOpts.data = window.location.search.replace(/^\?/, '') + '&' + $.param(ajaxOpts.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax($.extend({}, {
|
||||||
|
headers: {"X-Pjax" : 'CurrentField'},
|
||||||
|
type: "POST",
|
||||||
|
url: gridField.data('url'),
|
||||||
|
dataType: 'html',
|
||||||
|
success: callback,
|
||||||
|
error: function(e) {
|
||||||
|
alert(ss.i18n._t('GRIDFIELD.ERRORINTRANSACTION'));
|
||||||
|
}
|
||||||
|
}, ajaxOpts));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})(jQuery);
|
})(jQuery);
|
@ -2,4 +2,5 @@ en:
|
|||||||
GridFieldSortableRows:
|
GridFieldSortableRows:
|
||||||
ALLOW_DRAG_DROP: "Allow Drag and Drop"
|
ALLOW_DRAG_DROP: "Allow Drag and Drop"
|
||||||
DISABLE_PAGINATOR: "Disable Pagenator"
|
DISABLE_PAGINATOR: "Disable Pagenator"
|
||||||
|
SORT_TO_PAGE: "Sort To Page"
|
||||||
EditPermissionsFailure: "No edit permissions"
|
EditPermissionsFailure: "No edit permissions"
|
@ -4,6 +4,7 @@
|
|||||||
<input type="checkbox" value="1"$Checked/> <%t GridFieldSortableRows.ALLOW_DRAG_DROP "_Allow drag and drop re-ordering" %>
|
<input type="checkbox" value="1"$Checked/> <%t GridFieldSortableRows.ALLOW_DRAG_DROP "_Allow drag and drop re-ordering" %>
|
||||||
$SortableToggle
|
$SortableToggle
|
||||||
$PagenatorToggle
|
$PagenatorToggle
|
||||||
|
$SortToPage
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
Loading…
Reference in New Issue
Block a user