summaryrefslogtreecommitdiff
path: root/program/js
diff options
context:
space:
mode:
Diffstat (limited to 'program/js')
-rw-r--r--program/js/app.js413
-rw-r--r--program/js/common.js78
-rw-r--r--program/js/editor.js3
-rw-r--r--program/js/list.js16
4 files changed, 357 insertions, 153 deletions
diff --git a/program/js/app.js b/program/js/app.js
index 1f75e219c..636db82d4 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -34,7 +34,7 @@ function rcube_webmail()
// webmail client settings
this.dblclick_time = 500;
- this.message_time = 4000;
+ this.message_time = 5000;
this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi');
// environment defaults
@@ -187,6 +187,8 @@ function rcube_webmail()
if (this.env.permaurl)
this.enable_command('permaurl', 'extwin', true);
+ this.local_storage_prefix = 'roundcube.' + (this.env.user_id || 'anonymous') + '.';
+
switch (this.task) {
case 'mail':
@@ -218,12 +220,8 @@ function rcube_webmail()
// load messages
this.command('list');
- }
- if (this.gui_objects.qsearchbox) {
- if (this.env.search_text != null)
- this.gui_objects.qsearchbox.value = this.env.search_text;
- $(this.gui_objects.qsearchbox).focusin(function() { rcmail.message_list && rcmail.message_list.blur(); });
+ $(this.gui_objects.qsearchbox).val(this.env.search_text).focusin(function() { rcmail.message_list.blur(); });
}
this.set_button_titles();
@@ -285,10 +283,10 @@ function rcube_webmail()
return rcube_event.cancel(e);
});
- // avoid textarea loosing focus when hitting the save-response button/link
- for (var i=0; this.buttons['save-response'] && i < this.buttons['save-response'].length; i++) {
- $('#'+this.buttons['save-response'][i].id).mousedown(function(e){ return rcube_event.cancel(e); })
- }
+ // avoid textarea loosing focus when hitting the save-response button/link
+ for (var i=0; this.buttons['save-response'] && i < this.buttons['save-response'].length; i++) {
+ $('#'+this.buttons['save-response'][i].id).mousedown(function(e){ return rcube_event.cancel(e); })
+ }
}
document.onmouseup = function(e){ return p.doc_mouse_up(e); };
@@ -351,7 +349,7 @@ function rcube_webmail()
this.env.contactfolders = $.extend($.extend({}, this.env.address_sources), this.env.contactgroups);
this.enable_command('add', 'import', this.env.writable_source);
- this.enable_command('list', 'listgroup', 'pushgroup', 'popgroup', 'listsearch', 'advanced-search', true);
+ this.enable_command('list', 'listgroup', 'pushgroup', 'popgroup', 'listsearch', 'search', 'reset-search', 'advanced-search', true);
if (this.gui_objects.contactslist) {
this.contact_list = new rcube_list_widget(this.gui_objects.contactslist,
@@ -369,8 +367,8 @@ function rcube_webmail()
this.gui_objects.contactslist.parentNode.onmousedown = function(e){ return p.click_on_list(e); };
document.onmouseup = function(e){ return p.doc_mouse_up(e); };
- if (this.gui_objects.qsearchbox)
- $(this.gui_objects.qsearchbox).focusin(function() { rcmail.contact_list.blur(); });
+
+ $(this.gui_objects.qsearchbox).focusin(function() { rcmail.contact_list.blur(); });
this.update_group_commands();
this.command('list');
@@ -394,9 +392,6 @@ function rcube_webmail()
this.init_contact_form();
}
- if (this.gui_objects.qsearchbox)
- this.enable_command('search', 'reset-search', true);
-
break;
case 'settings':
@@ -408,9 +403,6 @@ function rcube_webmail()
else if (this.env.action == 'edit-identity' || this.env.action == 'add-identity') {
this.enable_command('save', 'edit', 'toggle-editor', true);
this.enable_command('delete', this.env.identities_level < 2);
-
- if (this.env.action == 'add-identity')
- $("input[type='text']").first().select();
}
else if (this.env.action == 'folders') {
this.enable_command('subscribe', 'unsubscribe', 'create-folder', 'rename-folder', true);
@@ -419,7 +411,6 @@ function rcube_webmail()
this.enable_command('save', 'folder-size', true);
parent.rcmail.env.exists = this.env.messagecount;
parent.rcmail.enable_command('purge', this.env.messagecount);
- $("input[type='text']").first().select();
}
else if (this.env.action == 'responses') {
this.enable_command('add', true);
@@ -445,7 +436,7 @@ function rcube_webmail()
}
else if (this.gui_objects.responseslist) {
this.responses_list = new rcube_list_widget(this.gui_objects.responseslist, {multiselect:false, draggable:false, keyboard:false});
- this.responses_list.addEventListener('select', function(list){
+ this.responses_list.addEventListener('select', function(list) {
var win, id = list.get_single_selection();
p.enable_command('delete', !!id && $.inArray(id, p.env.readonly_responses) < 0);
if (id && (win = p.get_frame_window(p.env.contentframe))) {
@@ -489,6 +480,11 @@ function rcube_webmail()
break;
}
+ // select first input field in an edit form
+ if (this.gui_objects.editform)
+ $("input,select,textarea", this.gui_objects.editform)
+ .not(':hidden').not(':disabled').first().select();
+
// unset contentframe variable if preview_pane is enabled
if (this.env.contentframe && !$('#' + this.env.contentframe).is(':visible'))
this.env.contentframe = null;
@@ -584,9 +580,12 @@ function rcube_webmail()
}
// check input before leaving compose step
- if (this.task == 'mail' && this.env.action == 'compose' && $.inArray(command, this.env.compose_commands)<0) {
+ if (this.task == 'mail' && this.env.action == 'compose' && $.inArray(command, this.env.compose_commands) < 0 && !this.env.server_error) {
if (this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning')))
return false;
+
+ // remove copy from local storage if compose screen is left intentionally
+ this.remove_compose_data(this.env.compose_id);
}
// process external commands
@@ -621,10 +620,10 @@ function rcube_webmail()
break;
// commands to switch task
+ case 'logout':
case 'mail':
case 'addressbook':
case 'settings':
- case 'logout':
this.switch_task(command);
break;
@@ -644,6 +643,7 @@ function rcube_webmail()
var form = this.gui_objects.messageform,
win = this.open_window('');
+ this.save_compose_form_local();
$("input[name='_action']", form).val('compose');
form.action = this.url('mail/compose', { _id: this.env.compose_id, _extwin: 1 });
form.target = win.name;
@@ -1298,8 +1298,10 @@ function rcube_webmail()
return;
var url = this.get_task_url(task);
- if (task=='mail')
+ if (task == 'mail')
url += '&_mbox=INBOX';
+ else if (task == 'logout')
+ this.clear_compose_data();
this.redirect(url);
};
@@ -1706,7 +1708,7 @@ function rcube_webmail()
url += (url.match(/\?/) ? '&' : '?') + '_extwin=1';
if (this.env.standard_windows)
- extwin = window.open(url, wname);
+ var extwin = window.open(url, wname);
else {
var win = this.is_framed() ? parent.window : window,
page = $(win),
@@ -1727,7 +1729,7 @@ function rcube_webmail()
}
// focus window, delayed to bring to front
- window.setTimeout(function() { extwin.focus(); }, 10);
+ window.setTimeout(function() { extwin && extwin.focus(); }, 10);
return extwin;
};
@@ -3123,6 +3125,60 @@ function rcube_webmail()
}
}
+ // check for locally stored compose data
+ if (window.localStorage) {
+ var index = this.local_storage_get_item('compose.index', []);
+
+ for (var key, i = 0; i < index.length; i++) {
+ key = index[i], formdata = this.local_storage_get_item('compose.' + key, null, true);
+ if (!formdata) {
+ continue;
+ }
+ // restore saved copy of current compose_id
+ if (formdata.changed && key == this.env.compose_id) {
+ this.restore_compose_form(key, html_mode);
+ break;
+ }
+ // skip records from 'other' drafts
+ if (this.env.draft_id && formdata.draft_id && formdata.draft_id != this.env.draft_id) {
+ continue;
+ }
+ // show dialog asking to restore the message
+ if (formdata.changed && formdata.session != this.env.session_id) {
+ this.show_popup_dialog(
+ this.get_label('restoresavedcomposedata')
+ .replace('$date', new Date(formdata.changed).toLocaleString())
+ .replace('$subject', formdata._subject)
+ .replace(/\n/g, '<br/>'),
+ this.get_label('restoremessage'),
+ [{
+ text: this.get_label('restore'),
+ click: function(){
+ ref.restore_compose_form(key, html_mode);
+ ref.remove_compose_data(key); // remove old copy
+ ref.save_compose_form_local(); // save under current compose_id
+ $(this).dialog('close');
+ }
+ },
+ {
+ text: this.get_label('delete'),
+ click: function(){
+ ref.remove_compose_data(key);
+ $(this).dialog('close');
+ }
+ },
+ {
+ text: this.get_label('ignore'),
+ click: function(){
+ $(this).dialog('close');
+ }
+ }]
+ );
+ break;
+ }
+ }
+ }
+
if (input_to.val() == '')
input_to.focus();
else if (input_subject.val() == '')
@@ -3560,6 +3616,8 @@ function rcube_webmail()
this.env.draft_id = id;
$("input[name='_draft_saveid']").val(id);
+
+ this.remove_compose_data(this.env.compose_id);
};
this.auto_save_start = function()
@@ -3567,6 +3625,20 @@ function rcube_webmail()
if (this.env.draft_autosave)
this.save_timer = setTimeout(function(){ ref.command("savedraft"); }, this.env.draft_autosave * 1000);
+ // save compose form content to local storage every 5 seconds
+ if (!this.local_save_timer && window.localStorage) {
+ // track typing activity and only save on changes
+ this.compose_type_activity = this.compose_type_activity_last = 0;
+ $(document).bind('keypress', function(e){ ref.compose_type_activity++; });
+
+ this.local_save_timer = setInterval(function(){
+ if (ref.compose_type_activity > ref.compose_type_activity_last) {
+ ref.save_compose_form_local();
+ ref.compose_type_activity_last = ref.compose_type_activity;
+ }
+ }, 5000);
+ }
+
// Unlock interface now that saving is complete
this.busy = false;
};
@@ -3595,6 +3667,115 @@ function rcube_webmail()
return str;
};
+ // store the contents of the compose form to localstorage
+ this.save_compose_form_local = function()
+ {
+ var formdata = { session:this.env.session_id, changed:new Date().getTime() },
+ ed, empty = true;
+
+ // get fresh content from editor
+ if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody))) {
+ tinyMCE.triggerSave();
+ }
+
+ if (this.env.draft_id) {
+ formdata.draft_id = this.env.draft_id;
+ }
+
+ $('input, select, textarea', this.gui_objects.messageform).each(function(i, elem) {
+ switch (elem.tagName.toLowerCase()) {
+ case 'input':
+ if (elem.type == 'button' || elem.type == 'submit' || (elem.type == 'hidden' && elem.name != '_is_html')) {
+ break;
+ }
+ formdata[elem.name] = elem.type != 'checkbox' || elem.checked ? $(elem).val() : '';
+
+ if (formdata[elem.name] != '' && elem.type != 'hidden')
+ empty = false;
+ break;
+
+ case 'select':
+ formdata[elem.name] = $('option:checked', elem).val();
+ break;
+
+ default:
+ formdata[elem.name] = $(elem).val();
+ if (formdata[elem.name] != '')
+ empty = false;
+ }
+ });
+
+ if (window.localStorage && !empty) {
+ var index = this.local_storage_get_item('compose.index', []),
+ key = this.env.compose_id;
+
+ if ($.inArray(key, index) < 0) {
+ index.push(key);
+ }
+ this.local_storage_set_item('compose.' + key, formdata, true);
+ this.local_storage_set_item('compose.index', index);
+ }
+ };
+
+ // write stored compose data back to form
+ this.restore_compose_form = function(key, html_mode)
+ {
+ var ed, formdata = this.local_storage_get_item('compose.' + key, true);
+
+ if (formdata && typeof formdata == 'object') {
+ $.each(formdata, function(k, value) {
+ if (k[0] == '_') {
+ var elem = $("*[name='"+k+"']");
+ if (elem[0] && elem[0].type == 'checkbox') {
+ elem.prop('checked', value != '');
+ }
+ else {
+ elem.val(value);
+ }
+ }
+ });
+
+ // initialize HTML editor
+ if (formdata._is_html == '1') {
+ if (!html_mode) {
+ tinyMCE.execCommand('mceAddControl', false, this.env.composebody);
+ this.triggerEvent('aftertoggle-editor', { mode:'html' });
+ }
+ }
+ else if (html_mode) {
+ tinyMCE.execCommand('mceRemoveControl', false, this.env.composebody);
+ this.triggerEvent('aftertoggle-editor', { mode:'plain' });
+ }
+ }
+ };
+
+ // remove stored compose data from localStorage
+ this.remove_compose_data = function(key)
+ {
+ if (window.localStorage) {
+ var index = this.local_storage_get_item('compose.index', []);
+
+ if ($.inArray(key, index) >= 0) {
+ this.local_storage_remove_item('compose.' + key);
+ this.local_storage_set_item('compose.index', $.grep(index, function(val,i) { return val != key; }));
+ }
+ }
+ };
+
+ // clear all stored compose data of this user
+ this.clear_compose_data = function()
+ {
+ if (window.localStorage) {
+ var index = this.local_storage_get_item('compose.index', []);
+
+ for (var i=0; i < index.length; i++) {
+ this.local_storage_remove_item('compose.' + index[i]);
+ }
+ this.local_storage_remove_item('compose.index');
+ }
+ }
+
+
this.change_identity = function(obj, show_sig)
{
if (!obj || !obj.options)
@@ -4027,7 +4208,7 @@ function rcube_webmail()
case 38: // arrow up
case 40: // arrow down
if (!this.ksearch_visible())
- break;
+ return;
var dir = key==38 ? 1 : 0;
@@ -4062,8 +4243,7 @@ function rcube_webmail()
case 37: // left
case 39: // right
- if (mod != SHIFT_KEY)
- return;
+ return;
}
// start timer
@@ -4126,8 +4306,10 @@ function rcube_webmail()
if (this.ksearch_input.setSelectionRange)
this.ksearch_input.setSelectionRange(cpos, cpos);
- if (trigger)
+ if (trigger) {
this.triggerEvent('autocomplete_insert', { field:this.ksearch_input, insert:insert });
+ this.compose_type_activity++;
+ }
};
this.replace_group_recipients = function(id, recipients)
@@ -4136,6 +4318,7 @@ function rcube_webmail()
this.group2expand[id].input.value = this.group2expand[id].input.value.replace(this.group2expand[id].name, recipients);
this.triggerEvent('autocomplete_insert', { field:this.group2expand[id].input, insert:recipients });
this.group2expand[id] = null;
+ this.compose_type_activity++;
}
};
@@ -4820,8 +5003,6 @@ function rcube_webmail()
$('input.datepicker').datepicker();
}
- $("input[type='text']:visible").first().focus();
-
// Submit search form on Enter
if (this.env.action == 'search')
$(this.gui_objects.editform).append($('<input type="submit">').hide())
@@ -5438,7 +5619,10 @@ function rcube_webmail()
this.init_subscription_list = function()
{
- var p = this;
+ var p = this, delim = RegExp.escape(this.env.delimiter);
+
+ this.last_sub_rx = RegExp('['+delim+']?[^'+delim+']+$');
+
this.subscription_list = new rcube_list_widget(this.gui_objects.subscriptionlist,
{multiselect:false, draggable:true, keyboard:false, toggleselect:true});
this.subscription_list.addEventListener('select', function(o){ p.subscription_select(o); });
@@ -5449,6 +5633,7 @@ function rcube_webmail()
row.obj.onmouseout = function() { p.unfocus_subscription(row.id); };
};
this.subscription_list.init();
+
$('#mailboxroot')
.mouseover(function(){ p.focus_subscription(this.id); })
.mouseout(function(){ p.unfocus_subscription(this.id); })
@@ -5456,9 +5641,7 @@ function rcube_webmail()
this.focus_subscription = function(id)
{
- var row, folder,
- delim = RegExp.escape(this.env.delimiter),
- reg = RegExp('['+delim+']?[^'+delim+']+$');
+ var row, folder;
if (this.drag_active && this.env.mailbox && (row = document.getElementById(id)))
if (this.env.subscriptionrows[id] &&
@@ -5466,8 +5649,8 @@ function rcube_webmail()
) {
if (this.check_droptarget(folder) &&
!this.env.subscriptionrows[this.get_folder_row_id(this.env.mailbox)][2] &&
- (folder != this.env.mailbox.replace(reg, '')) &&
- (!folder.startsWith(this.env.mailbox + this.env.delimiter))
+ folder != this.env.mailbox.replace(this.last_sub_rx, '') &&
+ !folder.startsWith(this.env.mailbox + this.env.delimiter)
) {
this.env.dstfolder = folder;
$(row).addClass('droptarget');
@@ -5480,7 +5663,8 @@ function rcube_webmail()
var row = $('#'+id);
this.env.dstfolder = null;
- if (this.env.subscriptionrows[id] && row[0])
+
+ if (this.env.subscriptionrows[id] && row.length)
row.removeClass('droptarget');
else
$(this.subscription_list.frame).removeClass('droptarget');
@@ -5506,21 +5690,20 @@ function rcube_webmail()
this.subscription_move_folder = function(list)
{
- var delim = RegExp.escape(this.env.delimiter),
- reg = RegExp('['+delim+']?[^'+delim+']+$');
-
- if (this.env.mailbox && this.env.dstfolder !== null && (this.env.dstfolder != this.env.mailbox) &&
- (this.env.dstfolder != this.env.mailbox.replace(reg, ''))
+ 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, '')
) {
- reg = new RegExp('[^'+delim+']*['+delim+']', 'g');
- var basename = this.env.mailbox.replace(reg, ''),
- newname = this.env.dstfolder === '' ? basename : this.env.dstfolder+this.env.delimiter+basename;
+ var path = this.env.mailbox.split(this.env.delimiter),
+ basename = path.pop(),
+ newname = this.env.dstfolder === '' ? basename : this.env.dstfolder + 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();
}
}
+
this.drag_active = false;
this.unfocus_subscription(this.get_folder_row_id(this.env.dstfolder));
};
@@ -5549,7 +5732,7 @@ function rcube_webmail()
if (!this.gui_objects.subscriptionlist)
return false;
- var row, n, i, tmp, tmp_name, folders, rowid, list = [], slist = [],
+ var row, n, i, tmp, tmp_name, rowid, folders = [], list = [], slist = [],
tbody = this.gui_objects.subscriptionlist.tBodies[0],
refrow = $('tr', tbody).get(1),
id = 'rcmrow'+((new Date).getTime());
@@ -5564,8 +5747,7 @@ function rcube_webmail()
row = $(refrow).clone(true);
// set ID, reset css class
- row.attr('id', id);
- row.attr('class', class_name);
+ row.attr({id: id, 'class': class_name});
// set folder name
row.find('td:first').html(display_name);
@@ -5577,10 +5759,21 @@ function rcube_webmail()
// add to folder/row-ID map
this.env.subscriptionrows[id] = [name, display_name, 0];
- // sort folders, to find a place where to insert the row
- folders = [];
- $.each(this.env.subscriptionrows, function(k,v){ folders.push(v) });
- folders.sort(function(a,b){ return a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : 0) });
+ // sort folders (to find a place where to insert the row)
+ // replace delimiter with \0 character to fix sorting
+ // issue where 'Abc Abc' would be placed before 'Abc/def'
+ var replace_from = RegExp(RegExp.escape(this.env.delimiter), 'g'),
+ replace_to = String.fromCharCode(0);
+ $.each(this.env.subscriptionrows, function(k,v) {
+ var n = v[0];
+ n = n.replace(replace_from, replace_to);
+ v.push(n);
+ folders.push(v);
+ });
+ folders.sort(function(a, b) {
+ var len = a.length - 1; n1 = a[len], n2 = b[len];
+ return n1 < n2 ? -1 : 1;
+ });
for (n in folders) {
// protected folder
@@ -5642,7 +5835,7 @@ function rcube_webmail()
tbody = this.gui_objects.subscriptionlist.tBodies[0],
folders = this.env.subscriptionrows,
id = this.get_folder_row_id(oldfolder),
- regex = new RegExp('^'+RegExp.escape(oldfolder)),
+ prefix_len = oldfolder.length,
subscribed = $('input[name="_subscribed[]"]', $('#'+id)).prop('checked'),
// find subfolders of renamed folder
list = this.get_subfolders(oldfolder);
@@ -5667,7 +5860,7 @@ function rcube_webmail()
row.after(tmprow);
row = tmprow;
// update folder index
- name = name.replace(regex, newfolder);
+ name = newfolder + name.slice(prefix_len);
$('input[name="_subscribed[]"]', row).val(name);
this.env.subscriptionrows[id][0] = name;
// update the name if level is changed
@@ -5912,59 +6105,36 @@ function rcube_webmail()
// mouse over button
this.button_over = function(command, id)
{
- var n, button, obj, a_buttons = this.buttons[command],
- len = a_buttons ? a_buttons.length : 0;
-
- for (n=0; n<len; n++) {
- button = a_buttons[n];
- if (button.id == id && button.status == 'act') {
- obj = document.getElementById(button.id);
- if (obj && button.over) {
- if (button.type == 'image')
- obj.src = button.over;
- else
- obj.className = button.over;
- }
- }
- }
+ this.button_event(command, id, 'over');
};
// mouse down on button
this.button_sel = function(command, id)
{
- var n, button, obj, a_buttons = this.buttons[command],
- len = a_buttons ? a_buttons.length : 0;
-
- for (n=0; n<len; n++) {
- button = a_buttons[n];
- if (button.id == id && button.status == 'act') {
- obj = document.getElementById(button.id);
- if (obj && button.sel) {
- if (button.type == 'image')
- obj.src = button.sel;
- else
- obj.className = button.sel;
- }
- this.buttons_sel[id] = command;
- }
- }
+ this.button_event(command, id, 'sel');
};
// mouse out of button
this.button_out = function(command, id)
{
+ this.button_event(command, id, 'act');
+ };
+
+ // event of button
+ this.button_event = function(command, id, event)
+ {
var n, button, obj, a_buttons = this.buttons[command],
len = a_buttons ? a_buttons.length : 0;
for (n=0; n<len; n++) {
button = a_buttons[n];
if (button.id == id && button.status == 'act') {
- obj = document.getElementById(button.id);
- if (obj && button.act) {
- if (button.type == 'image')
- obj.src = button.act;
- else
- obj.className = button.act;
+ if (button[event] && (obj = document.getElementById(button.id))) {
+ obj[button.type == 'image' ? 'src' : 'className'] = button[event];
+ }
+
+ if (event == 'sel') {
+ this.buttons_sel[id] = command;
}
}
}
@@ -6039,7 +6209,7 @@ function rcube_webmail()
this.triggerEvent('message', { message:msg, type:type, timeout:timeout, object:obj });
if (timeout > 0)
- setTimeout(function() { ref.hide_message(id, type == 'loading'); }, timeout);
+ setTimeout(function() { ref.hide_message(id, type != 'loading'); }, timeout);
return id;
};
@@ -6152,8 +6322,8 @@ function rcube_webmail()
// enable/disable buttons for page shifting
this.set_page_buttons = function()
{
- this.enable_command('nextpage', 'lastpage', (this.env.pagecount > this.env.current_page));
- this.enable_command('previouspage', 'firstpage', (this.env.current_page > 1));
+ this.enable_command('nextpage', 'lastpage', this.env.pagecount > this.env.current_page);
+ this.enable_command('previouspage', 'firstpage', this.env.current_page > 1);
};
// mark a mailbox as selected and set environment variable
@@ -6163,14 +6333,10 @@ function rcube_webmail()
this.treelist.select(name);
}
else if (this.gui_objects.folderlist) {
- var current_li, target_li;
-
- if ((current_li = $('li.selected', this.gui_objects.folderlist))) {
- current_li.removeClass('selected').addClass('unfocused');
- }
- if ((target_li = this.get_folder_li(name, prefix, encode))) {
- $(target_li).removeClass('unfocused').addClass('selected');
- }
+ $('li.selected', this.gui_objects.folderlist)
+ .removeClass('selected').addClass('unfocused');
+ $(this.get_folder_li(name, prefix, encode))
+ .removeClass('unfocused').addClass('selected');
// trigger event hook
this.triggerEvent('selectfolder', { folder:name, prefix:prefix });
@@ -6199,8 +6365,6 @@ function rcube_webmail()
name = this.html_identifier(name, encode);
return document.getElementById(prefix+name);
}
-
- return null;
};
// for reordering column array (Konqueror workaround)
@@ -6744,6 +6908,20 @@ function rcube_webmail()
setTimeout(function(){ ref.keep_alive(); ref.start_keepalive(); }, 30000);
};
+ // handler for session errors detected on the server
+ this.session_error = function(redirect_url)
+ {
+ this.env.server_error = 401;
+
+ // save message in local storage and do not redirect
+ if (this.env.action == 'compose') {
+ this.save_compose_form_local();
+ }
+ else if (redirect_url) {
+ window.setTimeout(function(){ ref.redirect(redirect_url, true); }, 2000);
+ }
+ };
+
// callback when an iframe finished loading
this.iframe_loaded = function(unlock)
{
@@ -7265,7 +7443,28 @@ function rcube_webmail()
this.set_cookie = function(name, value, expires)
{
setCookie(name, value, expires, this.env.cookie_path, this.env.cookie_domain, this.env.cookie_secure);
- }
+ };
+
+ // wrapper for localStorage.getItem(key)
+ this.local_storage_get_item = function(key, deflt, encrypted)
+ {
+ // TODO: add encryption
+ var item = localStorage.getItem(this.local_storage_prefix + key);
+ return item !== null ? JSON.parse(item) : (deflt || null);
+ };
+
+ // wrapper for localStorage.setItem(key, data)
+ this.local_storage_set_item = function(key, data, encrypted)
+ {
+ // TODO: add encryption
+ return localStorage.setItem(this.local_storage_prefix + key, JSON.stringify(data));
+ };
+
+ // wrapper for localStorage.removeItem(key)
+ this.local_storage_remove_item = function(key)
+ {
+ return localStorage.removeItem(this.local_storage_prefix + key);
+ };
} // end object rcube_webmail
diff --git a/program/js/common.js b/program/js/common.js
index 02934f734..14091463f 100644
--- a/program/js/common.js
+++ b/program/js/common.js
@@ -37,47 +37,44 @@ function roundcube_browser()
this.vendver = n.vendorSub ? parseFloat(n.vendorSub) : 0;
this.product = n.product ? n.product : '';
this.platform = String(n.platform).toLowerCase();
- this.lang = (n.language) ? n.language.substring(0,2) :
- (n.browserLanguage) ? n.browserLanguage.substring(0,2) :
- (n.systemLanguage) ? n.systemLanguage.substring(0,2) : 'en';
+ this.lang = n.language ? n.language.substring(0,2) :
+ n.browserLanguage ? n.browserLanguage.substring(0,2) :
+ n.systemLanguage ? n.systemLanguage.substring(0,2) : 'en';
- this.win = (this.platform.indexOf('win') >= 0);
- this.mac = (this.platform.indexOf('mac') >= 0);
- this.linux = (this.platform.indexOf('linux') >= 0);
- this.unix = (this.platform.indexOf('unix') >= 0);
+ this.win = this.platform.indexOf('win') >= 0;
+ this.mac = this.platform.indexOf('mac') >= 0;
+ this.linux = this.platform.indexOf('linux') >= 0;
+ this.unix = this.platform.indexOf('unix') >= 0;
this.dom = document.getElementById ? true : false;
- this.dom2 = (document.addEventListener && document.removeEventListener);
-
- this.ie = (document.all && !window.opera);
- this.ie4 = (this.ie && !this.dom);
- this.ie5 = (this.dom && this.appver.indexOf('MSIE 5')>0);
- this.ie8 = (this.dom && this.appver.indexOf('MSIE 8')>0);
- this.ie9 = (this.dom && this.appver.indexOf('MSIE 9')>0);
- this.ie7 = (this.dom && this.appver.indexOf('MSIE 7')>0);
- this.ie6 = (this.dom && !this.ie8 && !this.ie7 && this.appver.indexOf('MSIE 6')>0);
-
- this.ns = ((this.ver < 5 && this.name == 'Netscape') || (this.ver >= 5 && this.vendor.indexOf('Netscape') >= 0));
- this.chrome = (this.agent_lc.indexOf('chrome') > 0);
- this.safari = (!this.chrome && (this.agent_lc.indexOf('safari') > 0 || this.agent_lc.indexOf('applewebkit') > 0));
- this.konq = (this.agent_lc.indexOf('konqueror') > 0);
- this.mz = (this.dom && !this.ie && !this.ns && !this.chrome && !this.safari && !this.konq && this.agent.indexOf('Mozilla') >= 0);
- this.iphone = (this.safari && (this.agent_lc.indexOf('iphone') > 0 || this.agent_lc.indexOf('ipod') > 0));
- this.ipad = (this.safari && this.agent_lc.indexOf('ipad') > 0);
- this.opera = window.opera ? true : false;
-
- if (this.opera && window.RegExp)
- this.vendver = (/opera(\s|\/)([0-9\.]+)/.test(this.agent_lc)) ? parseFloat(RegExp.$2) : -1;
- else if (this.chrome && window.RegExp)
- this.vendver = (/chrome\/([0-9\.]+)/.test(this.agent_lc)) ? parseFloat(RegExp.$1) : 0;
- else if (!this.vendver && this.safari)
- this.vendver = (/(safari|applewebkit)\/([0-9]+)/.test(this.agent_lc)) ? parseInt(RegExp.$2) : 0;
- else if ((!this.vendver && this.mz) || this.agent.indexOf('Camino')>0)
- this.vendver = (/rv:([0-9\.]+)/.test(this.agent)) ? parseFloat(RegExp.$1) : 0;
- else if (this.ie && window.RegExp)
- this.vendver = (/msie\s+([0-9\.]+)/.test(this.agent_lc)) ? parseFloat(RegExp.$1) : 0;
- else if (this.konq && window.RegExp)
- this.vendver = (/khtml\/([0-9\.]+)/.test(this.agent_lc)) ? parseFloat(RegExp.$1) : 0;
+ this.dom2 = document.addEventListener && document.removeEventListener;
+
+ this.ie = (document.all && !window.opera) || (this.win && this.agent_lc.indexOf('trident/') > 0);
+
+ if (this.ie) {
+ this.ie6 = this.appver.indexOf('MSIE 6') > 0;
+ this.ie7 = this.appver.indexOf('MSIE 7') > 0;
+ this.ie8 = this.appver.indexOf('MSIE 8') > 0;
+ this.ie9 = this.appver.indexOf('MSIE 9') > 0;
+ }
+ else {
+ this.chrome = this.agent_lc.indexOf('chrome') > 0;
+ this.safari = !this.chrome && (this.agent_lc.indexOf('safari') > 0 || this.agent_lc.indexOf('applewebkit') > 0);
+ this.konq = this.agent_lc.indexOf('konqueror') > 0;
+ this.mz = this.dom && !this.chrome && !this.safari && !this.konq && this.agent.indexOf('Mozilla') >= 0;
+ this.iphone = this.safari && (this.agent_lc.indexOf('iphone') > 0 || this.agent_lc.indexOf('ipod') > 0);
+ this.ipad = this.safari && this.agent_lc.indexOf('ipad') > 0;
+ this.opera = window.opera ? true : false;
+ }
+
+ if (!this.vendver) {
+ // common version strings
+ this.vendver = /(khtml|chrome|safari|applewebkit|opera|msie)(\s|\/)([0-9\.]+)/.test(this.agent_lc) ? parseFloat(RegExp.$3) : 0;
+
+ // any other (Mozilla, Camino, IE>=11)
+ if (!this.vendver)
+ this.vendver = /rv:([0-9\.]+)/.test(this.agent) ? parseFloat(RegExp.$1) : 0;
+ }
// get real language out of safari's user agent
if (this.safari && (/;\s+([a-z]{2})-[a-z]{2}\)/.test(this.agent_lc)))
@@ -86,11 +83,6 @@ function roundcube_browser()
this.tablet = /ipad|android|xoom|sch-i800|playbook|tablet|kindle/i.test(this.agent_lc);
this.mobile = /iphone|ipod|blackberry|iemobile|opera mini|opera mobi|mobile/i.test(this.agent_lc);
this.touch = this.mobile || this.tablet;
- this.dhtml = ((this.ie4 && this.win) || this.ie5 || this.ie6 || this.ns4 || this.mz);
- this.vml = (this.win && this.ie && this.dom && !this.opera);
- this.pngalpha = (this.mz || (this.opera && this.vendver >= 6) || (this.ie && this.mac && this.vendver >= 5) ||
- (this.ie && this.win && this.vendver >= 5.5) || this.safari);
- this.opacity = (this.mz || (this.ie && this.vendver >= 5.5 && !this.opera) || (this.safari && this.vendver >= 100));
this.cookies = n.cookieEnabled;
// test for XMLHTTP support
diff --git a/program/js/editor.js b/program/js/editor.js
index 020971d6e..df3d41240 100644
--- a/program/js/editor.js
+++ b/program/js/editor.js
@@ -61,6 +61,9 @@ function rcmail_editor_init(config)
if (!active)
rcmail.spellcheck_state();
});
+ ed.onKeyPress.add(function(ed, e) {
+ rcmail.compose_type_activity++;
+ });
}
}
diff --git a/program/js/list.js b/program/js/list.js
index e1d57745c..4ae6c0c66 100644
--- a/program/js/list.js
+++ b/program/js/list.js
@@ -795,8 +795,10 @@ select_row: function(id, mod_key, with_mouse)
break;
case CONTROL_KEY:
- if (with_mouse)
+ if (with_mouse) {
+ this.shift_start = id;
this.highlight_row(id, true);
+ }
break;
case CONTROL_SHIFT_KEY:
@@ -893,7 +895,7 @@ select_children: function(uid)
for (i=0; i<len; i++)
if (!this.in_selection(children[i]))
- this.select_row(children[i], CONTROL_KEY);
+ this.select_row(children[i], CONTROL_KEY, true);
},
@@ -1133,13 +1135,15 @@ key_press: function(e)
// Stop propagation so that the browser doesn't scroll
rcube_event.cancel(e);
return this.use_arrow_key(keyCode, mod_key);
+
case 32:
rcube_event.cancel(e);
return this.select_row(this.last_selected, mod_key, true);
+
case 37: // Left arrow key
case 39: // Right arrow key
case 107: // Plus sign on a numeric keypad
- case 109: // Minus sign on a numeric keypad
+ case 109: // Minus sign on a numeric keypad
// Stop propagation
rcube_event.cancel(e);
var ret = this.use_plusminus_key(keyCode, mod_key);
@@ -1148,20 +1152,26 @@ key_press: function(e)
this.triggerEvent('keypress');
this.modkey = 0;
return ret;
+
case 36: // Home
this.select_first(mod_key);
return rcube_event.cancel(e);
+
case 35: // End
this.select_last(mod_key);
return rcube_event.cancel(e);
+
case 27:
if (this.drag_active)
return this.drag_mouse_up(e);
+
if (this.col_drag_active) {
this.selected_column = null;
return this.column_drag_mouse_up(e);
}
+
return rcube_event.cancel(e);
+
default:
this.key_pressed = keyCode;
this.modkey = mod_key;