From 9b3fdc25c171d2b2461af42224ea16ad6c032c49 Mon Sep 17 00:00:00 2001 From: alecpl <alec@alec.pl> Date: Fri, 19 Mar 2010 07:20:12 -0400 Subject: [PATCH] - Implemented messages copying using drag&drop + SHIFT (#1484086) --- skins/default/common.css | 38 +++++++ CHANGELOG | 1 program/steps/mail/copy.inc | 59 +++++++++++ skins/default/templates/mail.html | 7 + program/include/rcube_imap.php | 57 ++++++++++- program/localization/en_US/messages.inc | 1 program/steps/mail/func.inc | 5 program/localization/en_US/labels.inc | 2 program/localization/pl_PL/labels.inc | 2 program/include/rcube_template.php | 2 program/localization/pl_PL/messages.inc | 3 skins/default/functions.js | 6 + program/js/app.js | 68 ++++++++++++- 13 files changed, 235 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9a03013..4fb3198 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG RoundCube Webmail =========================== +- Implemented messages copying using drag&drop + SHIFT (#1484086) - Improved performance of folders operations (#1486525) - Fix blocked.gif attachment is not attached to the message (#1486516) - Managesieve: import from Horde-INGO diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index 1e3c09d..651ecd6 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -2202,6 +2202,13 @@ $to_mbox = $this->mod_mailbox($to_mbox); $from_mbox = $from_mbox ? $this->mod_mailbox($from_mbox) : $this->mailbox; + // convert the list of uids to array + $a_uids = is_string($uids) ? explode(',', $uids) : (is_array($uids) ? $uids : NULL); + + // exit if no message uids are specified + if (!is_array($a_uids) || empty($a_uids)) + return false; + // make sure mailbox exists if ($to_mbox != 'INBOX' && !$this->mailbox_exists($tbox)) { @@ -2210,13 +2217,6 @@ else return false; } - - // convert the list of uids to array - $a_uids = is_string($uids) ? explode(',', $uids) : (is_array($uids) ? $uids : NULL); - - // exit if no message uids are specified - if (!is_array($a_uids) || empty($a_uids)) - return false; // flag messages as read before moving them $config = rcmail::get_instance()->config; @@ -2270,6 +2270,49 @@ /** + * Copy a message from one mailbox to another + * + * @param string List of UIDs to copy, separated by comma + * @param string Target mailbox + * @param string Source mailbox + * @return boolean True on success, False on error + */ + function copy_message($uids, $to_mbox, $from_mbox='') + { + $fbox = $from_mbox; + $tbox = $to_mbox; + $to_mbox = $this->mod_mailbox($to_mbox); + $from_mbox = $from_mbox ? $this->mod_mailbox($from_mbox) : $this->mailbox; + + // convert the list of uids to array + $a_uids = is_string($uids) ? explode(',', $uids) : (is_array($uids) ? $uids : NULL); + + // exit if no message uids are specified + if (!is_array($a_uids) || empty($a_uids)) + return false; + + // make sure mailbox exists + if ($to_mbox != 'INBOX' && !$this->mailbox_exists($tbox)) + { + if (in_array($tbox, $this->default_folders)) + $this->create_mailbox($tbox, true); + else + return false; + } + + // copy messages + $iil_copy = iil_C_Copy($this->conn, join(',', $a_uids), $from_mbox, $to_mbox); + $copied = !($iil_copy === false || $iil_copy < 0); + + if ($copied) { + $this->_clear_messagecount($to_mbox); + } + + return $copied; + } + + + /** * Mark messages as deleted and expunge mailbox * * @param string List of UIDs to move, separated by comma diff --git a/program/include/rcube_template.php b/program/include/rcube_template.php index 6de3272..ad498c9 100755 --- a/program/include/rcube_template.php +++ b/program/include/rcube_template.php @@ -860,7 +860,7 @@ if (!$attrib['href']) { $attrib['href'] = '#'; } - if ($command) { + if ($command && !$attrib['onclick']) { $attrib['onclick'] = sprintf( "return %s.command('%s','%s',this)", JS_OBJECT_NAME, diff --git a/program/js/app.js b/program/js/app.js index 87ee76c..7c86bb0 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -197,7 +197,7 @@ if (this.env.action=='show' || this.env.action=='preview') { - this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', + this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'copy', 'delete', 'open', 'mark', 'edit', 'viewsource', 'download', 'print', 'load-attachment', 'load-headers', true); if (this.env.next_uid) @@ -672,6 +672,11 @@ this.move_messages(props); else if (this.task == 'addressbook' && this.drag_active) this.copy_contact(null, props); + break; + + case 'copy': + if (this.task == 'mail') + this.copy_messages(props); break; case 'mark': @@ -1194,10 +1199,14 @@ // handle mouse release when dragging if (this.drag_active && model && this.env.last_folder_target) { + var mbox = model[this.env.last_folder_target].id; + $(this.get_folder_li(this.env.last_folder_target)).removeClass('droptarget'); - this.command('moveto', model[this.env.last_folder_target].id); this.env.last_folder_target = null; list.draglayer.hide(); + + if (!this.drag_menu(e, mbox)) + this.command('moveto', mbox); } // reset 'pressed' buttons @@ -1207,6 +1216,29 @@ this.button_out(this.buttons_sel[id], id); this.buttons_sel = {}; } + }; + + this.drag_menu = function(e, mbox) + { + var modkey = rcube_event.get_modifier(e); + var menu = $('#'+this.gui_objects.message_dragmenu); + + if (menu && modkey == SHIFT_KEY) { + var pos = rcube_event.get_mouse_pos(e); + this.env.drag_mbox = mbox; + menu.css({top: (pos.y-10)+'px', left: (pos.x-10)+'px'}).show(); + return true; + } + }; + + this.drag_menu_action = function(action) + { + var menu = $('#'+this.gui_objects.message_dragmenu); + if (menu) { + menu.hide(); + } + this.command(action, this.env.drag_mbox); + this.env.drag_mbox = null; }; this.drag_start = function(list) @@ -1389,12 +1421,12 @@ { this.enable_command('reply', 'reply-all', 'forward', false); this.enable_command('show', 'print', 'open', 'edit', 'download', 'viewsource', selected); - this.enable_command('delete', 'moveto', 'mark', (list.selection.length > 0 ? true : false)); + this.enable_command('delete', 'moveto', 'copy', 'mark', (list.selection.length > 0 ? true : false)); } else { this.enable_command('show', 'reply', 'reply-all', 'forward', 'print', 'edit', 'open', 'download', 'viewsource', selected); - this.enable_command('delete', 'moveto', 'mark', (list.selection.length > 0 ? true : false)); + this.enable_command('delete', 'moveto', 'copy', 'mark', (list.selection.length > 0 ? true : false)); } // start timer for message preview (wait for double click) @@ -2119,6 +2151,32 @@ $(row.obj).addClass('unroot'); else $(row.obj).removeClass('unroot'); + }; + + // copy selected messages to the specified mailbox + this.copy_messages = function(mbox) + { + // exit if current or no mailbox specified or if selection is empty + if (!mbox || mbox == this.env.mailbox || (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length))) + return; + + var add_url = '&_target_mbox='+urlencode(mbox)+'&_from='+(this.env.action ? this.env.action : ''); + var a_uids = new Array(); + + if (this.env.uid) + a_uids[0] = this.env.uid; + else + { + var selection = this.message_list.get_selection(); + var id; + for (var n=0; n<selection.length; n++) { + id = selection[n]; + a_uids[a_uids.length] = id; + } + } + + // send request to server + this.http_post('copy', '_uid='+a_uids.join(',')+'&_mbox='+urlencode(this.env.mailbox)+add_url, false); }; // move selected messages to the specified mailbox @@ -4625,7 +4683,7 @@ if (this.env.contentframe) this.show_contentframe(false); // disable commands useless when mailbox is empty - this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', + this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'copy', 'delete', 'mark', 'viewsource', 'open', 'edit', 'download', 'print', 'load-attachment', 'purge', 'expunge', 'select-all', 'select-none', 'sort', 'expand-all', 'expand-unread', 'collapse-all', false); diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index 3059692..1a1291c 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -59,6 +59,8 @@ $labels['threadsfromto'] = 'Threads $from to $to of $count'; $labels['messagenrof'] = 'Message $nr of $count'; +$labels['copy'] = 'Copy'; +$labels['move'] = 'Move'; $labels['moveto'] = 'Move to...'; $labels['download'] = 'Download'; diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc index b0a812c..e8c5502 100644 --- a/program/localization/en_US/messages.inc +++ b/program/localization/en_US/messages.inc @@ -86,6 +86,7 @@ $messages['sourceisreadonly'] = 'This address source is read only'; $messages['errorsavingcontact'] = 'Could not save the contact address'; $messages['movingmessage'] = 'Moving message...'; +$messages['copyingmessage'] = 'Copying message...'; $messages['receiptsent'] = 'Successfully sent a read receipt'; $messages['errorsendingreceipt'] = 'Could not send the receipt'; $messages['nodeletelastidentity'] = 'You cannot delete this identity, it\'s your last one.'; diff --git a/program/localization/pl_PL/labels.inc b/program/localization/pl_PL/labels.inc index b2897b2..d6af5ac 100644 --- a/program/localization/pl_PL/labels.inc +++ b/program/localization/pl_PL/labels.inc @@ -52,6 +52,8 @@ $labels['messagesfromto'] = 'Wiadomości od $from do $to z $count'; $labels['messagenrof'] = 'Wiadomość $nr z $count'; $labels['moveto'] = 'Przenieś do...'; +$labels['move'] = 'Przenieś'; +$labels['copy'] = 'Kopiuj'; $labels['download'] = 'Pobierz'; $labels['filename'] = 'Nazwa pliku'; $labels['filesize'] = 'Rozmiar pliku'; diff --git a/program/localization/pl_PL/messages.inc b/program/localization/pl_PL/messages.inc index 314b585..641d1ef 100644 --- a/program/localization/pl_PL/messages.inc +++ b/program/localization/pl_PL/messages.inc @@ -6,7 +6,7 @@ | language/pl_PL/messages.inc | | | | Language file of the RoundCube Webmail client | - | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland | + | Copyright (C) 2005-2010, RoundCube Dev. - Switzerland | | Licensed under the GNU GPL | | | +-----------------------------------------------------------------------+ @@ -89,6 +89,7 @@ $messages['sourceisreadonly'] = 'Źródło adresu jest tylko do odczytu'; $messages['errorsavingcontact'] = 'Nie można było zapisać adresu kontaktu'; $messages['movingmessage'] = 'Przenoszenie wiadomości...'; +$messages['copyingmessage'] = 'Kopiowanie wiadomości...'; $messages['receiptsent'] = 'Pomyślnie wysłano potwierdzenie dostarczenia'; $messages['errorsendingreceipt'] = 'Nie można wysłać potwierdzenia'; $messages['nodeletelastidentity'] = 'Nie można skasować tej tożsamości, ponieważ jest ostatnią.'; diff --git a/program/steps/mail/copy.inc b/program/steps/mail/copy.inc new file mode 100644 index 0000000..e2270a7 --- /dev/null +++ b/program/steps/mail/copy.inc @@ -0,0 +1,59 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/steps/mail/copy.inc | + | | + | This file is part of the RoundCube Webmail client | + | Copyright (C) 2005-2010, RoundCube Dev. - Switzerland | + | Licensed under the GNU GPL | + | | + | PURPOSE: | + | Copy the submitted messages to a specific mailbox | + | | + +-----------------------------------------------------------------------+ + | Author: Aleksander Machniak <alec@alec.pl> | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +// only process ajax requests +if (!$OUTPUT->ajax_call) + return; + +// count messages before changing anything +$old_count = $IMAP->messagecount(NULL, $IMAP->threading ? 'THREADS' : 'ALL'); +$old_pages = ceil($old_count / $IMAP->page_size); + +// move messages +if (!empty($_POST['_uid']) && !empty($_POST['_target_mbox'])) { + $count = sizeof(explode(',', ($uids = get_input_value('_uid', RCUBE_INPUT_POST)))); + $target = get_input_value('_target_mbox', RCUBE_INPUT_POST); + $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); + + $copied = $IMAP->copy_message($uids, $target, $mbox); + + if (!$copied) { + // send error message + if ($_POST['_from'] != 'show') + $OUTPUT->command('list_mailbox'); + $OUTPUT->show_message('errorcopying', 'error'); + $OUTPUT->send(); + exit; + } + + rcmail_send_unread_count($target, true); + + $OUTPUT->command('set_quota', rcmail_quota_content()); +} +// unknown action or missing query param +else { + exit; +} + +// send response +$OUTPUT->send(); + +?> diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 09a2492..e8600ef 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -130,7 +130,8 @@ $OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']); if (!$OUTPUT->ajax_call) - $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', 'movingmessage'); + $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', + 'movingmessage', 'copyingmessage', 'copy', 'move'); $OUTPUT->set_pagetitle(rcmail_localize_foldername($mbox_name)); } @@ -1457,7 +1458,6 @@ return false; } - function rcmail_search_filter($attrib) { global $OUTPUT, $CONFIG; @@ -1490,6 +1490,7 @@ return $out; } + // register UI objects $OUTPUT->add_handlers(array( 'mailboxlist' => 'rcmail_mailbox_list', diff --git a/skins/default/common.css b/skins/default/common.css index 5977087..c010128 100644 --- a/skins/default/common.css +++ b/skins/default/common.css @@ -349,6 +349,44 @@ -webkit-box-shadow: #999 1px 1px 12px; } +.popupmenu ul +{ + margin: -4px 0; + padding: 0; + list-style: none; +} + +.popupmenu ul li +{ + font-size: 11px; + white-space: nowrap; + min-width: 100px; + margin: 3px -4px; +} + +.popupmenu li a +{ + display: block; + color: #a0a0a0; + padding: 2px 10px; + text-decoration: none; + min-height: 14px; +} + +.popupmenu li a.active, +.popupmenu li a.active:active, +.popupmenu li a.active:visited +{ + color: #333; +} + +.popupmenu li a.active:hover +{ + color: #fff; + background-color: #c00; +} + + /***** common table settings ******/ diff --git a/skins/default/functions.js b/skins/default/functions.js index 4ee2a9d..6d0641d 100644 --- a/skins/default/functions.js +++ b/skins/default/functions.js @@ -125,6 +125,7 @@ this.searchmenu = $('#searchmenu'); this.messagemenu = $('#messagemenu'); this.listmenu = $('#listmenu'); + this.dragmessagemenu = $('#dragmessagemenu'); } rcube_mail_ui.prototype = { @@ -259,6 +260,8 @@ this.show_markmenu(false); else if (this.messagemenu && this.messagemenu.is(':visible') && target != rcube_find_object('messagemenulink')) this.show_messagemenu(false); + else if (this.dragmessagemenu && this.dragmessagemenu.is(':visible') && !rcube_mouse_is_over(evt, rcube_find_object('dragmessagemenu'))) + this.dragmessagemenu.hide(); else if (this.listmenu && this.listmenu.is(':visible') && target != rcube_find_object('listmenulink')) { var menu = rcube_find_object('listmenu'); while (target.parentNode) { @@ -290,6 +293,8 @@ this.show_messagemenu(false); if (this.listmenu && this.listmenu.is(':visible')) this.show_listmenu(false); + if (this.dragmessagemenu && this.dragmessagemenu.is(':visible')) + this.dragmessagemenu.hide(); } } @@ -304,4 +309,5 @@ rcube_event.add_listener({ object:rcmail_ui, method:'body_keypress', event:'keypress' }); rcmail.addEventListener('menu-open', 'open_listmenu', rcmail_ui); rcmail.addEventListener('menu-save', 'save_listmenu', rcmail_ui); + rcmail.gui_object('message_dragmenu', 'dragmessagemenu'); } diff --git a/skins/default/templates/mail.html b/skins/default/templates/mail.html index c66bc58..206f101 100644 --- a/skins/default/templates/mail.html +++ b/skins/default/templates/mail.html @@ -152,6 +152,13 @@ <roundcube:button command="reset-search" id="searchreset" image="/images/icons/reset.gif" title="resetsearch" /> </div> +<div id="dragmessagemenu" class="popupmenu"> + <ul> + <li><roundcube:button command="moveto" onclick="return rcmail.drag_menu_action('moveto')" label="move" classAct="active" /></li> + <li><roundcube:button command="copy" onclick="return rcmail.drag_menu_action('copy')" label="copy" classAct="active" /></li> + </ul> +</div> + <div id="listmenu" class="popupmenu"> <fieldset class="thinbordered"><legend><roundcube:label name="listmode" /></legend> <ul class="toolbarmenu"> -- Gitblit v1.9.1