diff options
author | svncommit <devs@roundcube.net> | 2007-09-25 07:33:37 +0000 |
---|---|---|
committer | svncommit <devs@roundcube.net> | 2007-09-25 07:33:37 +0000 |
commit | b0dbf3ce3e8a7b72e9d2c2376015f1f47de84d12 (patch) | |
tree | de3e0c5a2530071cb449187784d67433d41dcfbb | |
parent | 5f041a37473041070df31233c31885bcd9c36dd1 (diff) |
Enable drag-/dropping of folders to a new parent folder, closes #1457344.
-rw-r--r-- | CHANGELOG | 5 | ||||
-rw-r--r-- | program/js/app.js | 123 | ||||
-rw-r--r-- | program/js/common.js | 8 | ||||
-rw-r--r-- | program/steps/settings/manage_folders.inc | 18 | ||||
-rw-r--r-- | skins/default/settings.css | 20 |
5 files changed, 160 insertions, 14 deletions
@@ -1,6 +1,11 @@ CHANGELOG RoundCube Webmail --------------------------- +2007/09/25 (robin) +---------- +- Enable drag-/dropping of folders to a new parent folder (#1457344) + + 2007/09/24 (robin) ---------- - Fix preview pane size for Safari & Konqueror (#1484187) diff --git a/program/js/app.js b/program/js/app.js index 1711ab592..43467e4d4 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -286,6 +286,9 @@ function rcube_webmail() this.identity_list.highlight_row(this.env.iid); } + if (this.gui_objects.subscriptionlist) + this.init_subscription_list(); + break; case 'login': @@ -1157,6 +1160,8 @@ function rcube_webmail() return (id != this.env.mailbox); else if (this.task == 'addressbook') return (id != this.env.source && this.env.address_sources[id] && !this.env.address_sources[id].readonly); + else if (this.task == 'settings') + return (id != this.env.folder); }; @@ -2397,6 +2402,18 @@ function rcube_webmail() /********* user settings methods *********/ /*********************************************************/ + this.init_subscription_list = function() + { + var p = this; + this.subscription_list = new rcube_list_widget(this.gui_objects.subscriptionlist, {multiselect:false, draggable:true, keyboard:false}); + this.subscription_list.addEventListener('select', function(o){ p.subscription_select(o); }); + this.subscription_list.addEventListener('mouseover', function(o){ p.subscription_select_parent(o); }); + this.subscription_list.addEventListener('mouseout', function(o){ p.subscription_unselect_parent(o); }); + this.subscription_list.addEventListener('dragstart', function(o){ p.drag_active = true; }); + this.subscription_list.addEventListener('dragend', function(o){ p.subscription_move_folder(o); }); + this.subscription_list.init(); + } + this.identity_select = function(list) { var id; @@ -2444,6 +2461,76 @@ function rcube_webmail() }; + this.focus_subscription = function(id) + { + var row; + var reg = RegExp('['+RegExp.escape(this.env.delimiter)+']?[^'+RegExp.escape(this.env.delimiter)+']+$'); + if (this.drag_active && this.check_droptarget(id) && + (id != this.env.folder.replace(reg, '')) && + (row = document.getElementById(this.get_folder_row_id(id)))) + if (find_in_array(this.env.defaultfolders, id)>=0) + { + if (this.env.folder.replace(reg, '')!='') + { + this.set_env('dstfolder', this.env.delimiter); + this.set_classname(this.subscription_list.frame, 'droptarget', true); + } + } + else + { + this.set_env('dstfolder', id); + this.set_classname(row, 'droptarget', true); + } + } + + + this.unfocus_subscription = function(id) + { + var row; + if (row = document.getElementById(this.get_folder_row_id(id))) + { + this.set_env('dstfolder', null); + if (find_in_array(this.env.defaultfolders, id)>=0) + this.set_classname(this.subscription_list.frame, 'droptarget', false); + else + this.set_classname(row, 'droptarget', false); + } + } + + + this.subscription_select = function(list) + { + var id; + if (id = list.get_single_selection()) + { + var folder = this.env.subscriptionrows['rcmrow'+id][0]; + if (this.env.folder && (this.env.folder==folder)) + { + list.clear_selection(); + this.set_env('folder', null); + } + else + this.set_env('folder', folder); + } + }; + + + this.subscription_move_folder = function(list) + { + var reg = RegExp('['+RegExp.escape(this.env.delimiter)+']?[^'+RegExp.escape(this.env.delimiter)+']+$'); + if (this.env.folder && this.env.dstfolder && (this.env.dstfolder != this.env.folder) && + (this.env.dstfolder != this.env.folder.replace(reg, ''))) + { + var reg = new RegExp('[^'+RegExp.escape(this.env.delimiter)+']*['+RegExp.escape(this.env.delimiter)+']', 'g'); + var basename = this.env.folder.replace(reg, ''); + var newname = this.env.dstfolder==this.env.delimiter ? basename : this.env.dstfolder+this.env.delimiter+basename; + this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.folder)+'&_folder_newname='+urlencode(newname)); + } + this.drag_active = false; + this.unfocus_subscription(this.env.dstfolder); + }; + + // tell server to create and subscribe a new mailbox this.create_folder = function(name) { @@ -2499,9 +2586,12 @@ function rcube_webmail() if (id && (row = document.getElementById(id))) { + var reg = new RegExp('.*['+RegExp.escape(this.env.delimiter)+']'); this.name_input = document.createElement('INPUT'); - this.name_input.value = this.env.subscriptionrows[id][1]; + this.name_input.value = folder.replace(reg, ''); this.name_input.style.width = '100%'; + reg = new RegExp('['+RegExp.escape(this.env.delimiter)+']?[^'+RegExp.escape(this.env.delimiter)+']+$'); + this.name_input.setAttribute('parent', folder.replace(reg, '')); this.name_input.onkeypress = function(e){ rcmail.name_input_keypress(e); }; row.cells[0].replaceChild(this.name_input, row.cells[0].firstChild); @@ -2519,7 +2609,10 @@ function rcube_webmail() { var cell = this.name_input ? this.name_input.parentNode : null; if (cell && this.edit_folder && this.env.subscriptionrows[this.edit_folder]) - cell.innerHTML = this.env.subscriptionrows[this.edit_folder][1]; + { + var reg = new RegExp('[^'+RegExp.escape(this.env.delimiter)+']*['+RegExp.escape(this.env.delimiter)+']', 'g'); + cell.innerHTML = this.env.subscriptionrows[this.edit_folder][1].replace(reg, ' '); + } this.edit_folder = null; }; @@ -2535,7 +2628,11 @@ function rcube_webmail() { var newname = this.name_input ? this.name_input.value : null; if (this.edit_folder && newname) - this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.subscriptionrows[this.edit_folder][0])+'&_folder_newname='+urlencode(newname)); + { + if (this.name_input.getAttribute('parent') && this.name_input.getAttribute('parent')!='') + newname = this.name_input.getAttribute('parent')+this.env.delimiter+newname; + this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.subscriptionrows[this.edit_folder][0])+'&_folder_newname='+urlencode(newname)); + } } // escape else if (key==27) @@ -2611,6 +2708,10 @@ function rcube_webmail() } this.sort_subscription_list(); + this.init_subscription_list(); + + if (document.getElementById('rcmrow'+id).scrollIntoView) + document.getElementById('rcmrow'+id).scrollIntoView(); }; @@ -2765,19 +2866,19 @@ function rcube_webmail() var index = new Array(); var tbody = this.gui_objects.subscriptionlist.tBodies[0]; var swapped = false; - for (var i = 0; i<(tbody.childNodes.length-1); i++) + for (var i = 0; i<tbody.childNodes.length; i++) if (this.env.subscriptionrows[tbody.childNodes[i].id]!=null) index.push(i); for (i = 0; i<(index.length-1); i++) { - if (this.env.subscriptionrows[tbody.childNodes[index[i]].id][0]> - this.env.subscriptionrows[tbody.childNodes[index[i+1]].id][0]) + var one = tbody.childNodes[index[i]]; + var two = tbody.childNodes[index[i+1]]; + if (this.env.subscriptionrows[one.id][0].toLowerCase()> + this.env.subscriptionrows[two.id][0].toLowerCase()) { - var swap = tbody.replaceChild(tbody.childNodes[index[i]], tbody.childNodes[index[i+1]]); - if (typeof(tbody.childNodes[index[i]]) != 'undefined') - tbody.insertBefore(swap, tbody.childNodes[index[i]]) - else - tbody.appendChild(swap); + var swap = one.cloneNode(true); + tbody.replaceChild(swap, two); + tbody.replaceChild(two, one); swapped = true; } } diff --git a/program/js/common.js b/program/js/common.js index d9216a58d..da1c09225 100644 --- a/program/js/common.js +++ b/program/js/common.js @@ -624,3 +624,11 @@ var bw = new roundcube_browser(); if (!window.console) console = new rcube_console(); + + +// Add escape() method to RegExp object +// http://dev.rubyonrails.org/changeset/7271 +RegExp.escape = function(str) + { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); + } diff --git a/program/steps/settings/manage_folders.inc b/program/steps/settings/manage_folders.inc index b08d9ccc9..b39cef612 100644 --- a/program/steps/settings/manage_folders.inc +++ b/program/steps/settings/manage_folders.inc @@ -22,6 +22,8 @@ // init IMAP connection rcmail_imap_init(TRUE); +$OUTPUT->include_script('list.js'); + // subscribe to one or more mailboxes if ($_action=='subscribe') @@ -71,7 +73,8 @@ else if ($_action=='rename-folder') if ($rename && $OUTPUT->ajax_call) { - $OUTPUT->command('replace_folder_row', $oldname, $rename, rcube_charset_convert($rename, 'UTF-7')); + $display_rename = str_repeat(' ', substr_count($rename, $IMAP->delimiter)) . preg_replace('/.*' . preg_quote($IMAP->delimiter) . '/', '', rcube_charset_convert($rename, 'UTF-7')); + $OUTPUT->command('replace_folder_row', $oldname, $rename, $display_rename); $OUTPUT->command('reset_folder_rename'); $OUTPUT->send(); } @@ -159,14 +162,21 @@ function rcube_subscription_form($attrib) $protected = ($CONFIG['protect_default_folders'] == TRUE && in_array($folder,$CONFIG['default_imap_folders'])); $zebra_class = $i%2 ? 'even' : 'odd'; $folder_js = JQ($folder); - $folder_html = $CONFIG['protect_default_folders'] && in_array($folder, $CONFIG['default_imap_folders']) ? rcube_label(strtolower($folder)) : rcube_charset_convert($folder, 'UTF-7'); + $display_folder = str_repeat(' ', substr_count($folder, $IMAP->delimiter)) . preg_replace('/.*' . preg_quote($IMAP->delimiter) . '/', '', rcube_charset_convert($folder, 'UTF-7')); + $folder_html = $CONFIG['protect_default_folders'] && in_array($folder, $CONFIG['default_imap_folders']) ? rcube_label(strtolower($folder)) : $display_folder; if (!$protected) $a_js_folders['rcmrow'.($i+1)] = array($folder, rcube_charset_convert($folder, 'UTF-7')); - $out .= sprintf('<tr id="rcmrow%d" class="%s"><td>%s</td>', + $out .= sprintf('<tr id="rcmrow%d" class="%s"' . + ' onmouseover="return %s.focus_subscription(\'%s\')"' . + ' onmouseout="return %s.unfocus_subscription(\'%s\')"><td>%s</td>', $i+1, $zebra_class, + JS_OBJECT_NAME, + $folder_js, + JS_OBJECT_NAME, + $folder_js, Q($folder_html)); if ($protected) @@ -197,6 +207,8 @@ function rcube_subscription_form($attrib) $OUTPUT->add_gui_object('subscriptionlist', $attrib['id']); $OUTPUT->set_env('subscriptionrows', $a_js_folders); + $OUTPUT->set_env('defaultfolders', $CONFIG['default_imap_folders']); + $OUTPUT->set_env('delimiter', $IMAP->delimiter); return $out; } diff --git a/skins/default/settings.css b/skins/default/settings.css index ba5b65b31..53e948c7e 100644 --- a/skins/default/settings.css +++ b/skins/default/settings.css @@ -76,6 +76,12 @@ span.tablink-selected a height: expression((parseInt(document.documentElement.clientHeight)-215)+'px'); } +#folder-manager.droptarget +{ + border: 1px solid #CC3333; + background-color: #FFFFA6; +} + #identities-table { width: 600px; @@ -161,6 +167,20 @@ div.settingspart white-space: nowrap; border-bottom: 1px solid #EBEBEB; background-color: #F9F9F9; + cursor: pointer; +} + +#subscription-table tr.selected td, +#subscription-table tr.selected td a +{ + color: #FFFFFF; + background-color: #CC3333; +} + +#subscription-table tr.droptarget td, +#subscription-table tr.droptarget td a +{ + background-color: #FFFFA6; } #subscription-table td.name |