summaryrefslogtreecommitdiff
path: root/program
diff options
context:
space:
mode:
Diffstat (limited to 'program')
-rw-r--r--program/js/app.js129
-rw-r--r--program/js/treelist.js67
-rw-r--r--program/steps/settings/folders.inc70
-rw-r--r--program/steps/settings/func.inc2
4 files changed, 148 insertions, 120 deletions
diff --git a/program/js/app.js b/program/js/app.js
index db9a2ff5f..2b9c3f0d7 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -1856,9 +1856,6 @@ function rcube_webmail()
&& !this.env.mailboxes[id].virtual
&& (this.env.mailboxes[id].id != this.env.mailbox || this.is_multifolder_listing())) ? 1 : 0;
- case 'settings':
- return id != this.env.mailbox ? 1 : 0;
-
case 'addressbook':
var target;
if (id != this.env.source && (target = this.env.contactfolders[id])) {
@@ -5765,62 +5762,38 @@ function rcube_webmail()
this.last_sub_rx = RegExp('['+delim+']?[^'+delim+']+$');
- this.subscription_list = new rcube_list_widget(this.gui_objects.subscriptionlist,
- {multiselect:false, draggable:true, keyboard:true, toggleselect:true});
- this.subscription_list
- .addEventListener('select', function(o){ ref.subscription_select(o); })
- .addEventListener('dragstart', function(o){ ref.drag_active = true; })
- .addEventListener('dragend', function(o){ ref.subscription_move_folder(o); })
- .addEventListener('initrow', function (row) {
- row.obj.onmouseover = function() { ref.focus_subscription(row.id); };
- row.obj.onmouseout = function() { ref.unfocus_subscription(row.id); };
- })
- .init()
- .focus();
-
- $('#mailboxroot')
- .mouseover(function(){ ref.focus_subscription(this.id); })
- .mouseout(function(){ ref.unfocus_subscription(this.id); })
- };
-
- this.focus_subscription = function(id)
- {
- var row, folder;
+ this.subscription_list = new rcube_treelist_widget(this.gui_objects.subscriptionlist, {
+ selectable: true
+ });
- if (this.drag_active && this.env.mailbox && (row = document.getElementById(id)))
- if (this.env.subscriptionrows[id] &&
- (folder = this.env.subscriptionrows[id][0]) !== null
- ) {
- if (this.check_droptarget(folder) &&
- !this.env.subscriptionrows[this.get_folder_row_id(this.env.mailbox)][2] &&
- folder != this.env.mailbox.replace(this.last_sub_rx, '') &&
- !folder.startsWith(this.env.mailbox + this.env.delimiter)
- ) {
- this.env.dstfolder = folder;
- $(row).addClass('droptarget');
+ this.subscription_list
+ .addEventListener('select', function(node) { ref.subscription_select(node.id); })
+ .draggable({cancel: '#mailboxroot'})
+ .droppable({
+ // @todo: find better way, accept callback is executed for every folder
+ // on the list when dragging starts (and stops), this is slow, but
+ // I didn't find a method to check droptarget on over event
+ accept: function(node) {
+ var source = ref.env.subscriptionrows[$(node).attr('id')],
+ dest = ref.env.subscriptionrows[this.id],
+ source_name = source[0],
+ dest_name = dest[0];
+
+ return !source[2]
+ && dest_name != source_name.replace(ref.last_sub_rx, '')
+ && !dest_name.startsWith(source_name + ref.env.delimiter);
+ },
+ drop: function(e, ui) {
+ ref.subscription_move_folder(ui.draggable.attr('id'), this.id);
}
- }
- };
-
- this.unfocus_subscription = function(id)
- {
- var row = $('#'+id);
-
- this.env.dstfolder = null;
-
- if (row.length && this.env.subscriptionrows[id])
- row.removeClass('droptarget');
- else
- $(this.subscription_list.frame).removeClass('droptarget');
+ });
};
- this.subscription_select = function(list)
+ this.subscription_select = function(id)
{
- var id, folder;
+ var folder;
- if (list && (id = list.get_single_selection()) &&
- (folder = this.env.subscriptionrows['rcmrow'+id])
- ) {
+ if (id && id != 'mailboxroot' && (folder = this.env.subscriptionrows[id])) {
this.env.mailbox = folder[0];
this.show_folder(folder[0]);
this.enable_command('delete-folder', !folder[2]);
@@ -5832,24 +5805,21 @@ function rcube_webmail()
}
};
- this.subscription_move_folder = function(list)
+ this.subscription_move_folder = function(from, to)
{
- if (this.env.mailbox && this.env.dstfolder !== null &&
- this.env.dstfolder != this.env.mailbox &&
- this.env.dstfolder != this.env.mailbox.replace(this.last_sub_rx, '')
- ) {
- var path = this.env.mailbox.split(this.env.delimiter),
+ var source = this.env.subscriptionrows[from][0];
+ dest = this.env.subscriptionrows[to][0];
+
+ if (source && dest !== null && source != dest && dest != source.replace(this.last_sub_rx, '')) {
+ var path = source.split(this.env.delimiter),
basename = path.pop(),
- newname = this.env.dstfolder === '' ? basename : this.env.dstfolder + this.env.delimiter + basename;
+ newname = dest === '' ? basename : dest + this.env.delimiter + basename;
- if (newname != this.env.mailbox) {
- this.http_post('rename-folder', {_folder_oldname: this.env.mailbox, _folder_newname: newname}, this.set_busy(true, 'foldermoving'));
- this.subscription_list.draglayer.hide();
+ if (newname != source) {
+ this.http_post('rename-folder', {_folder_oldname: source, _folder_newname: newname},
+ this.set_busy(true, 'foldermoving'));
}
}
-
- this.drag_active = false;
- this.unfocus_subscription(this.get_folder_row_id(this.env.dstfolder));
};
// tell server to create and subscribe a new mailbox
@@ -5865,8 +5835,7 @@ function rcube_webmail()
folder = this.env.subscriptionrows[id][0];
if (folder && confirm(this.get_label('deletefolderconfirm'))) {
- var lock = this.set_busy(true, 'folderdeleting');
- this.http_post('delete-folder', {_mbox: folder}, lock);
+ this.http_post('delete-folder', {_mbox: folder}, this.set_busy(true, 'folderdeleting'));
}
};
@@ -5878,9 +5847,9 @@ function rcube_webmail()
var row, n, tmp, tmp_name, rowid, collator,
folders = [], list = [], slist = [],
- tbody = this.gui_objects.subscriptionlist.tBodies[0],
- refrow = $('tr', tbody).get(1),
- id = 'rcmrow'+((new Date).getTime());
+ list_element = $(this.gui_objects.subscriptionlist),
+ refrow = $('li', list_element).get(1),
+ id = 'rcmli'+((new Date).getTime());
if (!refrow) {
// Refresh page if we don't have a table row to clone
@@ -5895,7 +5864,7 @@ function rcube_webmail()
row.attr({id: id, 'class': class_name});
// set folder name
- row.find('td:first').html(display_name);
+ $('.name', row).html(display_name);
// update subscription checkbox
$('input[name="_subscribed[]"]', row).val(name)
@@ -5966,12 +5935,13 @@ function rcube_webmail()
// add row to the table
if (rowid)
- $('#'+rowid).after(row);
+ $('#' + rowid).after(row);
else
- row.appendTo(tbody);
+ list_element.append(row);
// update list widget
- this.subscription_list.clear_selection();
+ this.subscription_list.select();
+
if (!skip_init)
this.init_subscription_list();
@@ -5988,11 +5958,11 @@ function rcube_webmail()
if (!this.gui_objects.subscriptionlist) {
if (this.is_framed)
return parent.rcmail.replace_folder_row(oldfolder, newfolder, display_name, is_protected, class_name);
+
return false;
}
var i, n, len, name, dispname, oldrow, tmprow, row, level,
- tbody = this.gui_objects.subscriptionlist.tBodies[0],
folders = this.env.subscriptionrows,
id = this.get_folder_row_id(oldfolder),
prefix_len = oldfolder.length,
@@ -6003,7 +5973,6 @@ function rcube_webmail()
// no renaming, only update class_name
if (oldfolder == newfolder) {
$('#'+id).attr('class', class_name || '');
- this.subscription_list.focus();
return;
}
@@ -6040,7 +6009,7 @@ function rcube_webmail()
for (i=level; i<0; i++)
dispname = '&nbsp;&nbsp;&nbsp;&nbsp;' + dispname;
}
- row.find('td:first').html(dispname);
+ $('.name', row).html(dispname);
this.env.subscriptionrows[id][1] = dispname;
}
}
@@ -6068,8 +6037,8 @@ function rcube_webmail()
this._remove_folder_row = function(id)
{
- this.subscription_list.remove_row(id.replace(/^rcmrow/, ''));
- $('#'+id).remove();
+ this.subscription_list.remove(id.replace(/^rcmli/, ''));
+ $('#' + id).remove();
delete this.env.subscriptionrows[id];
};
diff --git a/program/js/treelist.js b/program/js/treelist.js
index b2d838e13..1e6061770 100644
--- a/program/js/treelist.js
+++ b/program/js/treelist.js
@@ -46,7 +46,7 @@ function rcube_treelist_widget(node, p)
scroll_speed: 20,
save_state: false,
keyboard: true,
- check_droptarget: function(node){ return !node.virtual }
+ check_droptarget: function(node) { return !node.virtual; }
}, p || {});
var container = $(node),
@@ -67,6 +67,7 @@ function rcube_treelist_widget(node, p)
searchfield,
tree_state,
ui_droppable,
+ ui_draggable,
list_id = (container.attr('id') || p.id_prefix || '0'),
me = this;
@@ -83,6 +84,7 @@ function rcube_treelist_widget(node, p)
this.drag_end = drag_end;
this.intersects = intersects;
this.droppable = droppable;
+ this.draggable = draggable;
this.update = update_node;
this.insert = insert;
this.remove = remove;
@@ -108,7 +110,11 @@ function rcube_treelist_widget(node, p)
e.stopPropagation();
});
- container.on('click', 'li', function(e){
+ container.on('click', 'li', function(e) {
+ // do not select record on checkbox/input click
+ if ($(e.target).is('input'))
+ return true;
+
var node = p.selectable ? indexbyid[dom2id($(this))] : null;
if (node && !node.virtual) {
select(node.id);
@@ -232,6 +238,9 @@ function rcube_treelist_widget(node, p)
selection = null;
}
+ if (!id)
+ return;
+
var li = id2dom(id, true);
if (li.length) {
li.addClass('selected').attr('aria-selected', 'true');
@@ -708,6 +717,7 @@ function rcube_treelist_widget(node, p)
{
var domid = p.id_encode ? p.id_encode(id) : id,
suffix = search_active && !real ? '--xsR' : '';
+
return $('#' + p.id_prefix + domid + suffix, container);
}
@@ -850,6 +860,11 @@ function rcube_treelist_widget(node, p)
*/
function drag_start()
{
+ if (drag_active)
+ return;
+
+ drag_active = true;
+
var li, item, height,
pos = container.offset();
@@ -857,7 +872,6 @@ function rcube_treelist_widget(node, p)
list_scroll_top = container.parent().scrollTop();
pos.top += list_scroll_top;
- drag_active = true;
box_coords = {
x1: pos.left,
y1: pos.top,
@@ -920,6 +934,9 @@ function rcube_treelist_widget(node, p)
*/
function drag_end()
{
+ if (!drag_active)
+ return;
+
drag_active = false;
scroll_timer = null;
@@ -950,7 +967,7 @@ function rcube_treelist_widget(node, p)
}
/**
- * Determine if the given mouse coords intersect the list and one if its items
+ * Determine if the given mouse coords intersect the list and one of its items
*/
function intersects(mouse, highlight)
{
@@ -970,8 +987,8 @@ function rcube_treelist_widget(node, p)
}
// check intersection with visible list items
- var pos, node;
- for (var id in item_coords) {
+ var id, pos, node;
+ for (id in item_coords) {
pos = item_coords[id];
if (mouse.x >= pos.x1 && mouse.x < pos.x2 && mouse.top >= pos.y1 && mouse.top < pos.y2) {
node = indexbyid[id];
@@ -1024,7 +1041,14 @@ function rcube_treelist_widget(node, p)
*/
function droppable(opts)
{
- var my_opts = $.extend({ greedy: true, hoverClass: 'droptarget', addClasses:false }, opts);
+ if (!opts) opts = {};
+
+ var my_opts = $.extend({
+ greedy: true,
+ tolerance: 'pointer',
+ hoverClass: 'droptarget',
+ addClasses: false
+ }, opts);
my_opts.activate = function(e, ui) {
drag_start();
@@ -1046,7 +1070,34 @@ function rcube_treelist_widget(node, p)
opts.over(e, ui);
};
- $('li:not(.virtual)', container).droppable(my_opts);
+ $(selector ? selector : 'li:not(.virtual)', container).droppable(my_opts);
+
+ return this;
+ }
+
+ /**
+ * Wrapper for jQuery.UI.draggable() activation on this widget
+ *
+ * @param object Options as passed to regular .draggable() function
+ */
+ function draggable(opts)
+ {
+ if (!opts) opts = {};
+
+ var my_opts = $.extend({
+ appendTo: 'body',
+ iframeFix: true,
+ addClasses: false,
+ cursorAt: {left: -20, top: 5},
+ helper: function(e) {
+ return $('<div>').attr('id', 'rcmdraglayer')
+ .text($.trim($(e.target).first().text()));
+ }
+ }, opts);
+
+ $('li:not(.virtual)', container).draggable(my_opts);
+
+ return this;
}
}
diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc
index 33b2b0624..ad5f37d95 100644
--- a/program/steps/settings/folders.inc
+++ b/program/steps/settings/folders.inc
@@ -177,11 +177,9 @@ if ($OUTPUT->ajax_call) {
}
$OUTPUT->set_pagetitle($RCMAIL->gettext('folders'));
-$OUTPUT->include_script('list.js');
$OUTPUT->set_env('prefix_ns', $STORAGE->get_namespace('prefix'));
-if ($STORAGE->get_capability('QUOTA')) {
- $OUTPUT->set_env('quota', true);
-}
+$OUTPUT->set_env('quota', (bool) $STORAGE->get_capability('QUOTA'));
+$OUTPUT->include_script('treelist.js');
// add some labels to client
$OUTPUT->add_label('deletefolderconfirm', 'purgefolderconfirm', 'folderdeleting',
@@ -205,15 +203,8 @@ function rcube_subscription_form($attrib)
list($form_start, $form_end) = get_form_tags($attrib, 'folders');
unset($attrib['form']);
- if (!$attrib['id'])
+ if (!$attrib['id']) {
$attrib['id'] = 'rcmSubscriptionlist';
-
- $table = new html_table();
-
- if ($attrib['noheader'] !== true && $attrib['noheader'] != "true") {
- // add table header
- $table->add_header('name', $RCMAIL->gettext('foldername'));
- $table->add_header('subscribed', '');
}
$STORAGE = $RCMAIL->get_storage();
@@ -227,7 +218,6 @@ function rcube_subscription_form($attrib)
$namespace = $STORAGE->get_namespace();
$special_folders = array_flip(array_merge(array('inbox' => 'INBOX'), $STORAGE->get_special_folders()));
$protect_default = $RCMAIL->config->get('protect_default_folders');
- $a_js_folders = array();
$seen = array();
$list_folders = array();
@@ -272,19 +262,15 @@ function rcube_subscription_form($attrib)
unset($seen);
- // add drop-target representing 'root'
- $table->add_row(array('id' => 'mailboxroot', 'class' => 'virtual root'));
- $table->add('name', '&nbsp;');
- $table->add(null, '&nbsp;');
-
- $a_js_folders['mailboxroot'] = array('', '', true);
-
$checkbox_subscribe = new html_checkbox(array(
'name' => '_subscribed[]',
'title' => $RCMAIL->gettext('changesubscription'),
'onclick' => rcmail_output::JS_OBJECT_NAME.".command(this.checked?'subscribe':'unsubscribe',this.value)",
));
+ $js_folders = array();
+ $folders = array();
+
// create list of available folders
foreach ($list_folders as $i => $folder) {
$idx = $i + 1;
@@ -292,7 +278,7 @@ function rcube_subscription_form($attrib)
$subscribed = $sub_key !== false;
$protected = $protect_default && isset($special_folders[$folder['id']]);
$noselect = false;
- $classes = array($i%2 ? 'even' : 'odd');
+ $classes = array('listitem');
$folder_utf8 = rcube_charset::convert($folder['id'], 'UTF7-IMAP');
$display_folder = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $folder['level'])
@@ -352,25 +338,45 @@ function rcube_subscription_form($attrib)
}
}
- $table->add_row(array('id' => 'rcmrow'.$idx, 'class' => join(' ', $classes),
- 'foldername' => $folder['id']));
+ $row_id = 'rcmli' . $idx;
+ $folders[$row_id] = array(
+ 'folder' => $folder_utf8,
+ 'display' => $display_folder,
+ 'class' => join(' ', $classes),
+ 'folder_imap' => $folder['id'],
+ 'subscribed' => $subscribed,
+ 'protected' => $protected || $folder['virtual'],
+ 'content' => html::a(array('class' => 'name', 'href' => '#_' . $row_id), $display_folder)
+ . $checkbox_subscribe->show(($subscribed ? $folder_utf8 : ''),
+ array('value' => $folder_utf8, 'disabled' => $disabled ? 'disabled' : ''))
+ );
+ }
- $table->add('name', $display_folder);
- $table->add('subscribed', $checkbox_subscribe->show(($subscribed ? $folder_utf8 : ''),
- array('value' => $folder_utf8, 'disabled' => $disabled ? 'disabled' : '')));
+ $plugin = $RCMAIL->plugins->exec_hook('folders_list', array('list' => $folders));
- $a_js_folders['rcmrow'.$idx] = array($folder_utf8,
- $display_folder, $protected || $folder['virtual']);
+ // add drop-target representing 'root'
+ $roots = array(
+ 'mailboxroot' => array(
+ 'folder' => '',
+ 'display' => '',
+ 'protected' => true,
+ 'class' => 'root',
+ 'content' => html::span('name', '&nbsp;')
+ )
+ );
+ $folders = array_merge($roots, $plugin['list']);
+
+ while (list($key, $data) = each($folders)) {
+ $js_folders[$key] = array($data['folder'], $data['display'], $data['protected']);
+ $folders[$key] = html::tag('li', array('id' => $key, 'class' => $data['class']), $data['content']);
}
- $RCMAIL->plugins->exec_hook('folders_list', array('table' => $table));
-
$OUTPUT->add_gui_object('subscriptionlist', $attrib['id']);
- $OUTPUT->set_env('subscriptionrows', $a_js_folders);
+ $OUTPUT->set_env('subscriptionrows', $js_folders);
$OUTPUT->set_env('defaultfolders', array_keys($special_folders));
$OUTPUT->set_env('delimiter', $delimiter);
- return $form_start . $table->show($attrib) . $form_end;
+ return $form_start . html::tag('ul', $attrib, implode("\n", $folders)) . $form_end;
}
function rcmail_folder_frame($attrib)
diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc
index 7ccbfa4a5..40b70b119 100644
--- a/program/steps/settings/func.inc
+++ b/program/steps/settings/func.inc
@@ -1309,6 +1309,8 @@ function rcmail_update_folder_row($name, $oldname=null, $subscribe=false, $class
$display_name = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $level)
. rcube::Q($protected ? $RCMAIL->localize_foldername($name) : rcube_charset::convert($foldersplit[$level], 'UTF7-IMAP'));
+ $class_name = trim($class_name . ' listitem');
+
if ($oldname === null) {
$OUTPUT->command('add_folder_row', $name_utf8, $display_name, $protected, $subscribe,
false, $class_name);