Allow to drag&drop tasks to another list

This commit is contained in:
Thomas Bruederli 2012-09-18 08:53:24 +02:00
parent 6a66bea555
commit 05a1cb527d
5 changed files with 99 additions and 29 deletions

View file

@ -510,6 +510,18 @@ class tasklist_database_driver extends tasklist_driver
return $this->rc->db->affected_rows($query); return $this->rc->db->affected_rows($query);
} }
/**
* Move a single task to another list
*
* @param array Hash array with task properties:
* @return boolean True on success, False on error
* @see tasklist_driver::move_task()
*/
public function move_task($prop)
{
return $this->edit_task($prop);
}
/** /**
* Remove a single task from the database * Remove a single task from the database
* *

View file

@ -663,6 +663,27 @@ class tasklist_kolab_driver extends tasklist_driver
return $saved; return $saved;
} }
/**
* Move a single task to another list
*
* @param array Hash array with task properties:
* @return boolean True on success, False on error
* @see tasklist_driver::move_task()
*/
public function move_task($task)
{
$list_id = $task['list'];
if (!$list_id || !($folder = $this->folders[$list_id]))
return false;
// execute move command
if ($task['_fromlist'] && ($fromfolder = $this->folders[$task['_fromlist']])) {
return $fromfolder->move($task['uid'], $folder->name);
}
return false;
}
/** /**
* Remove a single task from the database * Remove a single task from the database
* *

View file

@ -175,6 +175,17 @@ abstract class tasklist_driver
*/ */
abstract function edit_task($prop); abstract function edit_task($prop);
/**
* Move a single task to another list
*
* @param array Hash array with task properties:
* id: Task identifier
* list: New list identifier to move to
* _fromlist: Previous list identifier
* @return boolean True on success, False on error
*/
abstract function move_task($prop);
/** /**
* Remove a single task from the database * Remove a single task from the database
* *

View file

@ -111,13 +111,13 @@ function rcube_tasklist_ui(settings)
*/ */
function init() function init()
{ {
// sinitialize task list selectors // initialize task list selectors
for (var id in me.tasklists) { for (var id in me.tasklists) {
if ((li = rcmail.get_folder_li(id, 'rcmlitasklist'))) { if ((li = rcmail.get_folder_li(id, 'rcmlitasklist'))) {
init_tasklist_li(li, id); init_tasklist_li(li, id);
} }
if (!me.tasklists.readonly && !me.selected_list) { if (me.tasklists[id].editable && !me.selected_list) {
me.selected_list = id; me.selected_list = id;
rcmail.enable_command('addtask', true); rcmail.enable_command('addtask', true);
$(li).click(); $(li).click();
@ -284,7 +284,7 @@ function rcube_tasklist_ui(settings)
if (item.length && (id = item.data('id')) && (rec = listdata[id])) { if (item.length && (id = item.data('id')) && (rec = listdata[id])) {
var list = rec.list && me.tasklists[rec.list] ? me.tasklists[rec.list] : {}; var list = rec.list && me.tasklists[rec.list] ? me.tasklists[rec.list] : {};
if (rec.readonly || list.readonly) if (rec.readonly || !list.editable)
task_show_dialog(id); task_show_dialog(id);
else else
task_edit_dialog(id, 'edit'); task_edit_dialog(id, 'edit');
@ -674,7 +674,7 @@ function rcube_tasklist_ui(settings)
function draggable_start(event, ui) function draggable_start(event, ui)
{ {
$('.taskhead, #rootdroppable').droppable({ $('.taskhead, #rootdroppable, #'+rcmail.gui_objects.folderlist.id+' li').droppable({
hoverClass: 'droptarget', hoverClass: 'droptarget',
accept: droppable_accept, accept: droppable_accept,
drop: draggable_dropped, drop: draggable_dropped,
@ -694,14 +694,21 @@ function rcube_tasklist_ui(settings)
function droppable_accept(draggable) function droppable_accept(draggable)
{ {
var drag_id = draggable.data('id'), var drag_id = draggable.data('id'),
parent_id = $(this).data('id'), drop_id = $(this).data('id'),
drag_rec = listdata[drag_id] || {}, drag_rec = listdata[drag_id] || {},
drop_rec = listdata[parent_id]; drop_rec = listdata[drop_id];
// drop target is another list
if ($(this).data('type') == 'tasklist') {
var drop_list = me.tasklists[drop_id],
from_list = me.tasklists[drop_rec.list];
return drop_id != drag_rec.list && drop_list && drop_list.editable && from_list && from_list.editable;
}
if (drop_rec && drop_rec.list != drag_rec.list) if (drop_rec && drop_rec.list != drag_rec.list)
return false; return false;
if (parent_id == drag_rec.parent_id) if (drop_id == drag_rec.parent_id)
return false; return false;
while (drop_rec && drop_rec.parent_id) { while (drop_rec && drop_rec.parent_id) {
@ -715,15 +722,25 @@ function rcube_tasklist_ui(settings)
function draggable_dropped(event, ui) function draggable_dropped(event, ui)
{ {
var parent_id = $(this).data('id'), var drop_id = $(this).data('id'),
task_id = ui.draggable.data('id'), task_id = ui.draggable.data('id'),
parent = parent_id ? $('li[rel="'+parent_id+'"] > ul.childtasks', rcmail.gui_objects.resultlist) : $(rcmail.gui_objects.resultlist),
rec = listdata[task_id], rec = listdata[task_id],
li; parent, li;
// dropped on another list -> move
if ($(this).data('type') == 'tasklist') {
if (rec) {
save_task({ id:rec.id, list:drop_id, _fromlist:rec.list }, 'move');
rec.list = drop_id;
}
}
// dropped on a new parent task or root
else {
parent = drop_id ? $('li[rel="'+drop_id+'"] > ul.childtasks', rcmail.gui_objects.resultlist) : $(rcmail.gui_objects.resultlist)
if (rec && parent.length) { if (rec && parent.length) {
// submit changes to server // submit changes to server
rec.parent_id = parent_id || 0; rec.parent_id = drop_id || 0;
save_task(rec, 'edit'); save_task(rec, 'edit');
li = ui.draggable.parent(); li = ui.draggable.parent();
@ -734,6 +751,7 @@ function rcube_tasklist_ui(settings)
}); });
} }
} }
}
/** /**
@ -816,7 +834,7 @@ function rcube_tasklist_ui(settings)
list = rec.list && me.tasklists[rec.list] ? me.tasklists[rec.list] : list = rec.list && me.tasklists[rec.list] ? me.tasklists[rec.list] :
(me.selected_list ? me.tasklists[me.selected_list] : { editable: action=='new' }); (me.selected_list ? me.tasklists[me.selected_list] : { editable: action=='new' });
if (list.readonly || (action == 'edit' && (!rec || rec.readonly))) if (!list.editable || (action == 'edit' && (!rec || rec.readonly)))
return false; return false;
me.selected_task = $.extend({}, rec); // clone task object me.selected_task = $.extend({}, rec); // clone task object
@ -886,7 +904,7 @@ function rcube_tasklist_ui(settings)
$('#taskedit select.edit-alarm-type, #taskedit select.edit-alarm-offset').change(); $('#taskedit select.edit-alarm-type, #taskedit select.edit-alarm-offset').change();
// attachments // attachments
rcmail.enable_command('remove-attachment', !list.readonly); rcmail.enable_command('remove-attachment', list.editable);
me.selected_task.deleted_attachments = []; me.selected_task.deleted_attachments = [];
// we're sharing some code for uploads handling with app.js // we're sharing some code for uploads handling with app.js
rcmail.env.attachments = []; rcmail.env.attachments = [];
@ -1187,7 +1205,7 @@ function rcube_tasklist_ui(settings)
function list_remove(id) function list_remove(id)
{ {
var list = me.tasklists[id]; var list = me.tasklists[id];
if (list && !list.readonly) { if (list && list.editable) {
alert('To be implemented') alert('To be implemented')
} }
} }
@ -1348,13 +1366,15 @@ function rcube_tasklist_ui(settings)
$(li).click(function(e){ $(li).click(function(e){
var id = $(this).data('id'); var id = $(this).data('id');
rcmail.select_folder(id, 'rcmlitasklist'); rcmail.select_folder(id, 'rcmlitasklist');
rcmail.enable_command('list-edit', 'list-remove', 'import', !me.tasklists[id].readonly); rcmail.enable_command('list-edit', 'list-remove', 'import', me.tasklists[id].editable);
me.selected_list = id; me.selected_list = id;
}) })
.dblclick(function(e){ .dblclick(function(e){
list_edit_dialog($(this).data('id')); list_edit_dialog($(this).data('id'));
}) })
.data('id', id); .data('id', id)
.data('type', 'tasklist')
.addClass(me.tasklists[id].editable ? null : 'readonly');
} }

View file

@ -177,6 +177,12 @@ class tasklist extends rcube_plugin
} }
break; break;
case 'move':
if ($success = $this->driver->move_task($rec)) {
$refresh = $this->driver->get_task($rec);
}
break;
case 'delete': case 'delete':
if (!($success = $this->driver->delete_task($rec, false))) if (!($success = $this->driver->delete_task($rec, false)))
$this->rc->output->command('plugin.reload_data'); $this->rc->output->command('plugin.reload_data');