From a02c77c584906f629d382409e76f0df4d2cfaf01 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Fri, 15 Mar 2013 05:30:53 -0400 Subject: [PATCH] Add ability to toggle between view as HTML and text while viewing a message (#1486939) --- program/js/app.js | 121 +++++++++++++++++++++++++++++----------- 1 files changed, 88 insertions(+), 33 deletions(-) diff --git a/program/js/app.js b/program/js/app.js index 7c6dba8..d3c319e 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -179,7 +179,8 @@ } // enable general commands - this.enable_command('close', 'logout', 'mail', 'addressbook', 'settings', 'save-pref', 'compose', 'undo', 'about', 'switch-task', true); + this.enable_command('close', 'logout', 'mail', 'addressbook', 'settings', 'save-pref', + 'compose', 'undo', 'about', 'switch-task', 'menu-open', 'menu-save', true); if (this.env.permaurl) this.enable_command('permaurl', 'extwin', true); @@ -205,12 +206,13 @@ this.message_list.addEventListener('dragend', function(e){ p.drag_end(e); }); this.message_list.addEventListener('expandcollapse', function(e){ p.msglist_expand(e); }); this.message_list.addEventListener('column_replace', function(e){ p.msglist_set_coltypes(e); }); + this.message_list.addEventListener('listupdate', function(e){ p.triggerEvent('listupdate', e); }); document.onmouseup = function(e){ return p.doc_mouse_up(e); }; this.gui_objects.messagelist.parentNode.onmousedown = function(e){ return p.click_on_list(e); }; this.message_list.init(); - this.enable_command('toggle_status', 'toggle_flag', 'menu-open', 'menu-save', 'sort', true); + this.enable_command('toggle_status', 'toggle_flag', 'sort', true); // load messages this.command('list'); @@ -226,8 +228,8 @@ this.env.message_commands = ['show', 'reply', 'reply-all', 'reply-list', 'moveto', 'copy', 'delete', 'open', 'mark', 'edit', 'viewsource', - 'print', 'load-attachment', 'show-headers', 'hide-headers', 'download', - 'forward', 'forward-inline', 'forward-attachment']; + 'print', 'load-attachment', 'download-attachment', 'show-headers', 'hide-headers', 'download', + 'forward', 'forward-inline', 'forward-attachment', 'change-format']; if (this.env.action == 'show' || this.env.action == 'preview') { this.enable_command(this.env.message_commands, this.env.uid); @@ -594,18 +596,35 @@ case 'extwin': if (this.env.action == 'compose') { - var prevstate = this.env.compose_extwin; - $("input[name='_action']", this.gui_objects.messageform).val('compose'); - this.gui_objects.messageform.action = this.url('mail/compose', { _id: this.env.compose_id, _extwin: 1 }); - this.gui_objects.messageform.target = this.open_window('', 1100, 900); - this.gui_objects.messageform.submit(); + var form = this.gui_objects.messageform; + + $("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.submit(); } else { this.open_window(this.env.permaurl, 900, 900); } break; + case 'change-format': + url = this.env.permaurl + '&_format=' + props; + + if (this.env.action == 'preview') + url = url.replace(/_action=show/, '_action=preview') + '&_framed=1'; + if (this.env.extwin) + url += '&_extwin=1'; + + location.href = url; + break; + case 'menu-open': + if (props && props.menu == 'attachmentmenu') { + var mimetype = this.env.attachments[props.id]; + this.enable_command('open-attachment', mimetype && this.env.mimetypes && $.inArray(mimetype, this.env.mimetypes) >= 0); + } + case 'menu-save': this.triggerEvent(command, {props:props}); return false; @@ -770,7 +789,7 @@ case 'moveto': if (this.task == 'mail') this.move_messages(props); - else if (this.task == 'addressbook' && this.drag_active) + else if (this.task == 'addressbook') this.copy_contact(null, props); break; @@ -831,11 +850,14 @@ break; case 'load-attachment': - var qstring = '_mbox='+urlencode(this.env.mailbox)+'&_uid='+this.env.uid+'&_part='+props.part; + case 'open-attachment': + case 'download-attachment': + var qstring = '_mbox='+urlencode(this.env.mailbox)+'&_uid='+this.env.uid+'&_part='+props, + mimetype = this.env.attachments[props]; // open attachment in frame if it's of a supported mimetype - if (this.env.uid && props.mimetype && this.env.mimetypes && $.inArray(props.mimetype, this.env.mimetypes) >= 0) { - var attachment_win = window.open(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', 'rcubemailattachment'+this.env.uid+props.part); + 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', 'rcubemailattachment'+this.env.uid+props); if (attachment_win) { setTimeout(function(){ attachment_win.focus(); }, 10); break; @@ -878,7 +900,7 @@ case 'nextmessage': if (this.env.next_uid) - this.show_message(this.env.next_uid, false, this.env.action=='preview'); + this.show_message(this.env.next_uid, false, this.env.action == 'preview'); break; case 'lastmessage': @@ -1224,7 +1246,7 @@ if (!url) url = this.env.comm_path; - return url.replace(/_task=[a-z]+/, '_task='+task); + return url.replace(/_task=[a-z0-9_-]+/i, '_task='+task); }; this.reload = function(delay) @@ -2973,10 +2995,10 @@ input_message = $("[name='_message']").get(0), html_mode = $("input[name='_is_html']").val() == '1', ac_fields = ['cc', 'bcc', 'replyto', 'followupto'], - ac_props; + ac_props, opener_rc = this.opener(); // close compose step in opener - if (window.opener && !window.opener.closed && opener.rcmail && opener.rcmail.env.action == 'compose') { + if (opener_rc && opener_rc.env.action == 'compose') { setTimeout(function(){ opener.history.back(); }, 100); this.env.opened_extwin = true; } @@ -3655,9 +3677,10 @@ this.display_message(msg, type); if (this.env.extwin) { + var opener_rc = this.opener(); this.lock_form(this.gui_objects.messageform); - if (window.opener && !window.opener.closed && opener.rcmail) - opener.rcmail.display_message(msg, type); + if (opener_rc) + opener_rc.display_message(msg, type); setTimeout(function(){ window.close() }, 1000); } else { @@ -4224,7 +4247,7 @@ this.group_member_change('add', cid, dest, to.id); else { var lock = this.display_message(this.get_label('copyingcontact'), 'loading'), - post_data = {_cid: cid, _source: source, _to: dest, _togid: to.id, _gid: group}; + post_data = {_cid: cid, _source: this.env.source, _to: dest, _togid: to.id, _gid: group}; this.http_post('copy', post_data, lock); } @@ -4232,7 +4255,7 @@ // target is an addressbook else if (to.id != source) { var lock = this.display_message(this.get_label('copyingcontact'), 'loading'), - post_data = {_cid: cid, _source: source, _to: to.id, _gid: group}; + post_data = {_cid: cid, _source: this.env.source, _to: to.id, _gid: group}; this.http_post('copy', post_data, lock); } @@ -4438,7 +4461,10 @@ 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)); - this.name_input_li.insertAfter(li); + 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))); } this.name_input.select().focus(); @@ -5563,14 +5589,15 @@ if (!this.gui_objects.message) return; - var k, n, i, msg, m = this.messages; + var k, n, i, o, m = this.messages; // Hide message by object, don't use for 'loading'! if (typeof obj === 'object') { - $(obj)[fade?'fadeOut':'hide'](); - msg = $(obj).data('key'); - if (this.messages[msg]) - delete this.messages[msg]; + o = $(obj); + k = o.data('key'); + this.hide_message_object(o, fade); + if (m[k]) + delete m[k]; } // Hide message by id else { @@ -5580,7 +5607,7 @@ m[k].elements.splice(n, 1); // hide DOM element if last instance is removed if (!m[k].elements.length) { - m[k].obj[fade?'fadeOut':'hide'](); + this.hide_message_object(m[k].obj, fade); delete m[k]; } // set pending action label for 'loading' message @@ -5590,15 +5617,24 @@ delete m[k].labels[i]; } else { - msg = m[k].labels[i].msg; + o = m[k].labels[i].msg; + m[k].obj.html(o); } - m[k].obj.html(msg); } } } } } } + }; + + // hide message object and remove from the DOM + this.hide_message_object = function(o, fade) + { + if (fade) + o.fadeOut(600, function() {$(this).remove(); }); + else + o.hide().remove(); }; // remove all messages immediately @@ -5613,7 +5649,7 @@ for (k in m) for (n in m[k].elements) if (m[k].obj) - m[k].obj.hide(); + this.hide_message_object(m[k].obj); this.messages = {}; }; @@ -5945,9 +5981,9 @@ var base = this.env.comm_path, k, param = {}; // overwrite task name - if (query._action.match(/([a-z]+)\/([a-z0-9-_.]+)/)) { + if (query._action.match(/([a-z0-9_-]+)\/([a-z0-9-_.]+)/)) { query._action = RegExp.$2; - base = base.replace(/\_task=[a-z]+/, '_task='+RegExp.$1); + base = base.replace(/\_task=[a-z0-9_-]+/, '_task='+RegExp.$1); } // remove undefined values @@ -6224,6 +6260,14 @@ if (location_url && this.env.action != 'compose') // don't redirect on compose screen, contents might get lost (#1488926) this.redirect(location_url); + // 403 Forbidden response (CSRF prevention) - reload the page. + // In case there's a new valid session it will be used, otherwise + // login form will be presented (#1488960). + if (request.status == 403) { + (this.is_framed() ? parent : window).location.reload(); + return; + } + // re-send keep-alive requests after 30 seconds if (action == 'keep-alive') setTimeout(function(){ ref.keep_alive(); ref.start_keepalive(); }, 30000); @@ -6476,6 +6520,17 @@ /********* helper methods *********/ /********************************************************/ + // get window.opener.rcmail if available + this.opener = function() + { + // catch Error: Permission denied to access property rcmail + try { + if (window.opener && !opener.closed && opener.rcmail) + return opener.rcmail; + } + catch (e) {} + }; + // check if we're in show mode or if we have a unique selection // and return the message uid this.get_single_uid = function() -- Gitblit v1.9.1