Sorting with known previous sibling's ID

This commit is contained in:
Eero Jääskeläinen 2022-11-28 09:39:28 +02:00
parent 0b0c89ba3c
commit 066e9eb236
5 changed files with 67 additions and 94 deletions

View file

@ -244,29 +244,21 @@ class Services extends EA_Controller {
{ {
abort(400,'Invalid ID value'); abort(400,'Invalid ID value');
} }
$newOrder = request('new_order');
if ( (($newOrder = filter_var($newOrder,FILTER_VALIDATE_INT)) === FALSE) || $insertAfterId = request('after');
$newOrder < 0) if (($insertAfterId = filter_var($insertAfterId,FILTER_VALIDATE_INT)) === FALSE)
{ {
abort(400,'Invalid new order value'); abort(400,'Invalid after value, must be ID or -1');
} }
$visibleServices = request('allIds'); if ($insertAfterId <= 0)
if (empty($visibleServices))
{ {
abort('allIds must be defined to successfully sort services'); $insertAfterId = FALSE;
} }
if (!is_array($visibleServices))
{
$visibleServices = Array($visibleServices);
}
$visibleServices = array_filter(filter_var_array($visibleServices, FILTER_VALIDATE_INT));
$service = $this->services_model->find($service_id); $service = $this->services_model->find($service_id);
$service['row_order'] = $this->services_model->set_service_order($service['id'], $newOrder,$visibleServices); $service['row_order'] = $this->services_model->set_service_order($service['id'], $insertAfterId);
return json_response($service); return json_response($service);
} }

View file

@ -238,83 +238,53 @@ class EA_Model extends CI_Model {
/** /**
* Inserts entry to desired order in table relative to user visible entries * Inserts entry order after defined entry
* *
* @param string $table Table * @param string $table Table
* @param array $entry Entity * @param array $entry Entity to insert
* @param int $desiredOrder Desired place in table (relative to visible entities) * @param mixed|bool $afterId ID of entry where to insert at. Or false to set at beginning
* @param Array [$visibleIds] Visible ids to sort on * @param string [$order_column] Ordering Column name (Default: row_order)
* @param string [$order_column] Ordering Column name
* *
* @throws RuntimeException * @throws RuntimeException
* @throws InvalidArgumentException
*/ */
public function insert_row_order_visible (string $table, array &$entry, int $desiredOrder, Array &$visibleIds = NULL, string $order_column='row_order') public function insert_row_order_after(string $table, array &$entry, $afterId, string $order_column='row_order')
{ {
if (empty($table)) if (empty($table))
throw new InvalidArgumentException("Table parameter must be defined"); throw new InvalidArgumentException("Table parameter must be defined");
if (empty($column)) if (empty($order_column))
throw new InvalidArgumentException("Column parameter must be defined"); throw new InvalidArgumentException("Column parameter must be defined");
if (!array_key_exists('id', $entry)) if (!array_key_exists('id', $entry))
throw new InvalidArgumentException('Entry does not contain ID column'); throw new InvalidArgumentException('Entry does not contain ID column');
if (!array_key_exists($column,$entry)) if (!array_key_exists($order_column,$entry))
throw new InvalidArgumentException('Entry does not contain sorting column'); throw new InvalidArgumentException('Entry does not contain sorting column');
$setOrder = $desiredOrder;
$id = $entry['id'];
// Get position of desired entry:
if (!empty($visibleIds)) if (is_int($afterId) && $afterId > 0)
{ {
// Set order to reflect real position in DB $position = $this->db->from($table)
->select([$order_column])
$allRows = $this->db->from($table) ->where('id',$afterId)
->order_by($order_column)
->select(['id'])
->get() ->get()
->result_array(); ->row_array();
if ($desiredOrder >= count($visibleIds) -1) if ($position === false)
{ {
$setOrder = count($allRows); // Desired last throw new InvalidArgumentException("Could not found service with ID $afterId");
}
$position = intval($position[$order_column]);
} }
else { else {
$position = FALSE;
}
for ($i=0; $i < count($allRows); $i++) if (! $this->insert_row_order($table,$entry,$position,$order_column))
{
if ($i >= count($visibleIds))
{
break;
}
elseif ($i > $desiredOrder)
{
break;
}
elseif (!in_array($allRows[$i]['id'], $visibleIds))
{
$setOrder ++;
}
}
}
}
$currentOrder = intval(
$this->db
->select($order_column)
->from($table)
->where(['id'=>$id])
->limit(1)
->get()
->row_array()
[$order_column]
);
if ($setOrder != $currentOrder)
{
if (! $this->insert_row_order($table,$entry,$setOrder))
{ {
throw new RuntimeException('Could not update order, database error'); throw new RuntimeException('Could not update order, database error');
} }
}
} }
@ -323,13 +293,14 @@ class EA_Model extends CI_Model {
* *
* @param string $table Table * @param string $table Table
* @param array $entry Entry, should be associative array containing columns 'Id' and desired $column sort value. * @param array $entry Entry, should be associative array containing columns 'Id' and desired $column sort value.
* @param int|bool $position Position to set entry to. If set to False, it will be positioned to first.
* @param string $column Column name that contains sorting data (default is 'row_order'). * @param string $column Column name that contains sorting data (default is 'row_order').
* *
* @return bool TRUE on success, FALSE on failure * @return bool TRUE on success, FALSE on failure
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
protected function insert_row_order(string $table, array &$entry, int $position, string $column = 'row_order') protected function insert_row_order(string $table, array &$entry, $position, string $column = 'row_order')
{ {
if (empty($table)) if (empty($table))
throw new InvalidArgumentException("Table parameter must be defined"); throw new InvalidArgumentException("Table parameter must be defined");
@ -341,8 +312,16 @@ class EA_Model extends CI_Model {
if (!array_key_exists($column,$entry)) if (!array_key_exists($column,$entry))
throw new InvalidArgumentException('Entry does not contain sorting column'); throw new InvalidArgumentException('Entry does not contain sorting column');
$movingUp = $position >= intval($entry[$column]);
$newOr = $movingUp? $position +1 : $position; if (is_int($position))
{
$newOr = $position +1;
}
else
{
$newOr = 0;
}
$this->db->update($table, [$column => $newOr ], [ 'id'=> $entry['id'] ]); $this->db->update($table, [$column => $newOr ], [ 'id'=> $entry['id'] ]);

View file

@ -542,17 +542,16 @@ class Services_model extends EA_Model {
* Sort service * Sort service
* *
* @param int $service_id Service ID * @param int $service_id Service ID
* @param int $desiredOrder Desired place in table (relative to visible services) * @param int|bool $afterServiceId ID of service that service should be inserted after, or FALSE to set to beginning
* @param Array [$allServiceIds] Visible service ids to sort on
* *
* @return int New place in table * @return int New place in table
*/ */
public function set_service_order(int $service_id, int $desiredOrder, Array &$allServiceIds = NULL) public function set_service_order(int $service_id, $afterServiceId)
{ {
$service = $this->find($service_id); $service = $this->find($service_id);
$this->insert_row_order_visible('services',$service,$desiredOrder,$allServiceIds); $this->insert_row_order_after('services',$service,$afterServiceId);
return $this->value($service['id'],'row_order'); return $this->value($service['id'],'row_order');
} }

View file

@ -127,20 +127,17 @@ App.Http.Services = (function () {
* *
* @param {Number} serviceId * @param {Number} serviceId
* *
* @param {Number} newOrder * @param {Number} afterId
*
* @param {Array} allIds
* *
* @return {Object} * @return {Object}
*/ */
function sort(serviceId, newOrder, allIds) function sort(serviceId, afterId)
{ {
const url = App.Utils.Url.siteUrl('services/sort'); const url = App.Utils.Url.siteUrl('services/sort');
const data = { const data = {
csrf_token: vars('csrf_token'), csrf_token: vars('csrf_token'),
service_id: serviceId, service_id: serviceId,
new_order : newOrder, after : afterId
allIds
}; };
return $.post(url,data); return $.post(url,data);
} }

View file

@ -95,7 +95,13 @@ App.Pages.Services = (function () {
$services.find('.results').sortable({ $services.find('.results').sortable({
update: function(ev,ui){ update: function(ev,ui){
resetForm(); resetForm();
sort(ui.item.data('id'),ui.item.index()) var afterId;
if (ui.item.index( )== 0)
afterId = -1;
else {
afterId = ui.item.prev('.service-row').data('id');
}
sort(ui.item.data('id'), afterId)
.catch(err => { .catch(err => {
$(this).sortable('cancel'); $(this).sortable('cancel');
$services.find('.form-message').addClass('alert-danger').text(lang('error')).show(); $services.find('.form-message').addClass('alert-danger').text(lang('error')).show();
@ -228,13 +234,13 @@ App.Pages.Services = (function () {
* *
* @param {Number} serviceId Id of service to sort * @param {Number} serviceId Id of service to sort
* *
* @param {Number} newOrder New place in order * @param {Number} afterId Id of service to place after
* *
* @return {Promise<Number>} * @return {Promise<Number>}
*/ */
function sort(serviceId, newOrder){ function sort(serviceId, afterId){
return App.Http.Services.sort(serviceId,newOrder,
$services.find('.results > .service-row').map((i,e)=> e.dataset['id']).get()) return App.Http.Services.sort(serviceId, afterId)
.then(response => { .then(response => {
App.Layouts.Backend.displayNotification(lang('service_saved')); App.Layouts.Backend.displayNotification(lang('service_saved'));
return response.row_order; return response.row_order;