| | |
| | | this.messages = {}; |
| | | this.group2expand = {}; |
| | | this.http_request_jobs = {}; |
| | | this.menu_stack = new Array(); |
| | | this.menu_stack = []; |
| | | |
| | | // webmail client settings |
| | | this.dblclick_time = 500; |
| | | this.message_time = 5000; |
| | | this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi'); |
| | | this.identifier_expr = /[^0-9a-z_-]/gi; |
| | | |
| | | // environment defaults |
| | | this.env = { |
| | |
| | | }); |
| | | |
| | | // avoid textarea loosing focus when hitting the save-response button/link |
| | | for (var i=0; this.buttons['save-response'] && i < this.buttons['save-response'].length; i++) { |
| | | $('#'+this.buttons['save-response'][i].id).mousedown(function(e){ return rcube_event.cancel(e); }) |
| | | } |
| | | $.each(this.buttons['save-response'] || [], function (i, v) { |
| | | $('#' + v.id).mousedown(function(e){ return rcube_event.cancel(e); }) |
| | | }); |
| | | } |
| | | |
| | | // init message compose form |
| | |
| | | this.contact_list |
| | | .addEventListener('initrow', function(o) { ref.triggerEvent('insertrow', { cid:o.uid, row:o }); }) |
| | | .addEventListener('select', function(o) { ref.compose_recipient_select(o); }) |
| | | .addEventListener('dblclick', function(o) { ref.compose_add_recipient('to'); }) |
| | | .addEventListener('dblclick', function(o) { ref.compose_add_recipient(); }) |
| | | .addEventListener('keypress', function(o) { |
| | | if (o.key_pressed == o.ENTER_KEY) { |
| | | if (!ref.compose_add_recipient('to')) { |
| | | if (!ref.compose_add_recipient()) { |
| | | // execute link action on <enter> if not a recipient entry |
| | | if (o.last_selected && String(o.last_selected).charAt(0) == 'G') { |
| | | $(o.rows[o.last_selected].obj).find('a').first().click(); |
| | |
| | | } |
| | | }) |
| | | .init(); |
| | | |
| | | // remember last focused address field |
| | | $('#_to,#_cc,#_bcc').focus(function() { ref.env.focused_field = this; }); |
| | | } |
| | | |
| | | if (this.gui_objects.addressbookslist) { |
| | |
| | | .addEventListener('dragend', function(e) { ref.drag_end(e); }) |
| | | .init(); |
| | | |
| | | if (this.env.cid) |
| | | this.contact_list.highlight_row(this.env.cid); |
| | | |
| | | this.gui_objects.contactslist.parentNode.onmousedown = function(e){ return ref.click_on_list(e); }; |
| | | |
| | | $(this.gui_objects.qsearchbox).focusin(function() { ref.contact_list.blur(); }); |
| | | |
| | | this.update_group_commands(); |
| | | this.command('list'); |
| | | } |
| | | |
| | | if (this.gui_objects.savedsearchlist) { |
| | | this.savedsearchlist = new rcube_treelist_widget(this.gui_objects.savedsearchlist, { |
| | | id_prefix: 'rcmli', |
| | | id_encode: this.html_identifier_encode, |
| | | id_decode: this.html_identifier_decode |
| | | }); |
| | | |
| | | this.savedsearchlist.addEventListener('select', function(node) { |
| | | ref.triggerEvent('selectfolder', { folder:node.id, prefix:'rcmli' }); }); |
| | | } |
| | | |
| | | this.set_page_buttons(); |
| | |
| | | }) |
| | | .init() |
| | | .focus(); |
| | | |
| | | if (this.env.iid) |
| | | this.identity_list.highlight_row(this.env.iid); |
| | | } |
| | | else if (this.gui_objects.sectionslist) { |
| | | this.sections_list = new rcube_list_widget(this.gui_objects.sectionslist, {multiselect:false, draggable:false, keyboard:true}); |
| | |
| | | // init treelist widget |
| | | if (this.gui_objects.folderlist && window.rcube_treelist_widget) { |
| | | this.treelist = new rcube_treelist_widget(this.gui_objects.folderlist, { |
| | | selectable: true, |
| | | id_prefix: 'rcmli', |
| | | id_encode: this.html_identifier_encode, |
| | | id_decode: this.html_identifier_decode, |
| | |
| | | { |
| | | var ret, uid, cid, url, flag, aborted = false; |
| | | |
| | | if (obj && obj.blur && !(event || rcube_event.is_keyboard(event))) |
| | | if (obj && obj.blur && !(event && rcube_event.is_keyboard(event))) |
| | | obj.blur(); |
| | | |
| | | // do nothing if interface is locked by other command (with exception for searching reset) |
| | |
| | | this.command_enabled = function(cmd) |
| | | { |
| | | return this.commands[cmd]; |
| | | } |
| | | }; |
| | | |
| | | // lock/unlock interface |
| | | this.set_busy = function(a, message, id) |
| | |
| | | // switch to another application task |
| | | this.switch_task = function(task) |
| | | { |
| | | if (this.task===task && task!='mail') |
| | | if (this.task === task && task != 'mail') |
| | | return; |
| | | |
| | | var url = this.get_task_url(task); |
| | | |
| | | if (task == 'mail') |
| | | url += '&_mbox=INBOX'; |
| | | else if (task == 'logout') |
| | |
| | | |
| | | this.save_pref = function(prop) |
| | | { |
| | | var request = {'_name': prop.name, '_value': prop.value}; |
| | | var request = {_name: prop.name, _value: prop.value}; |
| | | |
| | | if (prop.session) |
| | | request['_session'] = prop.session; |
| | | request._session = prop.session; |
| | | if (prop.env) |
| | | this.env[prop.env] = prop.value; |
| | | |
| | |
| | | |
| | | // select the folder if one of its childs is currently selected |
| | | // don't select if it's virtual (#1488346) |
| | | if (this.env.mailbox && this.env.mailbox.startsWith(name + this.env.delimiter) && !node.virtual) |
| | | if (!node.virtual && this.env.mailbox && this.env.mailbox.startsWith(name + this.env.delimiter)) |
| | | this.command('list', name); |
| | | } |
| | | else { |
| | |
| | | } |
| | | |
| | | // reset popup menus; delayed to have updated menu_stack data |
| | | window.setTimeout(function(e){ |
| | | setTimeout(function(e){ |
| | | var obj, skip, config, id, i, parents = $(target).parents(); |
| | | for (i = ref.menu_stack.length - 1; i >= 0; i--) { |
| | | id = ref.menu_stack[i]; |
| | |
| | | var target = e.target || {}, |
| | | keyCode = rcube_event.get_keycode(e); |
| | | |
| | | // save global reference for keyboard detection on click events in IE |
| | | rcube_event._last_keyboard_event = e; |
| | | |
| | | if (e.keyCode != 27 && (!this.menu_keyboard_active || target.nodeName == 'TEXTAREA' || target.nodeName == 'SELECT')) { |
| | | return true; |
| | | } |
| | |
| | | case 40: |
| | | case 63232: // "up", in safari keypress |
| | | case 63233: // "down", in safari keypress |
| | | focus_menu_item(mod = keyCode == 38 || keyCode == 63232 ? -1 : 1); |
| | | break; |
| | | focus_menu_item(keyCode == 38 || keyCode == 63232 ? -1 : 1); |
| | | return rcube_event.cancel(e); |
| | | |
| | | case 9: // tab |
| | | if (this.focused_menu) { |
| | |
| | | url._framed = 1; |
| | | } |
| | | |
| | | if (this.env.uid) |
| | | url._uid = this.env.uid; |
| | | |
| | | // load message list to target frame/window |
| | | if (mbox) { |
| | | this.set_busy(true, 'loading'); |
| | |
| | | selection.push(selected[i]); |
| | | |
| | | this.message_list.selection = selection; |
| | | } |
| | | }; |
| | | |
| | | // expand all threads with unread children |
| | | this.expand_unread = function() |
| | |
| | | this.message_list.expand_all(r); |
| | | this.set_unread_children(r.uid); |
| | | } |
| | | |
| | | new_row = new_row.nextSibling; |
| | | } |
| | | |
| | | return false; |
| | | }; |
| | | |
| | |
| | | } |
| | | |
| | | // update unread_children for roots |
| | | for (var i=0; i<roots.length; i++) |
| | | this.set_unread_children(roots[i].uid); |
| | | for (r=0; r<roots.length; r++) |
| | | this.set_unread_children(roots[r].uid); |
| | | |
| | | return count; |
| | | }; |
| | |
| | | |
| | | this.compose_add_recipient = function(field) |
| | | { |
| | | // find last focused field name |
| | | if (!field) { |
| | | field = $(this.env.focused_field).filter(':visible'); |
| | | field = field.length ? field.attr('id').replace('_', '') : 'to'; |
| | | } |
| | | |
| | | var recipients = [], input = $('#_'+field), delim = this.env.recipients_delimiter; |
| | | |
| | | if (this.contact_list && this.contact_list.selection.length) { |
| | |
| | | myprompt = $('<div class="prompt">').html('<div class="message">' + this.get_label('nosubjectwarning') + '</div>') |
| | | .appendTo(document.body), |
| | | prompt_value = $('<input>').attr({type: 'text', size: 30}).val(this.get_label('nosubject')) |
| | | .appendTo(myprompt); |
| | | .appendTo(myprompt), |
| | | save_func = function() { |
| | | input_subject.val(prompt_value.val()); |
| | | myprompt.dialog('close'); |
| | | ref.command(cmd, { nocheck:true }); // repeat command which triggered this |
| | | }; |
| | | |
| | | buttons[this.get_label('cancel')] = function(){ |
| | | buttons[this.get_label('sendmessage')] = function() { |
| | | save_func($(this)); |
| | | }; |
| | | buttons[this.get_label('cancel')] = function() { |
| | | input_subject.focus(); |
| | | $(this).dialog('close'); |
| | | }; |
| | | buttons[this.get_label('sendmessage')] = function(){ |
| | | input_subject.val(prompt_value.val()); |
| | | $(this).dialog('close'); |
| | | ref.command(cmd, { nocheck:true }); // repeat command which triggered this |
| | | }; |
| | | |
| | | myprompt.dialog({ |
| | | modal: true, |
| | | resizable: false, |
| | | buttons: buttons, |
| | | close: function(event, ui) { $(this).remove() } |
| | | close: function(event, ui) { $(this).remove(); } |
| | | }); |
| | | |
| | | prompt_value.select(); |
| | | prompt_value.select().keydown(function(e) { |
| | | if (e.which == 13) save_func(); |
| | | }); |
| | | |
| | | return false; |
| | | } |
| | | |
| | |
| | | if (!result && e) { |
| | | // fix selector value if operation failed |
| | | $(e.target).filter('select').val(props.html ? 'plain' : 'html'); |
| | | } |
| | | |
| | | if (result) { |
| | | // update internal format flag |
| | | $("input[name='_is_html']").val(props.html ? 1 : 0); |
| | | } |
| | | |
| | | return result; |
| | |
| | | $(this).dialog('close'); |
| | | }; |
| | | |
| | | this.show_popup_dialog(html, this.gettext('savenewresponse'), buttons); |
| | | this.show_popup_dialog(html, this.gettext('newresponse'), buttons); |
| | | |
| | | $('#ffresponsetext').val(text); |
| | | $('#ffresponsename').select(); |
| | |
| | | { |
| | | var active = this.editor.spellcheck_state(); |
| | | |
| | | if (this.buttons.spellcheck) |
| | | $('#'+this.buttons.spellcheck[0].id)[active ? 'addClass' : 'removeClass']('selected'); |
| | | $.each(this.buttons.spellcheck || [], function(i, v) { |
| | | $('#' + v.id)[active ? 'addClass' : 'removeClass']('selected'); |
| | | }); |
| | | |
| | | return active; |
| | | }; |
| | |
| | | } |
| | | this.local_storage_remove_item('compose.index'); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | |
| | | this.change_identity = function(obj, show_sig) |
| | |
| | | if (upload_id) |
| | | this.triggerEvent('fileuploaded', {name: name, attachment: att, id: upload_id}); |
| | | |
| | | if (!this.env.attachments) |
| | | this.env.attachments = {}; |
| | | |
| | | if (upload_id && this.env.attachments[upload_id]) |
| | | delete this.env.attachments[upload_id]; |
| | | |
| | | this.env.attachments[name] = att; |
| | | |
| | | if (!this.gui_objects.attachmentlist) |
| | | return false; |
| | | |
| | |
| | | |
| | | if (!att.complete && att.frame) |
| | | att.html = '<a title="'+this.get_label('cancel')+'" onclick="return rcmail.cancel_attachment_upload(\''+name+'\', \''+att.frame+'\');" href="#cancelupload" class="cancelupload">' |
| | | + (this.env.cancelicon ? '<img src="'+this.env.cancelicon+'" alt="" />' : this.get_label('cancel')) + '</a>' + att.html; |
| | | + (this.env.cancelicon ? '<img src="'+this.env.cancelicon+'" alt="'+this.get_label('cancel')+'" />' : this.get_label('cancel')) + '</a>' + att.html; |
| | | |
| | | var indicator, li = $('<li>'); |
| | | |
| | |
| | | li.appendTo(this.gui_objects.attachmentlist); |
| | | } |
| | | |
| | | if (upload_id && this.env.attachments[upload_id]) |
| | | delete this.env.attachments[upload_id]; |
| | | |
| | | this.env.attachments[name] = att; |
| | | // set tabindex attribute |
| | | var tabindex = $(this.gui_objects.attachmentlist).attr('data-tabindex') || '0'; |
| | | li.find('a').attr('tabindex', tabindex); |
| | | |
| | | return true; |
| | | }; |
| | |
| | | |
| | | this.upload_progress_update = function(param) |
| | | { |
| | | var elem = $('#'+param.name + '> span'); |
| | | var elem = $('#'+param.name + ' > span'); |
| | | |
| | | if (!elem.length || !param.text) |
| | | return; |
| | |
| | | this.display_message(msg, type); |
| | | |
| | | 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); |
| | | } |
| | | }; |
| | | |
| | |
| | | |
| | | // register (delegate) event handlers |
| | | ul.on('mouseover', 'li', function(e){ ref.ksearch_select(e.target); }) |
| | | .on('onmouseup', 'li', function(e){ ref.ksearch_click(e.target); }) |
| | | .on('mouseup', 'li', function(e){ ref.ksearch_click(e.target); }) |
| | | } |
| | | |
| | | ul = this.ksearch_pane.__ul; |
| | |
| | | $(this.gui_objects.addresslist_title).html(this.get_label('contacts')); |
| | | } |
| | | |
| | | this.select_folder(folder, '', true); |
| | | if (!this.env.search_id) |
| | | this.select_folder(folder, '', true); |
| | | |
| | | // load contacts remotely |
| | | if (this.gui_objects.contactslist) { |
| | |
| | | { |
| | | var selection = this.contact_list ? this.contact_list.get_selection() : []; |
| | | |
| | | // exit if no mailbox specified or if selection is empty |
| | | // exit if no contact specified or if selection is empty |
| | | if (!selection.length && !this.env.cid) |
| | | return; |
| | | |
| | |
| | | |
| | | // find list (UL) element |
| | | if (type == 'contactsearch') |
| | | ul = this.gui_objects.folderlist; |
| | | ul = this.gui_objects.savedsearchlist; |
| | | else |
| | | ul = $('ul.groups', this.get_folder_li(this.env.source,'',true)); |
| | | |
| | |
| | | .html(prop.name); |
| | | |
| | | this.env.contactfolders[key] = this.env.contactgroups[key] = prop; |
| | | this.treelist.insert({ id:key, html:link, classes:['contactgroup'] }, prop.source, true); |
| | | this.treelist.insert({ id:key, html:link, classes:['contactgroup'] }, prop.source, 'contactgroup'); |
| | | |
| | | this.triggerEvent('group_insert', { id:prop.id, source:prop.source, name:prop.name, li:this.treelist.get_item(key) }); |
| | | }; |
| | |
| | | .html(name), |
| | | prop = { name:name, id:id }; |
| | | |
| | | this.treelist.insert({ id:key, html:link, classes:['contactsearch'] }, null, 'contactsearch'); |
| | | this.savedsearchlist.insert({ id:key, html:link, classes:['contactsearch'] }, null, 'contactsearch'); |
| | | this.select_folder(key,'',true); |
| | | this.enable_command('search-delete', true); |
| | | this.env.search_id = id; |
| | |
| | | this.remove_search_item = function(id) |
| | | { |
| | | var li, key = 'S'+id; |
| | | if (this.treelist.remove(key)) { |
| | | if (this.savedsearchlist.remove(key)) { |
| | | this.triggerEvent('search_delete', { id:id, li:li }); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | this.reset_qsearch(); |
| | | this.select_folder('S'+id, '', true); |
| | | |
| | | if (this.savedsearchlist) { |
| | | this.treelist.select(''); |
| | | this.savedsearchlist.select('S'+id); |
| | | } |
| | | else |
| | | this.select_folder('S'+id, '', true); |
| | | |
| | | // reset vars |
| | | this.env.current_page = 1; |
| | |
| | | // mark a mailbox as selected and set environment variable |
| | | this.select_folder = function(name, prefix, encode) |
| | | { |
| | | if (this.savedsearchlist) { |
| | | this.savedsearchlist.select(''); |
| | | } |
| | | |
| | | if (this.treelist) { |
| | | this.treelist.select(name); |
| | | } |
| | |
| | | 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) { |
| | | 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); |
| | | } |
| | | delete this.env.list_uid; |
| | | } |
| | | |
| | | this.enable_command('set-listmode', this.env.threads && !is_multifolder); |
| | | if (this.message_list.rowcount > 0) |
| | | this.message_list.focus(); |
| | | this.msglist_select(this.message_list); |
| | | this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:this.message_list.rowcount }); |
| | | 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') { |
| | |
| | | // post the given form to a hidden iframe |
| | | this.async_upload_form = function(form, action, onload) |
| | | { |
| | | var frame, ts = new Date().getTime(), |
| | | frame_name = 'rcmupload'+ts; |
| | | // create hidden iframe |
| | | var ts = new Date().getTime(), |
| | | frame_name = 'rcmupload' + ts, |
| | | frame = this.async_upload_form_frame(frame_name); |
| | | |
| | | // upload progress support |
| | | if (this.env.upload_progress_name) { |
| | |
| | | field.val(ts); |
| | | } |
| | | |
| | | // have to do it this way for IE |
| | | // otherwise the form will be posted to a new window |
| | | if (document.all) { |
| | | document.body.insertAdjacentHTML('BeforeEnd', '<iframe name="'+frame_name+'"' |
| | | + ' src="program/resources/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>'); |
| | | frame = $('iframe[name="'+frame_name+'"]'); |
| | | } |
| | | // for standards-compliant browsers |
| | | else { |
| | | frame = $('<iframe>').attr('name', frame_name) |
| | | .css({border: 'none', width: 0, height: 0, visibility: 'hidden'}) |
| | | .appendTo(document.body); |
| | | } |
| | | |
| | | // handle upload errors, parsing iframe content in onload |
| | | // handle upload errors by parsing iframe content in onload |
| | | frame.bind('load', {ts:ts}, onload); |
| | | |
| | | $(form).attr({ |
| | | target: frame_name, |
| | | action: this.url(action, { _id:this.env.compose_id||'', _uploadid:ts }), |
| | | action: this.url(action, {_id: this.env.compose_id || '', _uploadid: ts, _from: this.env.action}), |
| | | method: 'POST'}) |
| | | .attr(form.encoding ? 'encoding' : 'enctype', 'multipart/form-data') |
| | | .submit(); |
| | |
| | | return frame_name; |
| | | }; |
| | | |
| | | // create iframe element for files upload |
| | | this.async_upload_form_frame = function(name) |
| | | { |
| | | return $('<iframe>').attr({name: name, style: 'border: none; width: 0; height: 0; visibility: hidden'}) |
| | | .appendTo(document.body); |
| | | }; |
| | | |
| | | // html5 file-drop API |
| | | this.document_drag_hover = function(e, over) |
| | | { |