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');
}
$newOrder = request('new_order');
if ( (($newOrder = filter_var($newOrder,FILTER_VALIDATE_INT)) === FALSE) ||
$newOrder < 0)
$insertAfterId = request('after');
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 (empty($visibleServices))
if ($insertAfterId <= 0)
{
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['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);
}

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 array $entry Entity
* @param int $desiredOrder Desired place in table (relative to visible entities)
* @param Array [$visibleIds] Visible ids to sort on
* @param string [$order_column] Ordering Column name
* @param array $entry Entity to insert
* @param mixed|bool $afterId ID of entry where to insert at. Or false to set at beginning
* @param string [$order_column] Ordering Column name (Default: row_order)
*
* @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))
throw new InvalidArgumentException("Table parameter must be defined");
if (empty($column))
if (empty($order_column))
throw new InvalidArgumentException("Column parameter must be defined");
if (!array_key_exists('id', $entry))
throw new InvalidArgumentException('Entry does not contain ID column');
if (!array_key_exists($column,$entry))
throw new InvalidArgumentException('Entry does not contain sorting column');
if (!array_key_exists($order_column,$entry))
throw new InvalidArgumentException('Entry does not contain sorting column');
$setOrder = $desiredOrder;
$id = $entry['id'];
// Get position of desired entry:
if (is_int($afterId) && $afterId > 0)
{
$position = $this->db->from($table)
->select([$order_column])
->where('id',$afterId)
->get()
->row_array();
if ($position === false)
{
throw new InvalidArgumentException("Could not found service with ID $afterId");
}
$position = intval($position[$order_column]);
}
else {
$position = FALSE;
}
if (! $this->insert_row_order($table,$entry,$position,$order_column))
{
throw new RuntimeException('Could not update order, database error');
}
if (!empty($visibleIds))
{
// Set order to reflect real position in DB
$allRows = $this->db->from($table)
->order_by($order_column)
->select(['id'])
->get()
->result_array();
if ($desiredOrder >= count($visibleIds) -1)
{
$setOrder = count($allRows); // Desired last
}
else {
for ($i=0; $i < count($allRows); $i++)
{
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');
}
}
}
@ -323,13 +293,14 @@ class EA_Model extends CI_Model {
*
* @param string $table Table
* @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').
*
* @return bool TRUE on success, FALSE on failure
* @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))
throw new InvalidArgumentException("Table parameter must be defined");
@ -341,8 +312,16 @@ class EA_Model extends CI_Model {
if (!array_key_exists($column,$entry))
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'] ]);

View file

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

View file

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

View file

@ -95,7 +95,13 @@ App.Pages.Services = (function () {
$services.find('.results').sortable({
update: function(ev,ui){
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 => {
$(this).sortable('cancel');
$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} newOrder New place in order
* @param {Number} afterId Id of service to place after
*
* @return {Promise<Number>}
*/
function sort(serviceId, newOrder){
return App.Http.Services.sort(serviceId,newOrder,
$services.find('.results > .service-row').map((i,e)=> e.dataset['id']).get())
function sort(serviceId, afterId){
return App.Http.Services.sort(serviceId, afterId)
.then(response => {
App.Layouts.Backend.displayNotification(lang('service_saved'));
return response.row_order;