From e48f8945b32ab5b67f1cdeb53a37d3d196e31e4d Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Fri, 20 May 2016 05:19:01 -0400 Subject: [PATCH] Fix bug where message list columns could be in wrong order after column drag-n-drop and list sorting --- program/js/app.js | 86 +++++++++++++++++++++++++++---------------- 1 files changed, 54 insertions(+), 32 deletions(-) diff --git a/program/js/app.js b/program/js/app.js index 53d678c..b5be135 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -156,8 +156,8 @@ var n; this.task = this.env.task; - // check browser - if (this.env.server_error != 409 && (!bw.dom || !bw.xmlhttp_test() || (bw.mz && bw.vendver < 1.9) || (bw.ie && bw.vendver < 7))) { + // check browser capabilities (never use version checks here) + if (this.env.server_error != 409 && (!bw.dom || !bw.xmlhttp_test())) { this.goto_url('error', '_code=0x199'); return; } @@ -653,7 +653,9 @@ } // 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.task == 'mail' && this.env.action == 'compose' && !this.env.server_error && command != 'save-pref' + && $.inArray(command, this.env.compose_commands) < 0 + ) { if (!this.env.is_sent && this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning'))) return false; @@ -997,7 +999,7 @@ break; } - this.goto_url('get', qstring+'&_download=1', false); + this.goto_url('get', qstring+'&_download=1', false, true); break; case 'select-all': @@ -1203,10 +1205,10 @@ case 'download': if (this.env.action == 'get') { - location.href = location.href.replace(/_frame=/, '_download='); + location.href = this.secure_url(location.href.replace(/_frame=/, '_download=')); } else if (uid = this.get_single_uid()) { - this.goto_url('viewsource', this.params_from_uid(uid, {_save: 1})); + this.goto_url('viewsource', this.params_from_uid(uid, {_save: 1}), false, true); } break; @@ -1294,13 +1296,13 @@ case 'export': if (this.contact_list.rowcount > 0) { - this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _search: this.env.search_request }); + this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _search: this.env.search_request }, false, true); } break; case 'export-selected': if (this.contact_list.rowcount > 0) { - this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _cid: this.contact_list.get_selection().join(',') }); + this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _cid: this.contact_list.get_selection().join(',') }, false, true); } break; @@ -1415,7 +1417,7 @@ if (task == 'mail') url += '&_mbox=INBOX'; else if (task == 'logout' && !this.env.server_error) { - url += '&_token=' + this.env.request_token; + url = this.secure_url(url); this.clear_compose_data(); } @@ -1463,6 +1465,12 @@ return url + '?' + name + '=' + value; }; + + // append CSRF protection token to the given url + this.secure_url = function(url) + { + return this.add_url(url, '_token', this.env.request_token); + }, this.is_framed = function() { @@ -2486,22 +2494,23 @@ // removes messages that doesn't exists from list selection array this.update_selection = function() { - var selected = this.message_list.selection, - rows = this.message_list.rows, + var list = this.message_list, + selected = list.selection, + rows = list.rows, i, selection = []; for (i in selected) if (rows[selected[i]]) selection.push(selected[i]); - this.message_list.selection = selection; + list.selection = selection; // reset preview frame, if currently previewed message is not selected (has been removed) try { var win = this.get_frame_window(this.env.contentframe), id = win.rcmail.env.uid; - if (id && $.inArray(id, selection) < 0) + if (id && !list.in_selection(id)) this.show_contentframe(false); } catch (e) {}; @@ -3593,7 +3602,7 @@ var oldval = input.val(), rx = new RegExp(RegExp.escape(delim) + '\\s*$'); if (oldval && !rx.test(oldval)) oldval += delim + ' '; - input.val(oldval + recipients.join(delim + ' ') + delim + ' '); + input.val(oldval + recipients.join(delim + ' ') + delim + ' ').change(); this.triggerEvent('add-recipient', { field:field, recipients:recipients }); } @@ -7061,7 +7070,7 @@ if (show) { // truncate stack down to the one containing the ref link for (var i = this.menu_stack.length - 1; stack && i >= 0; i--) { - if (!$(ref).parents('#'+this.menu_stack[i]).length) + if (!$(ref).parents('#'+this.menu_stack[i]).length && $(event.target).parent().attr('role') != 'menuitem') this.hide_menu(this.menu_stack[i], event); } if (stack && this.menu_stack.length) { @@ -7279,9 +7288,11 @@ } }; - this.goto_url = function(action, query, lock) + this.goto_url = function(action, query, lock, secure) { - this.redirect(this.url(action, query), lock); + var url = this.url(action, query) + if (secure) url = this.secure_url(url); + this.redirect(url, lock); }; this.location_href = function(url, target, frame) @@ -7526,7 +7537,10 @@ this.enable_command('set-listmode', this.env.threads && !is_multifolder); if (list.rowcount > 0 && !$(document.activeElement).is('input,textarea')) list.focus(); - this.msglist_select(list); + + // trigger 'select' so all dependent actions update its state + // e.g. plugins use this event to activate buttons (#1490647) + list.triggerEvent('select'); } if (response.action != 'getunread') @@ -7793,7 +7807,7 @@ // html5 file-drop API this.document_drag_hover = function(e, over) { - e.preventDefault(); + // don't e.preventDefault() here to not block text dragging on the page (#1490619) $(this.gui_objects.filedrop)[(over?'addClass':'removeClass')]('active'); }; @@ -7826,7 +7840,8 @@ var submit_data = function() { var multiple = files.length > 1, ts = new Date().getTime(), - content = '<span>' + (multiple ? ref.get_label('uploadingmany') : files[0].name) + '</span>'; + // jQuery way to escape filename (#1490530) + content = $('<span>').text(multiple ? ref.get_label('uploadingmany') : files[0].name).html(); // add to attachments list if (!ref.add2attachment_list(ts, { name:'', html:content, classname:'uploading', complete:false })) @@ -8151,14 +8166,10 @@ if (!this.env.browser_capabilities) this.env.browser_capabilities = {}; - if (this.env.browser_capabilities.pdf === undefined) - this.env.browser_capabilities.pdf = this.pdf_support_check(); - - if (this.env.browser_capabilities.flash === undefined) - this.env.browser_capabilities.flash = this.flash_support_check(); - - if (this.env.browser_capabilities.tif === undefined) - this.tif_support_check(); + $.each(['pdf', 'flash', 'tif'], function() { + if (ref.env.browser_capabilities[this] === undefined) + ref.env.browser_capabilities[this] = ref[this + '_support_check'](); + }); }; // Returns browser capabilities string @@ -8177,11 +8188,14 @@ this.tif_support_check = function() { - var img = new Image(); + window.setTimeout(function() { + var img = new Image(); + img.onload = function() { ref.env.browser_capabilities.tif = 1; }; + img.onerror = function() { ref.env.browser_capabilities.tif = 0; }; + img.src = ref.assets_path('program/resources/blank.tif'); + }, 10); - img.onload = function() { ref.env.browser_capabilities.tif = 1; }; - img.onerror = function() { ref.env.browser_capabilities.tif = 0; }; - img.src = this.assets_path('program/resources/blank.tif'); + return 0; }; this.pdf_support_check = function() @@ -8217,6 +8231,14 @@ return 1; } + window.setTimeout(function() { + $('<object>').css({position: 'absolute', left: '-10000px'}) + .attr({data: ref.assets_path('program/resources/dummy.pdf'), width: 1, height: 1, type: 'application/pdf'}) + .load(function() { ref.env.browser_capabilities.pdf = 1; }) + .error(function() { ref.env.browser_capabilities.pdf = 0; }) + .appendTo($('body')); + }, 10); + return 0; }; -- Gitblit v1.9.1