From 99e17f6131bf0eb1762ddc13766b41fcd1942a29 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Thu, 13 Jun 2013 09:12:07 -0400 Subject: [PATCH] Fix timeout issue on drag&drop uploads (#1489170) --- program/js/app.js | 237 ++++++++++++++++++++++++++++++++++------------------------- 1 files changed, 136 insertions(+), 101 deletions(-) diff --git a/program/js/app.js b/program/js/app.js index c19ff62..0dea592 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -44,7 +44,9 @@ comm_path: './', blankpage: 'program/resources/blank.gif', recipients_separator: ',', - recipients_delimiter: ', ' + recipients_delimiter: ', ', + popup_width: 1150, + popup_width_small: 900 }; // create protected reference to myself @@ -177,11 +179,6 @@ parent.rcmail.set_busy(false, null, parent.rcmail.env.frame_lock); parent.rcmail.env.frame_lock = null; } - - // Makes that reference to document.activeElement do not throw - // "unspecified error" in IE9 (#1489008) - if (this.env.framed && bw.ie) - document.documentElement.focus(); // enable general commands this.enable_command('close', 'logout', 'mail', 'addressbook', 'settings', 'save-pref', @@ -601,15 +598,16 @@ case 'extwin': if (this.env.action == 'compose') { - var form = this.gui_objects.messageform; + var form = this.gui_objects.messageform, + win = this.open_window(''); $("input[name='_action']", form).val('compose'); form.action = this.url('mail/compose', { _id: this.env.compose_id, _extwin: 1 }); - form.target = this.open_window('', 1100, 900); + form.target = win.name; form.submit(); } else { - this.open_window(this.env.permaurl, 900, 900); + this.open_window(this.env.permaurl, true); } break; @@ -862,11 +860,8 @@ // open attachment in frame if it's of a supported mimetype if (command != 'download-attachment' && mimetype && this.env.mimetypes && $.inArray(mimetype, this.env.mimetypes) >= 0) { - var attachment_win = window.open(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', this.html_identifier('rcubemailattachment'+this.env.uid+props)); - if (attachment_win) { - setTimeout(function(){ attachment_win.focus(); }, 10); + if (this.open_window(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', true, true)) break; - } } this.goto_url('get', qstring+'&_download=1', false); @@ -941,16 +936,13 @@ url._to = props; } else { - // use contact_id passed as command parameter - var n, len, a_cids = []; + var a_cids = []; + // use contact id passed as command parameter if (props) a_cids.push(props); // get selected contacts - else if (this.contact_list) { - var selection = this.contact_list.get_selection(); - for (n=0, len=selection.length; n<len; n++) - a_cids.push(selection[n]); - } + else if (this.contact_list) + a_cids = this.contact_list.get_selection(); if (a_cids.length) this.http_post('mailto', { _cid: a_cids.join(','), _source: this.env.source }, true); @@ -1053,9 +1045,8 @@ case 'print': if (uid = this.get_single_uid()) { - ref.printwin = window.open(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : '')); + ref.printwin = this.open_window(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : ''), true, true); if (this.printwin) { - setTimeout(function(){ ref.printwin.focus(); }, 20); if (this.env.action != 'show') this.mark_message('read', uid); } @@ -1063,11 +1054,8 @@ break; case 'viewsource': - if (uid = this.get_single_uid()) { - ref.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)); - if (this.sourcewin) - setTimeout(function(){ ref.sourcewin.focus(); }, 20); - } + if (uid = this.get_single_uid()) + this.open_window(this.env.comm_path+'&_action=viewsource&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true, true); break; case 'download': @@ -1187,6 +1175,7 @@ if (typeof cmd === 'string') { this.commands[cmd] = enable; this.set_button(cmd, (enable ? 'act' : 'pas')); + this.triggerEvent('enable-command', {command: cmd, status: enable}); } // push array elements into commands array else { @@ -1514,7 +1503,7 @@ // start timer for message preview (wait for double click) if (selected && this.env.contentframe && !list.multi_selecting && !this.dummy_select) - this.preview_timer = setTimeout(function(){ ref.msglist_get_preview(); }, 200); + this.preview_timer = setTimeout(function() { ref.msglist_get_preview(); }, this.dblclick_time); else if (this.env.contentframe) this.show_contentframe(false); }; @@ -1530,12 +1519,13 @@ var win = this.get_frame_window(this.env.contentframe); - if (win && win.location.href.indexOf(this.env.blankpage)>=0) { + if (win && win.location.href.indexOf(this.env.blankpage) >= 0) { if (this.preview_timer) clearTimeout(this.preview_timer); if (this.preview_read_timer) clearTimeout(this.preview_read_timer); - this.preview_timer = setTimeout(function(){ ref.msglist_get_preview(); }, 200); + + this.preview_timer = setTimeout(function() { ref.msglist_get_preview(); }, this.dblclick_time); } }; @@ -1543,11 +1533,11 @@ { if (this.preview_timer) clearTimeout(this.preview_timer); - if (this.preview_read_timer) clearTimeout(this.preview_read_timer); var uid = list.get_single_selection(); + if (uid && this.env.mailbox == this.env.drafts_mailbox) this.open_compose_step({ _draft_uid: uid, _mbox: this.env.mailbox }); else if (uid) @@ -1587,7 +1577,7 @@ this.msglist_set_coltypes = function(list) { - var i, found, name, cols = list.list.tHead.rows[0].cells; + var i, found, name, cols = list.thead.rows[0].cells; this.env.coltypes = []; @@ -1635,15 +1625,28 @@ return 0; }; - this.open_window = function(url, width, height) + // open popup window + this.open_window = function(url, small, toolbar) { - var w = Math.min(width, screen.width - 10), - h = Math.min(height, screen.height - 100), - l = (screen.width - w) / 2 + (screen.left || 0), - t = Math.max(0, (screen.height - h) / 2 + (screen.top || 0) - 20), - wname = 'rcmextwin' + new Date().getTime(), - extwin = window.open(url + (url.match(/\?/) ? '&' : '?') + '_extwin=1', wname, - 'width='+w+',height='+h+',top='+t+',left='+l+',resizable=yes,toolbar=no,status=no,location=no'); + var wname = 'rcmextwin' + new Date().getTime(); + + url += (url.match(/\?/) ? '&' : '?') + '_extwin=1'; + + if (this.env.standard_windows) + extwin = window.open(url, wname); + else { + var win = this.is_framed() ? parent.window : window, + page = $(win), + page_width = page.width(), + page_height = bw.mz ? $('body', win).height() : page.height(), + w = Math.min(small ? this.env.popup_width_small : this.env.popup_width, page_width), + h = page_height, // always use same height + l = (win.screenLeft || win.screenX) + 20, + t = (win.screenTop || win.screenY) + 20, + extwin = window.open(url, wname, + 'width='+w+',height='+h+',top='+t+',left='+l+',resizable=yes,location=no,scrollbars=yes' + +(toolbar ? ',toolbar=yes,menubar=yes,status=yes' : ',toolbar=no,menubar=no,status=no')); + } // write loading... message to empty windows if (!url && extwin.document) { @@ -1652,10 +1655,8 @@ // focus window, delayed to bring to front window.setTimeout(function() { extwin.focus(); }, 10); - // position window with setTimeout for Chrome (#1488931) - window.setTimeout(function() { extwin.moveTo(l,t); }, bw.chrome ? 100 : 10); - return wname; + return extwin; }; @@ -1739,10 +1740,7 @@ + (flags.flagged ? ' flagged' : '') + (flags.unread_children && flags.seen && !this.env.autoexpand_threads ? ' unroot' : '') + (message.selected ? ' selected' : ''), - // for performance use DOM instead of jQuery here - row = document.createElement('tr'); - - row.id = 'rcmrow'+uid; + row = { cols:[], style:{}, id:'rcmrow'+uid }; // message status icons css_class = 'msgicon'; @@ -1806,8 +1804,7 @@ // add each submitted col for (n in this.env.coltypes) { c = this.env.coltypes[n]; - col = document.createElement('td'); - col.className = String(c).toLowerCase(); + col = { className: String(c).toLowerCase() }; if (c == 'flag') { css_class = (flags.flagged ? 'flagged' : 'unflagged'); @@ -1852,8 +1849,7 @@ html = cols[c]; col.innerHTML = html; - - row.appendChild(col); + row.cols.push(col); } list.insert_row(row, attop); @@ -1954,7 +1950,7 @@ } else { if (!preview && this.env.message_extwin && !this.env.extwin) - this.open_window(this.env.comm_path+url, 1000, 1200); + this.open_window(this.env.comm_path+url, true); else this.location_href(this.env.comm_path+url, target, true); @@ -2216,7 +2212,7 @@ if (root) row = rows[root] ? rows[root].obj : null; else - row = this.message_list.list.tBodies[0].firstChild; + row = this.message_list.tbody.firstChild; while (row) { if (row.nodeType == 1 && (r = rows[row.uid])) { @@ -2392,7 +2388,7 @@ this.delete_excessive_thread_rows = function() { var rows = this.message_list.rows, - tbody = this.message_list.list.tBodies[0], + tbody = this.message_list.tbody, row = tbody.firstChild, cnt = this.env.pagesize + 1; @@ -2980,11 +2976,12 @@ // open new compose window if (this.env.compose_extwin && !this.env.extwin) { - this.open_window(url, 1150, 900); + this.open_window(url); } else { this.redirect(url); - window.resizeTo(Math.max(1150, $(window).width()), Math.max(900, $(window).height())); + if (this.env.extwin) + window.resizeTo(Math.max(this.env.popup_width, $(window).width()), $(window).height() + 24); } }; @@ -3092,7 +3089,7 @@ this.compose_add_recipient = function(field) { - var recipients = [], input = $('#_'+field); + var recipients = [], input = $('#_'+field), delim = this.env.recipients_delimiter; if (this.contact_list && this.contact_list.selection.length) { for (var id, n=0; n < this.contact_list.selection.length; n++) { @@ -3111,8 +3108,10 @@ } if (recipients.length && input.length) { - var oldval = input.val(); - input.val((oldval ? oldval + this.env.recipients_delimiter : '') + recipients.join(this.env.recipients_delimiter)); + 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 + ' '); this.triggerEvent('add-recipient', { field:field, recipients:recipients }); } }; @@ -3355,12 +3354,45 @@ if (!show_sig) show_sig = this.env.show_sig; - var cursor_pos, p = -1, + var i, rx, cursor_pos, p = -1, id = obj.options[obj.selectedIndex].value, input_message = $("[name='_message']"), message = input_message.val(), is_html = ($("input[name='_is_html']").val() == '1'), - sig = this.env.identity; + sig = this.env.identity, + delim = this.env.recipients_delimiter, + headers = ['replyto', 'bcc']; + + // update reply-to/bcc fields with addresses defined in identities + for (i in headers) { + var key = headers[i], + old_val = sig && this.env.identities[sig] ? this.env.identities[sig][key] : '', + new_val = id && this.env.identities[id] ? this.env.identities[id][key] : '', + input = $('[name="_'+key+'"]'), input_val = input.val(); + + // remove old address(es) + if (old_val && input_val) { + rx = new RegExp('\\s*' + RegExp.escape(old_val) + '\\s*'); + input_val = input_val.replace(rx, ''); + } + + // cleanup + rx = new RegExp(RegExp.escape(delim) + '\\s*' + RegExp(delim), 'g'); + input_val = input_val.replace(rx, delim) + rx = new RegExp('^\\s*' + RegExp.escape(delim) + '\\s*$'); + input_val = input_val.replace(rx, '') + + // add new address(es) + if (new_val) { + rx = new RegExp(RegExp.escape(delim) + '\\s*$'); + if (input_val && !rx.test(input_val)) + input_val += delim + ' '; + input_val += new_val + delim + ' '; + } + + if (old_val || new_val) + input.val(input_val).change(); + } // enable manual signature insert if (this.env.signatures && this.env.signatures[id]) { @@ -4073,6 +4105,7 @@ var n, id, sid, ref = this, writable = false, source = this.env.source ? this.env.address_sources[this.env.source] : null; + // we don't have dblclick handler here, so use 200 instead of this.dblclick_time if (id = list.get_single_selection()) this.preview_timer = setTimeout(function(){ ref.load_contact(id, 'show'); }, 200); else if (this.env.contentframe) @@ -4335,21 +4368,7 @@ newcid = newcid+'-'+source; } - if (list.rows[cid] && (row = list.rows[cid].obj)) { - for (c=0; c<cols_arr.length; c++) - if (row.cells[c]) - $(row.cells[c]).html(cols_arr[c]); - - // cid change - if (newcid) { - newcid = this.html_identifier(newcid); - row.id = 'rcmrow' + newcid; - list.remove_row(cid); - list.init_row(row); - list.selection[0] = newcid; - row.style.display = ''; - } - } + list.update_row(cid, cols_arr, newcid, true); }; // add row to contacts list @@ -4359,7 +4378,7 @@ return false; var c, col, list = this.contact_list, - row = document.createElement('tr'); + row = { cols:[] }; row.id = 'rcmrow'+this.html_identifier(cid); row.className = 'contact ' + (classes || ''); @@ -4369,10 +4388,10 @@ // add each submitted col for (c in cols) { - col = document.createElement('td'); + col = {}; col.className = String(c).toLowerCase(); col.innerHTML = cols[c]; - row.appendChild(col); + row.cols.push(col); } list.insert_row(row); @@ -4478,11 +4497,22 @@ this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); }); this.name_input_li = $('<li>').addClass(type).append(this.name_input); - var li = type == 'contactsearch' ? $('li:last', this.gui_objects.folderlist) : $('ul.groups li:last', this.get_folder_li(this.env.source,'',true)); + var ul, li; + + // find list (UL) element + if (type == 'contactsearch') + ul = this.gui_objects.folderlist; + else + ul = $('ul.groups', this.get_folder_li(this.env.source,'',true)); + + // append to the list + li = $('li:last', ul); if (li.length) this.name_input_li.insertAfter(li); - else - this.name_input_li.appendTo(type == 'contactsearch' ? this.gui_objects.folderlist : $('ul.groups', this.get_folder_li(this.env.source,'',true))); + else { + this.name_input_li.appendTo(ul); + ul.show(); // make sure the list is visible + } } this.name_input.select().focus(); @@ -4539,11 +4569,13 @@ this.reset_add_input = function() { if (this.name_input) { + var li = this.name_input.parent(); if (this.env.group_renaming) { - var li = this.name_input.parent(); li.children().last().show(); this.env.group_renaming = false; } + else if ($('li', li.parent()).length == 1) + li.parent().hide(); this.name_input.remove(); @@ -4971,17 +5003,15 @@ this.update_identity_row = function(id, name, add) { - var row, col, list = this.identity_list, + var list = this.identity_list, rid = this.html_identifier(id); - if (list.rows[rid] && (row = list.rows[rid].obj)) { - $(row.cells[0]).html(name); - } - else if (add) { - row = $('<tr>').attr('id', 'rcmrow'+rid).get(0); - col = $('<td>').addClass('mail').html(name).appendTo(row); - list.insert_row(row); + if (add) { + list.insert_row({ id:'rcmrow'+rid, cols:[ { className:'mail', innerHTML:name } ] }); list.select(rid); + } + else { + list.update_row(rid, [ name ]); } }; @@ -5673,11 +5703,11 @@ }; // open a jquery UI dialog with the given content - this.show_popup_dialog = function(html, title) + this.show_popup_dialog = function(html, title, buttons) { // forward call to parent window if (this.is_framed()) { - parent.rcmail.show_popup_dialog(html, title); + parent.rcmail.show_popup_dialog(html, title, buttons); return; } @@ -5685,17 +5715,21 @@ .html(html) .dialog({ title: title, + buttons: buttons, modal: true, resizable: true, - width: 580, + width: 500, close: function(event, ui) { $(this).remove() } }); - // resize and center popup - var win = $(window), w = win.width(), h = win.height(), - width = popup.width(), height = popup.height(); - popup.dialog('option', { height: Math.min(h-40, height+50), width: Math.min(w-20, width+50) }) - .dialog('option', 'position', ['center', 'center']); // only works in a separate call (!?) + // resize and center popup + var win = $(window), w = win.width(), h = win.height(), + width = popup.width(), height = popup.height(); + + popup.dialog('option', { + height: Math.min(h - 40, height + 75 + (buttons ? 50 : 0)), + width: Math.min(w - 20, width + 20) + }); }; // enable/disable buttons for page shifting @@ -5757,7 +5791,7 @@ this.set_message_coltypes = function(coltypes, repl, smart_col) { var list = this.message_list, - thead = list ? list.list.tHead : null, + thead = list ? list.thead : null, cell, col, n, len, th, tr; this.env.coltypes = coltypes; @@ -5770,7 +5804,7 @@ for (c=0, len=repl.length; c < len; c++) { cell = document.createElement('td'); - cell.innerHTML = repl[c].html; + cell.innerHTML = repl[c].html || ''; if (repl[c].id) cell.id = repl[c].id; if (repl[c].className) cell.className = repl[c].className; tr.appendChild(cell); @@ -6399,6 +6433,7 @@ url: ref.url(ref.env.filedrop.action||'upload', { _id:ref.env.compose_id||ref.env.cid||'', _uploadid:ts, _remote:1 }), contentType: formdata ? false : 'multipart/form-data; boundary=' + boundary, processData: false, + timeout: 0, // disable default timeout set in ajaxSetup() data: formdata || multipart, headers: {'X-Roundcube-Request': ref.env.request_token}, beforeSend: function(xhr, s) { if (!formdata && xhr.sendAsBinary) xhr.send = xhr.sendAsBinary; }, -- Gitblit v1.9.1