From c5c8e73351c38ece1b3814a8c82a0439e7424fc4 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 25 Feb 2015 08:07:11 -0500 Subject: Improved handling of storage errors after message is sent After sending a message it is stored in Sent folder, this operation may fail, e.g. because of "over quota" error. In such a case we'll not close the compose window, but display the error and, if user clicks Send/Save button, we'll display a dialog informing about the situation and providing an option to try the save operation again. --- program/js/app.js | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'program/js/app.js') diff --git a/program/js/app.js b/program/js/app.js index e818955bd..56d07f37e 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -654,7 +654,7 @@ function rcube_webmail() // check input before leaving compose step 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'))) + if (!this.env.is_sent && 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 @@ -1115,7 +1115,7 @@ function rcube_webmail() break; case 'send': - if (!props.nocheck && !this.check_compose_input(command)) + if (!props.nocheck && !this.env.is_sent && !this.check_compose_input(command)) break; // Reset the auto-save timer @@ -3489,15 +3489,35 @@ function rcube_webmail() .attr({ 'autocomplete': 'off', 'aria-autocomplete': 'list', 'aria-expanded': 'false', 'role': 'combobox' }); }; - this.submit_messageform = function(draft) + this.submit_messageform = function(draft, saveonly) { var form = this.gui_objects.messageform; if (!form) return; + // the message has been sent but not saved, ask the user what to do + if (!saveonly && this.env.is_sent) { + return this.show_popup_dialog(this.get_label('messageissent'), '', + [{ + text: this.get_label('save'), + 'class': 'mainaction', + click: function() { + ref.submit_messageform(false, true); + $(this).dialog('close'); + } + }, + { + text: this.get_label('cancel'), + click: function() { + $(this).dialog('close'); + } + }] + ); + } + // all checks passed, send message - var msgid = this.set_busy(true, draft ? 'savingmessage' : 'sendingmessage'), + var msgid = this.set_busy(true, draft || saveonly ? 'savingmessage' : 'sendingmessage'), lang = this.spellcheck_lang(), files = []; @@ -3511,6 +3531,10 @@ function rcube_webmail() form.action = this.add_url(form.action, '_lang', lang); form.action = this.add_url(form.action, '_framed', 1); + if (saveonly) { + form.action = this.add_url(form.action, '_saveonly', 1); + } + // register timer to notify about connection timeout this.submit_timer = setTimeout(function(){ ref.set_busy(false, null, msgid); @@ -4358,13 +4382,14 @@ function rcube_webmail() }; // action executed after mail is sent - this.sent_successfully = function(type, msg, folders) + this.sent_successfully = function(type, msg, folders, save_error) { this.display_message(msg, type); this.compose_skip_unsavedcheck = true; if (this.env.extwin) { - this.lock_form(this.gui_objects.messageform); + if (!save_error) + this.lock_form(this.gui_objects.messageform); var filter = {task: 'mail', action: ''}, rc = this.opener(false, filter) || this.opener(true, filter); @@ -4377,12 +4402,16 @@ function rcube_webmail() } } - setTimeout(function() { window.close(); }, 1000); + if (!save_error) + setTimeout(function() { window.close(); }, 1000); } - else { + else if (!save_error) { // before redirect we need to wait some time for Chrome (#1486177) setTimeout(function() { ref.list_mailbox(); }, 500); } + + if (save_error) + this.env.is_sent = true; }; -- cgit v1.2.3 From 9ad0fc489ff3c32face845989a8f5f311208b4f9 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 2 Mar 2015 13:51:51 +0100 Subject: Fix javascript error after creating a folder which is a subfolder of another one (#1490297) --- CHANGELOG | 1 + program/js/app.js | 6 ++++-- program/steps/settings/folders.inc | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'program/js/app.js') diff --git a/CHANGELOG b/CHANGELOG index 47ff57340..1a3b412cf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,6 +23,7 @@ CHANGELOG Roundcube Webmail - Fix parsing invalid HTML messages with BOM after (#1490291) - Fix duplicate entry on timezones list in rcube_config::timezone_name_from_abbr() (#1490293) - Fix so localized folder name is displayed in multi-folder search result (#1490243) +- Fix javascript error after creating a folder which is a subfolder of another one (#1490297) RELEASE 1.1.0 ------------- diff --git a/program/js/app.js b/program/js/app.js index 56d07f37e..7d3f0c55d 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1608,7 +1608,8 @@ function rcube_webmail() this.folder_collapsed = function(node) { - var prefname = this.env.task == 'addressbook' ? 'collapsed_abooks' : 'collapsed_folders'; + var prefname = this.env.task == 'addressbook' ? 'collapsed_abooks' : 'collapsed_folders', + old = this.env[prefname]; if (node.collapsed) { this.env[prefname] = this.env[prefname] + '&'+urlencode(node.id)+'&'; @@ -1624,7 +1625,8 @@ function rcube_webmail() } if (!this.drag_active) { - this.command('save-pref', { name: prefname, value: this.env[prefname] }); + if (old !== this.env[prefname]) + this.command('save-pref', { name: prefname, value: this.env[prefname] }); if (this.env.unread_counts) this.set_unread_count_display(node.id, false); diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index 6db0b17e8..443635fae 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -265,7 +265,7 @@ function rcmail_subscription_form($attrib) $js_folders = array(); $folders = array(); - $collapsed = $RCMAIL->config->get('collapsed_folders'); + $collapsed = (string) $RCMAIL->config->get('collapsed_folders'); // create list of available folders foreach ($list_folders as $i => $folder) { -- cgit v1.2.3 From 1ec105c6855c99f4f2a12038d6f9598067fdf205 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 9 Mar 2015 07:44:11 -0400 Subject: Fix so search filter, scope and fields are reset on folder change --- CHANGELOG | 1 + program/js/app.js | 19 ++++++++++++++----- program/steps/mail/func.inc | 13 +------------ program/steps/mail/list.inc | 14 -------------- 4 files changed, 16 insertions(+), 31 deletions(-) (limited to 'program/js/app.js') diff --git a/CHANGELOG b/CHANGELOG index 94f4829a8..19c5ed469 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -30,6 +30,7 @@ CHANGELOG Roundcube Webmail - Fix missing vcard_attachment icon on messages list (#1490303) - Fix storing signatures with big images in MySQL database (#1490306) - Fix Opera browser detection in javascript (#1490307) +- Fix so search filter, scope and fields are reset on folder change RELEASE 1.1.0 ------------- diff --git a/program/js/app.js b/program/js/app.js index 7d3f0c55d..223606e45 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -2378,6 +2378,9 @@ function rcube_webmail() // list messages of a specific mailbox using filter this.filter_mailbox = function(filter) { + if (this.filter_disabled) + return; + var lock = this.set_busy(true, 'searching'); this.clear_message_list(); @@ -2411,16 +2414,22 @@ function rcube_webmail() if (sort) url._sort = sort; - // also send search request to get the right messages - if (this.env.search_request) - url._search = this.env.search_request; - - // set page=1 if changeing to another mailbox + // folder change, reset page, search scope, etc. if (this.env.mailbox != mbox) { page = 1; this.env.current_page = page; + this.env.search_scope = 'base'; this.select_all_mode = false; + + // reset search filter + this.filter_disabled = true; + if (this.gui_objects.search_filter) + $(this.gui_objects.search_filter).val('ALL').change(); + this.filter_disabled = false; } + // also send search request to get the right messages + else if (this.env.search_request) + url._search = this.env.search_request; if (!update_only) { // unselect selected messages and clear the list and message data diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 341c14bc8..684cdf933 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -64,17 +64,6 @@ if (empty($RCMAIL->action) || $RCMAIL->action == 'list') { $mbox_name = $RCMAIL->storage->get_folder(); if (empty($RCMAIL->action)) { - // initialize searching result if search_filter is used - if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') { - $RCMAIL->storage->search($mbox_name, $_SESSION['search_filter'], RCUBE_CHARSET, rcmail_sort_column()); - - $search_request = md5($mbox_name.$_SESSION['search_filter']); - $_SESSION['search'] = $RCMAIL->storage->get_search_set(); - $_SESSION['search_request'] = $search_request; - - $OUTPUT->set_env('search_request', $search_request); - } - $OUTPUT->set_env('search_mods', rcmail_search_mods()); if (!empty($_SESSION['search_scope'])) @@ -2056,7 +2045,7 @@ function rcmail_search_filter($attrib) $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('low'), 'HEADER X-PRIORITY 4'); $select_filter->add($RCMAIL->gettext('priority').': '.$RCMAIL->gettext('lowest'), 'HEADER X-PRIORITY 5'); - $out = $select_filter->show($_SESSION['search_filter']); + $out = $select_filter->show($_REQUEST['_search'] ? $_SESSION['search_filter'] : 'ALL'); $RCMAIL->output->add_gui_object('search_filter', $attrib['id']); diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc index 32197bde3..4f2b73c53 100644 --- a/program/steps/mail/list.inc +++ b/program/steps/mail/list.inc @@ -58,20 +58,6 @@ $threading = (bool) $RCMAIL->storage->get_threading(); // Synchronize mailbox cache, handle flag changes $RCMAIL->storage->folder_sync($mbox_name); -// initialize searching result if search_filter is used -if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') { - $search_request = md5($mbox_name.$_SESSION['search_scope'].$_SESSION['search_filter']); - $RCMAIL->storage->search($mbox_name, $_SESSION['search_filter'], RCUBE_CHARSET, rcmail_sort_column()); - - $_SESSION['search'] = $RCMAIL->storage->get_search_set(); - $_SESSION['search_request'] = $search_request; - - $OUTPUT->set_env('search_request', $search_request); - $OUTPUT->set_env('search_filter', $_SESSION['search_filter']); - - $multifolder = is_a($_SESSION['search'][1], 'rcube_result_multifolder'); -} - // fetch message headers if ($count = $RCMAIL->storage->count($mbox_name, $threading ? 'THREADS' : 'ALL', !empty($_REQUEST['_refresh']))) { $a_headers = $RCMAIL->storage->list_messages($mbox_name, NULL, rcmail_sort_column(), rcmail_sort_order()); -- cgit v1.2.3 From c2df5d4e13e9ab63e8f152d638eec35284efdf2f Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 9 Mar 2015 09:24:05 -0400 Subject: Unified request* event arguments handling, added support for _unlock and _action parameters --- CHANGELOG | 1 + program/js/app.js | 72 ++++++++++++++++++++++++++++++++-------------------- program/js/common.js | 28 ++++++++++++++++++++ 3 files changed, 73 insertions(+), 28 deletions(-) (limited to 'program/js/app.js') diff --git a/CHANGELOG b/CHANGELOG index 19c5ed469..1ae0a3a0e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ CHANGELOG Roundcube Webmail - Add possibility to configure max_allowed_packet value for all database engines (#1490283) - Improved handling of storage errors after message is sent - Update to TinyMCE 4.1.8 +- Unified request* event arguments handling, added support for _unlock and _action parameters - Fix refreshing of drafts list when sending a message which was saved in meantime (#1490238) - Fix saving/sending emoticon images when assets_dir is set - Fix PHP fatal error when visiting Vacation interface and there's no sieve script yet (#1490292) diff --git a/program/js/app.js b/program/js/app.js index 223606e45..b8e6e775c 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -7287,22 +7287,32 @@ function rcube_webmail() }; // send a http request to the server - this.http_request = function(action, query, lock) + this.http_request = function(action, data, lock) { - var url = this.url(action, query); + if (typeof data !== 'object') + data = rcube_parse_query(data); + + data._remote = 1; + data._unlock = lock ? lock : 0; // trigger plugin hook - var result = this.triggerEvent('request'+action, query); + var result = this.triggerEvent('request' + action, data); - if (result !== undefined) { - // abort if one the handlers returned false - if (result === false) - return false; - else - url = this.url(action, result); + // abort if one of the handlers returned false + if (result === false) { + if (data._unlock) + this.set_busy(false, null, data._unlock); + return false; + } + else if (result !== undefined) { + data = result; + if (data._action) { + action = data._action; + delete data._action; + } } - url += '&_remote=1'; + var url = this.url(action, data); // send request this.log('HTTP GET: ' + url); @@ -7311,33 +7321,39 @@ function rcube_webmail() this.start_keepalive(); return $.ajax({ - type: 'GET', url: url, data: { _unlock:(lock?lock:0) }, dataType: 'json', - success: function(data){ ref.http_response(data); }, + type: 'GET', url: url, dataType: 'json', + success: function(data) { ref.http_response(data); }, error: function(o, status, err) { ref.http_error(o, status, err, lock, action); } }); }; // send a http POST request to the server - this.http_post = function(action, postdata, lock) + this.http_post = function(action, data, lock) { - var url = this.url(action); + if (typeof data !== 'object') + data = rcube_parse_query(data); - if (postdata && typeof postdata === 'object') { - postdata._remote = 1; - postdata._unlock = (lock ? lock : 0); - } - else - postdata += (postdata ? '&' : '') + '_remote=1' + (lock ? '&_unlock='+lock : ''); + data._remote = 1; + data._unlock = lock ? lock : 0; // trigger plugin hook - var result = this.triggerEvent('request'+action, postdata); - if (result !== undefined) { - // abort if one of the handlers returned false - if (result === false) - return false; - else - postdata = result; + var result = this.triggerEvent('request'+action, data); + + // abort if one of the handlers returned false + if (result === false) { + if (data._unlock) + this.set_busy(false, null, data._unlock); + return false; } + else if (result !== undefined) { + data = result; + if (data._action) { + action = data._action; + delete data._action; + } + } + + var url = this.url(action); // send request this.log('HTTP POST: ' + url); @@ -7346,7 +7362,7 @@ function rcube_webmail() this.start_keepalive(); return $.ajax({ - type: 'POST', url: url, data: postdata, dataType: 'json', + type: 'POST', url: url, data: data, dataType: 'json', success: function(data){ ref.http_response(data); }, error: function(o, status, err) { ref.http_error(o, status, err, lock, action); } }); diff --git a/program/js/common.js b/program/js/common.js index e60a14e38..3babf1efb 100644 --- a/program/js/common.js +++ b/program/js/common.js @@ -654,6 +654,34 @@ jQuery.fn.placeholder = function(text) { }); }; +// function to parse query string into an object +rcube_parse_query = function(query) +{ + if (!query) + return {}; + + var params = {}, e, k, v, + re = /([^&=]+)=?([^&]*)/g, + decodeRE = /\+/g, // Regex for replacing addition symbol with a space + decode = function (str) { return decodeURIComponent(str.replace(decodeRE, ' ')); }; + + query = query.replace(/\?/, ''); + + while (e = re.exec(query)) { + k = decode(e[1]); + v = decode(e[2]); + + if (k.substring(k.length - 2) === '[]') { + k = k.substring(0, k.length - 2); + (params[k] || (params[k] = [])).push(v); + } + else + params[k] = v; + } + + return params; +}; + // This code was written by Tyler Akins and has been placed in the // public domain. It would be nice if you left this header intact. -- cgit v1.2.3 From da1816edd8a5764c7bb6c7e129a7c4ae5e31697c Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 9 Mar 2015 17:35:51 +0100 Subject: Reset search filter on folder selection and search reset --- program/js/app.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'program/js/app.js') diff --git a/program/js/app.js b/program/js/app.js index b8e6e775c..a178a3eb7 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -774,7 +774,7 @@ function rcube_webmail() case 'list': if (props && props != '') { - this.reset_qsearch(); + this.reset_qsearch(true); } if (this.env.action == 'compose' && this.env.extwin) { window.close(); @@ -1224,7 +1224,7 @@ function rcube_webmail() var n, s = this.env.search_request || this.env.qsearch, ss = this.gui_objects.qsearchbox && this.gui_objects.qsearchbox.value != ''; - this.reset_qsearch(); + this.reset_qsearch(true); this.select_all_mode = false; if (s && this.env.action == 'compose') { @@ -2420,12 +2420,7 @@ function rcube_webmail() this.env.current_page = page; this.env.search_scope = 'base'; this.select_all_mode = false; - - // reset search filter - this.filter_disabled = true; - if (this.gui_objects.search_filter) - $(this.gui_objects.search_filter).val('ALL').change(); - this.filter_disabled = false; + this.reset_search_filter(); } // also send search request to get the right messages else if (this.env.search_request) @@ -4341,8 +4336,17 @@ function rcube_webmail() return url; }; + // reset search filter + this.reset_search_filter = function() + { + this.filter_disabled = true; + if (this.gui_objects.search_filter) + $(this.gui_objects.search_filter).val('ALL').change(); + this.filter_disabled = false; + }; + // reset quick-search form - this.reset_qsearch = function() + this.reset_qsearch = function(all) { if (this.gui_objects.qsearchbox) this.gui_objects.qsearchbox.value = ''; @@ -4350,6 +4354,11 @@ function rcube_webmail() if (this.env.qsearch) this.abort_request(this.env.qsearch); + if (all) { + this.env.search_scope = 'base'; + this.reset_search_filter(); + } + this.env.qsearch = null; this.env.search_request = null; this.env.search_id = null; -- cgit v1.2.3 From d12b999403b5f1dd413bc9c78d9384f5abc11d99 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 9 Mar 2015 19:40:57 +0100 Subject: (Properly) reset search filter on reset-search action --- program/js/app.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'program/js/app.js') diff --git a/program/js/app.js b/program/js/app.js index a178a3eb7..8853335ac 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1221,8 +1221,7 @@ function rcube_webmail() // reset quicksearch case 'reset-search': - var n, s = this.env.search_request || this.env.qsearch, - ss = this.gui_objects.qsearchbox && this.gui_objects.qsearchbox.value != ''; + var n, s = this.env.search_request || this.env.qsearch; this.reset_qsearch(true); this.select_all_mode = false; @@ -1231,7 +1230,7 @@ function rcube_webmail() if (this.contact_list) this.list_contacts_clear(); } - else if (s && ss && this.env.mailbox) { + else if (s && this.env.mailbox) { this.list_mailbox(this.env.mailbox, 1); } else if (s && this.task == 'addressbook') { -- cgit v1.2.3 From 3c4d3dcc42eb8907134de11bd1fed7ef6f97f0a7 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 11 Mar 2015 18:59:54 +0100 Subject: Fix submission of _reload parameter when switching address books --- program/js/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program/js/app.js') diff --git a/program/js/app.js b/program/js/app.js index 8853335ac..5f3ca5f65 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -894,7 +894,7 @@ function rcube_webmail() else { // reload form if (props == 'reload') { - form.action += '?_reload=1'; + form.action += '&_reload=1'; } else if (this.task == 'settings' && (this.env.identities_level % 2) == 0 && (input = $("input[name='_email']", form)) && input.length && !rcube_check_email(input.val()) -- cgit v1.2.3 From 65e735dec541564c01defb58eac326e7369feb7e Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 12 Mar 2015 20:48:19 +0100 Subject: Fix javascripts errors in IE8 - lack of Event.which, focusing a hidden element (#1490318) --- CHANGELOG | 1 + program/js/app.js | 11 +++++++---- program/js/list.js | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'program/js/app.js') diff --git a/CHANGELOG b/CHANGELOG index d50f38857..ac6d5b9ce 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -40,6 +40,7 @@ CHANGELOG Roundcube Webmail - Fix backtick character handling in sql queries (#1490312) - Fix redirct URL for attachments loaded in an iframe when behind proxy (#1490191) - Fix menu container references to point to the actual
    element (#1490313) +- Fix javascripts errors in IE8 - lack of Event.which, focusing a hidden element (#1490318) RELEASE 1.1.0 ------------- diff --git a/program/js/app.js b/program/js/app.js index 5f3ca5f65..d6c5cd8aa 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -3349,7 +3349,7 @@ function rcube_webmail() if (!this.gui_objects.messageform) return false; - var i, pos, input_from = $("[name='_from']"), + var i, elem, pos, input_from = $("[name='_from']"), input_to = $("[name='_to']"), input_subject = $("input[name='_subject']"), input_message = $("[name='_message']").get(0), @@ -3403,11 +3403,14 @@ function rcube_webmail() this.compose_restore_dialog(0, html_mode) if (input_to.val() == '') - input_to.focus(); + elem = input_to; else if (input_subject.val() == '') - input_subject.focus(); + elem = input_subject; else if (input_message) - input_message.focus(); + elem = input_message; + + // focus first empty element (need to be visible on IE8) + $(elem).filter(':visible').focus(); this.env.compose_focus_elem = document.activeElement; diff --git a/program/js/list.js b/program/js/list.js index 9a7f2840e..9c41a12da 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -151,8 +151,8 @@ init_row: function(row) this.rows[uid] = {uid:uid, id:row.id, obj:row}; // set eventhandlers to table row (only left-button-clicks in mouseup) - row.onmousedown = function(e){ return self.drag_row(e, this.uid); }; - row.onmouseup = function(e){ if (e.which == 1) return self.click_row(e, this.uid); }; + $(row).mousedown(function(e) { return self.drag_row(e, this.uid); }) + .mouseup(function(e) { if (e.which == 1) return self.click_row(e, this.uid); }); if (bw.touch && row.addEventListener) { row.addEventListener('touchstart', function(e) { -- cgit v1.2.3 From 465ba8d11bc27dc44407337afff8d4fe12bce955 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Sun, 15 Mar 2015 20:03:35 +0100 Subject: Avoid errors when message list doesn't have a header --- program/js/app.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'program/js/app.js') diff --git a/program/js/app.js b/program/js/app.js index d6c5cd8aa..1da2a8173 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -6728,6 +6728,9 @@ function rcube_webmail() this.env.listcols = listcols; + if (!this.env.coltypes) + this.env.coltypes = {}; + // replace old column headers if (thead) { if (repl) { -- cgit v1.2.3 From e8e88d347d99dacfe6e34713a52e412561fcfadd Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 10 Apr 2015 09:46:21 +0200 Subject: Fix bug where forced extwin page reload could exit from the extwin mode (#1490350) With small improvements in rcube_webmail.url() method. --- CHANGELOG | 1 + program/js/app.js | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'program/js/app.js') diff --git a/CHANGELOG b/CHANGELOG index 30edbdc39..3096b6e68 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ CHANGELOG Roundcube Webmail - Fix so unrecognized TNEF attachments are displayed on the list of attachments (#1490351) - Fix lack of signature separator for plain text signatures in html mode (#1490352) - Fix font artifact in Google Chrome on Windows (#1490353) +- Fix bug where forced extwin page reload could exit from the extwin mode (#1490350) RELEASE 1.1.1 ------------- diff --git a/program/js/app.js b/program/js/app.js index 1da2a8173..64fd548c9 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1440,7 +1440,7 @@ function rcube_webmail() else if (delay) setTimeout(function() { ref.reload(); }, delay); else if (window.location) - location.href = this.env.comm_path + (this.env.action ? '&_action='+this.env.action : ''); + location.href = this.url('', {_extwin: this.env.extwin}); }; // Add variable to GET string, replace old value if exists @@ -7222,7 +7222,7 @@ function rcube_webmail() // compose a valid url with the given parameters this.url = function(action, query) { - var querystring = typeof query === 'string' ? '&' + query : ''; + var querystring = typeof query === 'string' ? query : ''; if (typeof action !== 'string') query = action; @@ -7234,12 +7234,12 @@ function rcube_webmail() else if (this.env.action) query._action = this.env.action; - var base = this.env.comm_path, k, param = {}; + var url = this.env.comm_path, k, param = {}; // overwrite task name if (action && action.match(/([a-z0-9_-]+)\/([a-z0-9-_.]+)/)) { query._action = RegExp.$2; - base = base.replace(/\_task=[a-z0-9_-]+/, '_task='+RegExp.$1); + url = url.replace(/\_task=[a-z0-9_-]+/, '_task=' + RegExp.$1); } // remove undefined values @@ -7248,7 +7248,13 @@ function rcube_webmail() param[k] = query[k]; } - return base + (base.indexOf('?') > -1 ? '&' : '?') + $.param(param) + querystring; + if (param = $.param(param)) + url += (url.indexOf('?') > -1 ? '&' : '?') + param; + + if (querystring) + url += (url.indexOf('?') > -1 ? '&' : '?') + querystring; + + return url; }; this.redirect = function(url, lock) -- cgit v1.2.3 From 09225a41ec7135031a4c0304b8dcdccd45904939 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 16 Apr 2015 10:55:32 +0200 Subject: Add option to place signature at bottom of the quoted text even in top-posting mode [sig_below] --- CHANGELOG | 1 + config/defaults.inc.php | 5 ++++ program/js/app.js | 6 +++-- program/js/editor.js | 51 +++++++++++++++++------------------ program/localization/en_US/labels.inc | 1 + program/steps/mail/compose.inc | 7 +++-- program/steps/settings/func.inc | 14 ++++++++++ program/steps/settings/save_prefs.inc | 1 + 8 files changed, 56 insertions(+), 30 deletions(-) (limited to 'program/js/app.js') diff --git a/CHANGELOG b/CHANGELOG index 6c584fce1..c3049eb73 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,7 @@ CHANGELOG Roundcube Webmail - Plugin API: Added message_part_body hook - Plugin API: Added message_ready hook - Plugin API: Add special onload() method to execute plugin actions before startup (session and GUI initialization) +- Add option to place signature at bottom of the quoted text even in top-posting mode [sig_below] - Fix handling of %-encoded entities in mailto: URLs (#1490346) - Fix zipped messages downloads after selecting all messages in a folder (#1490339) - Fix vpopmaild driver of password plugin diff --git a/config/defaults.inc.php b/config/defaults.inc.php index 50ae71ed9..df8b612ea 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -1086,6 +1086,11 @@ $config['strip_existing_sig'] = true; // 3 - Forwards and Replies only $config['show_sig'] = 1; +// By default the signature is placed depending on cursor position (reply_mode). +// Sometimes it might be convenient to start the reply on top but keep +// the signature below the quoted text (sig_below = true). +$config['sig_below'] = false; + // Use MIME encoding (quoted-printable) for 8bit characters in message body $config['force_7bit'] = false; diff --git a/program/js/app.js b/program/js/app.js index 64fd548c9..b6b4d319c 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -3384,14 +3384,16 @@ function rcube_webmail() if (!html_mode) { pos = this.env.top_posting ? 0 : input_message.value.length; - this.set_caret_pos(input_message, pos); // add signature according to selected identity - // if we have HTML editor, signature is added in callback + // if we have HTML editor, signature is added in a callback if (input_from.prop('type') == 'select-one') { this.change_identity(input_from[0]); } + // set initial cursor position + this.set_caret_pos(input_message, pos); + // scroll to the bottom of the textarea (#1490114) if (pos) { $(input_message).scrollTop(input_message.scrollHeight); diff --git a/program/js/editor.js b/program/js/editor.js index 296a161ca..abd800ca3 100644 --- a/program/js/editor.js +++ b/program/js/editor.js @@ -485,32 +485,37 @@ function rcube_text_editor(config, id) sig = rcmail.env.signatures[id].text; sig = sig.replace(/\r\n/g, '\n'); - if (rcmail.env.top_posting) { - if (p >= 0) { // in place of removed signature - message = message.substring(0, p) + sig + message.substring(p, message.length); - cursor_pos = p - 1; - } - else if (!message) { // empty message - cursor_pos = 0; - message = '\n\n' + sig; - } - else if (pos = rcmail.get_caret_pos(input_message.get(0))) { // at cursor position + // in place of removed signature + if (p >= 0) { + message = message.substring(0, p) + sig + message.substring(p, message.length); + cursor_pos = p - 1; + } + // empty message + else if (!message) { + message = '\n\n' + sig; + cursor_pos = 0; + } + else if (rcmail.env.top_posting && !rcmail.env.sig_below) { + // at cursor position + if (pos = rcmail.get_caret_pos(input_message.get(0))) { message = message.substring(0, pos) + '\n' + sig + '\n\n' + message.substring(pos, message.length); cursor_pos = pos; } - else { // on top - cursor_pos = 0; + // on top + else { message = '\n\n' + sig + '\n\n' + message.replace(/^[\r\n]+/, ''); + cursor_pos = 0; } } else { message = message.replace(/[\r\n]+$/, ''); - cursor_pos = !rcmail.env.top_posting && message.length ? message.length+1 : 0; + cursor_pos = !rcmail.env.top_posting && message.length ? message.length + 1 : 0; message += '\n\n' + sig; } } - else + else { cursor_pos = rcmail.env.top_posting ? 0 : message.length; + } input_message.val(message); @@ -528,24 +533,18 @@ function rcube_text_editor(config, id) sigElem = doc.createElement('div'); sigElem.setAttribute('id', '_rc_sig'); - if (rcmail.env.top_posting) { - // if no existing sig and top posting then insert at caret pos + if (rcmail.env.top_posting && !rcmail.env.sig_below) { this.editor.getWin().focus(); // correct focus in IE & Chrome var node = this.editor.selection.getNode(); - if (node.nodeName == 'BODY') { - // no real focus, insert at start - body.insertBefore(sigElem, body.firstChild); - body.insertBefore(doc.createElement('br'), body.firstChild); - } - else { - body.insertBefore(sigElem, node.nextSibling); - body.insertBefore(doc.createElement('br'), node.nextSibling); - } + + // insert at start or at cursor position if found + body.insertBefore(sigElem, node.nodeName == 'BODY' ? body.firstChild : node.nextSibling); + body.insertBefore(doc.createElement('p'), sigElem); } else { body.appendChild(sigElem); - position_element = $(sigElem).prev(); + position_element = rcmail.env.top_posting ? body.firstChild : $(sigElem).prev(); } } diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index fac52ba1e..8202b140d 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -509,6 +509,7 @@ $labels['autoaddsignature'] = 'Automatically add signature'; $labels['newmessageonly'] = 'new message only'; $labels['replyandforwardonly'] = 'replies and forwards only'; $labels['insertsignature'] = 'Insert signature'; +$labels['sigbelow'] = 'Place signature below the quoted message'; $labels['previewpanemarkread'] = 'Mark previewed messages as read'; $labels['afternseconds'] = 'after $n seconds'; $labels['reqmdn'] = 'Always request a return receipt'; diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index ba6f334c9..5009c525a 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -91,6 +91,7 @@ $OUTPUT->set_env('compose_id', $COMPOSE['id']); $OUTPUT->set_env('session_id', session_id()); $OUTPUT->set_env('mailbox', $RCMAIL->storage->get_folder()); $OUTPUT->set_env('top_posting', intval($RCMAIL->config->get('reply_mode')) > 0); +$OUTPUT->set_env('sig_below', $RCMAIL->config->get('sig_below')); $OUTPUT->set_env('recipients_separator', trim($RCMAIL->config->get('recipients_separator', ','))); $OUTPUT->set_env('save_localstorage', (bool)$RCMAIL->config->get('compose_save_localstorage')); $OUTPUT->set_env('is_sent', false); @@ -612,8 +613,10 @@ function rcmail_compose_header_from($attrib) if (count($MESSAGE->identities)) { $a_signatures = array(); $identities = array(); - $separator = intval($RCMAIL->config->get('reply_mode')) > 0 - && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD) ? '---' : '-- '; + $top_posting = intval($RCMAIL->config->get('reply_mode')) > 0 + && !$RCMAIL->config->get('sig_below') + && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD); + $separator = $top_posting ? '---' : '-- '; $field_attrib['onchange'] = rcmail_output::JS_OBJECT_NAME.".change_identity(this)"; $select_from = new html_select($field_attrib); diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index 46aed3019..c763dd39a 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -845,6 +845,20 @@ function rcmail_user_prefs($current = null) ); } + if (!isset($no_override['sig_below'])) { + if (!$current) { + continue 2; + } + + $field_id = 'rcmfd_sig_below'; + $input = new html_checkbox(array('name' => '_sig_below', 'id' => $field_id, 'value' => 1)); + + $blocks['sig']['options']['sig_below'] = array( + 'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('sigbelow'))), + 'content' => $input->show($RCMAIL->config->get('sig_below') ? 1 : 0), + ); + } + if (!isset($no_override['strip_existing_sig'])) { if (!$current) { continue 2; diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc index f0ce9c9a3..4ecaa70e6 100644 --- a/program/steps/settings/save_prefs.inc +++ b/program/steps/settings/save_prefs.inc @@ -85,6 +85,7 @@ case 'compose': 'spellcheck_ignore_caps' => isset($_POST['_spellcheck_ignore_caps']) ? true : false, 'show_sig' => isset($_POST['_show_sig']) ? intval($_POST['_show_sig']) : 1, 'reply_mode' => isset($_POST['_reply_mode']) ? intval($_POST['_reply_mode']) : 0, + 'sig_below' => isset($_POST['_sig_below']) ? true : false, 'strip_existing_sig' => isset($_POST['_strip_existing_sig']), 'default_font' => rcube_utils::get_input_value('_default_font', rcube_utils::INPUT_POST), 'default_font_size' => rcube_utils::get_input_value('_default_font_size', rcube_utils::INPUT_POST), -- cgit v1.2.3 From 28331d5ed23029753e0a8c5202e60b02716628cc Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 18 Apr 2015 10:07:25 -0400 Subject: Trigger 'listupdate' event also on response to check-recent request --- program/js/app.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'program/js/app.js') diff --git a/program/js/app.js b/program/js/app.js index b6b4d319c..c11ae7762 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -7507,7 +7507,7 @@ function rcube_webmail() this.enable_command('import-messages', !is_multifolder); this.enable_command('expand-all', 'expand-unread', 'collapse-all', this.env.threading && this.env.messagecount && !is_multifolder); - if ((response.action == 'list' || response.action == 'search') && this.message_list) { + if (this.message_list) { var list = this.message_list, uid = this.env.list_uid; // highlight message row when we're back from message page @@ -7520,12 +7520,14 @@ function rcube_webmail() delete this.env.list_uid; } - this.enable_command('set-listmode', this.env.threads && !is_multifolder); - if (list.rowcount > 0) - list.focus(); - this.msglist_select(list); - this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:list.rowcount }); + if (response.action == 'list' || response.action == 'search') { + this.enable_command('set-listmode', this.env.threads && !is_multifolder); + if (list.rowcount > 0) + list.focus(); + this.msglist_select(list); + } + this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:list.rowcount }); } } else if (this.task == 'addressbook') { -- cgit v1.2.3 From c095e6329c38bf759f42b414db9082d7f31aba18 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 19 Apr 2015 09:02:04 +0200 Subject: Fix message highligh regression from last commit (#1490363) --- program/js/app.js | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'program/js/app.js') diff --git a/program/js/app.js b/program/js/app.js index c11ae7762..b4b125f3f 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -7500,34 +7500,36 @@ function rcube_webmail() this.env.qsearch = null; case 'list': if (this.task == 'mail') { - var is_multifolder = this.is_multifolder_listing(); + var is_multifolder = this.is_multifolder_listing(), + list = this.message_list, + uid = this.env.list_uid; + this.enable_command('show', 'select-all', 'select-none', this.env.messagecount > 0); this.enable_command('expunge', this.env.exists && !is_multifolder); this.enable_command('purge', this.purge_mailbox_test() && !is_multifolder); this.enable_command('import-messages', !is_multifolder); this.enable_command('expand-all', 'expand-unread', 'collapse-all', this.env.threading && this.env.messagecount && !is_multifolder); - if (this.message_list) { - var list = this.message_list, uid = this.env.list_uid; - - // highlight message row when we're back from message page - if (uid) { - if (!list.rows[uid]) - uid += '-' + this.env.mailbox; - if (list.rows[uid]) { - list.select(uid); + if (list) { + if (response.action == 'list' || response.action == 'search') { + // highlight message row when we're back from message page + if (uid) { + if (!list.rows[uid]) + uid += '-' + this.env.mailbox; + if (list.rows[uid]) { + list.select(uid); + } + delete this.env.list_uid; } - delete this.env.list_uid; - } - if (response.action == 'list' || response.action == 'search') { this.enable_command('set-listmode', this.env.threads && !is_multifolder); if (list.rowcount > 0) list.focus(); this.msglist_select(list); } - this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:list.rowcount }); + if (response.action != 'getunread') + this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:list.rowcount }); } } else if (this.task == 'addressbook') { -- cgit v1.2.3