From 007f1b443888a17b5156ef871e5548d28a3a0130 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli <thomas@roundcube.net> Date: Sun, 20 Jul 2014 08:00:58 -0400 Subject: [PATCH] Warn for unsent/unsaved message when closing compose window; remove localStorage copy if page was left intentionally but not on session errors (#1489818) --- program/js/app.js | 133 +++++++++++++++++++++++++++++++------------- 1 files changed, 94 insertions(+), 39 deletions(-) diff --git a/program/js/app.js b/program/js/app.js index a72f49e..69cbca8 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -593,6 +593,7 @@ // remove copy from local storage if compose screen is left intentionally this.remove_compose_data(this.env.compose_id); + this.compose_skip_unsavedcheck = true; } // process external commands @@ -652,6 +653,7 @@ if (win) { this.save_compose_form_local(); + this.compose_skip_unsavedcheck = true; $("input[name='_action']", form).val('compose'); form.action = this.url('mail/compose', { _id: this.env.compose_id, _extwin: 1 }); form.target = win.name; @@ -1325,7 +1327,7 @@ var url = this.get_task_url(task); if (task == 'mail') url += '&_mbox=INBOX'; - else if (task == 'logout') + else if (task == 'logout' && !this.env.server_error) this.clear_compose_data(); this.redirect(url); @@ -2064,17 +2066,35 @@ this.location_href(this.env.comm_path+url, target, true); // mark as read and change mbox unread counter - if (preview && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread && this.env.preview_pane_mark_read >= 0) { + if (preview && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread && this.env.preview_pane_mark_read > 0) { this.preview_read_timer = setTimeout(function() { - ref.set_message(id, 'unread', false); - if (ref.env.unread_counts[ref.env.mailbox]) { - ref.env.unread_counts[ref.env.mailbox] -= 1; - ref.set_unread_count(ref.env.mailbox, ref.env.unread_counts[ref.env.mailbox], ref.env.mailbox == 'INBOX'); - } - if (ref.env.preview_pane_mark_read > 0) - ref.http_post('mark', {_uid: id, _flag: 'read', _quiet: 1}); + ref.set_unread_message(id, ref.env.mailbox); + ref.http_post('mark', {_uid: id, _flag: 'read', _quiet: 1}); }, this.env.preview_pane_mark_read * 1000); } + } + }; + + // update message status and unread counter after marking a message as read + this.set_unread_message = function(id, folder) + { + var self = this; + + // find window with messages list + if (!self.message_list) + self = self.opener(); + + if (!self && window.parent) + self = parent.rcmail; + + if (!self || !self.message_list) + return; + + self.set_message(id, 'unread', false); + + if (self.env.unread_counts[folder] > 0) { + self.env.unread_counts[folder] -= 1; + self.set_unread_count(folder, self.env.unread_counts[folder], folder == 'INBOX'); } }; @@ -2151,7 +2171,7 @@ var lock = this.set_busy(true, 'checkingmail'), params = this.check_recent_params(); - this.http_request('check-recent', params, lock); + this.http_post('check-recent', params, lock); }; // list messages of a specific mailbox using filter @@ -3243,6 +3263,7 @@ form._draft.value = draft ? '1' : ''; form.action = this.add_url(form.action, '_unlock', msgid); form.action = this.add_url(form.action, '_lang', lang); + form.action = this.add_url(form.action, '_framed', 1); // register timer to notify about connection timeout this.submit_timer = setTimeout(function(){ @@ -3389,17 +3410,8 @@ $(tinyMCE.get(props.id).getBody()).css('font-family', rcmail.env.default_font); }, 500); } - else { - var thisMCE = tinyMCE.get(props.id), existingHtml; - - if (existingHtml = thisMCE.getContent()) { - if (!confirm(this.get_label('editorwarning'))) { - return false; - } - this.html2plain(existingHtml, props.id); - } + else if (this.html2plain(tinyMCE.get(props.id).getContent(), props.id)) tinyMCE.execCommand('mceRemoveControl', false, props.id); - } return true; }; @@ -3546,10 +3558,7 @@ // submit delete request if (key && confirm(this.get_label('deleteresponseconfirm'))) { this.http_post('settings/delete-response', { _key: key }, false); - return true; } - - return false; }; this.stop_spellchecking = function() @@ -3649,16 +3658,18 @@ // always remove local copy upon saving as draft this.remove_compose_data(this.env.compose_id); + this.compose_skip_unsavedcheck = false; }; this.auto_save_start = function() { - if (this.env.draft_autosave) + if (this.env.draft_autosave) { this.draft_autosave_submit = false; this.save_timer = setTimeout(function(){ ref.draft_autosave_submit = true; // set auto-saved flag (#1489789) 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) { @@ -3672,6 +3683,21 @@ ref.compose_type_activity_last = ref.compose_type_activity; } }, 5000); + + $(window).unload(function() { + // remove copy from local storage if compose screen is left after warning + if (!ref.env.server_error) + ref.remove_compose_data(ref.env.compose_id); + }); + } + + // check for unsaved changes before leaving the compose page + if (!window.onbeforeunload) { + window.onbeforeunload = function() { + if (!ref.compose_skip_unsavedcheck && ref.cmp_hash != ref.compose_field_hash()) { + return ref.get_label('notsentwarning'); + } + }; } // Unlock interface now that saving is complete @@ -4209,23 +4235,25 @@ this.sent_successfully = function(type, msg, folders) { this.display_message(msg, type); + this.compose_skip_unsavedcheck = true; if (this.env.extwin) { - var rc = this.opener(); this.lock_form(this.gui_objects.messageform); + + var rc = this.opener(); if (rc) { rc.display_message(msg, type); // refresh the folder where sent message was saved or replied message comes from if (folders && rc.env.task == 'mail' && rc.env.action == '' && $.inArray(rc.env.mailbox, folders) >= 0) { - // @TODO: try with 'checkmail' here when #1485186 is fixed. See also #1489249. - rc.command('list'); + rc.command('checkmail'); } } - setTimeout(function(){ window.close() }, 1000); + + setTimeout(function() { window.close(); }, 1000); } else { // before redirect we need to wait some time for Chrome (#1486177) - setTimeout(function(){ ref.list_mailbox(); }, 500); + setTimeout(function() { ref.list_mailbox(); }, 500); } }; @@ -4342,9 +4370,7 @@ this.ksearch_input.value = pre + insert + end; // set caret to insert pos - cpos = p+insert.length; - if (this.ksearch_input.setSelectionRange) - this.ksearch_input.setSelectionRange(cpos, cpos); + this.set_caret_pos(this.ksearch_input, p + insert.length); if (trigger) { this.triggerEvent('autocomplete_insert', { field:this.ksearch_input, insert:insert }); @@ -5603,10 +5629,8 @@ id = this.env.iid ? this.env.iid : selection[0]; // submit request with appended token - if (confirm(this.get_label('deleteidentityconfirm'))) - this.goto_url('delete-identity', { _iid: id, _token: this.env.request_token }, true); - - return true; + if (id && confirm(this.get_label('deleteidentityconfirm'))) + this.http_post('settings/delete-identity', { _iid: id }, true); }; this.update_identity_row = function(id, name, add) @@ -5650,6 +5674,23 @@ frame.location.href = this.env.blankpage; } } + + this.enable_command('delete', false); + }; + + this.remove_identity = function(id) + { + var frame, list = this.identity_list, + rid = this.html_identifier(id); + + if (list && id) { + list.remove_row(rid); + if (this.env.contentframe && (frame = this.get_frame_window(this.env.contentframe))) { + frame.location.href = this.env.blankpage; + } + } + + this.enable_command('delete', false); }; @@ -6612,8 +6653,9 @@ // fetch headers only once if (!this.gui_objects.all_headers_box.innerHTML) { - var lock = this.display_message(this.get_label('loading'), 'loading'); - this.http_post('headers', {_uid: this.env.uid}, lock); + this.http_post('headers', {_uid: this.env.uid, _mbox: this.env.mailbox}, + this.display_message(this.get_label('loading'), 'loading') + ); } }; @@ -6742,6 +6784,16 @@ this.html2plain = function(htmlText, id) { + // warn the user (if converted content is not empty) + if (!htmlText || !(htmlText.replace(/<[^>]+>| |\s/g, '')).length) { + // without setTimeout() here, textarea is filled with initial (onload) content + setTimeout(function() { $('#'+id).val(''); }, 50); + return true; + } + + if (!confirm(this.get_label('editorwarning'))) + return false; + var rcmail = this, url = '?_task=utils&_action=html2text', lock = this.set_busy(true, 'converting'); @@ -6752,6 +6804,8 @@ error: function(o, status, err) { rcmail.http_error(o, status, err, lock); }, success: function(data) { rcmail.set_busy(false, null, lock); $('#'+id).val(data); rcmail.log(data); } }); + + return true; }; this.plain2html = function(plain, id) @@ -7097,6 +7151,7 @@ // save message in local storage and do not redirect if (this.env.action == 'compose') { this.save_compose_form_local(); + this.compose_skip_unsavedcheck = true; } else if (redirect_url) { window.setTimeout(function(){ ref.redirect(redirect_url, true); }, 2000); @@ -7327,7 +7382,7 @@ this.env.lastrefresh = new Date(); // plugins should bind to 'requestrefresh' event to add own params - this.http_request('refresh', params, lock); + this.http_post('refresh', params, lock); }; // returns check-recent request parameters -- Gitblit v1.9.1