| | |
| | | | Roundcube Webmail Client Script | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2010, The Roundcube Dev Team | |
| | | | Copyright (C) 2005-2011, The Roundcube Dev Team | |
| | | | Copyright (C) 2011, Kolab Systems AG | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | |
| | | this.message_time = 2000; |
| | | |
| | | this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi'); |
| | | |
| | | // mimetypes supported by the browser (default settings) |
| | | this.mimetypes = new Array('text/plain', 'text/html', 'text/xml', |
| | | 'image/jpeg', 'image/gif', 'image/png', |
| | | 'application/x-javascript', 'application/pdf', 'application/x-shockwave-flash'); |
| | | |
| | | // default environment vars |
| | | this.env.keep_alive = 60; // seconds |
| | |
| | | if (over) button_prop.over = over; |
| | | |
| | | this.buttons[command].push(button_prop); |
| | | |
| | | if (this.loaded) |
| | | init_button(command, button_prop); |
| | | }; |
| | | |
| | | // register a specific gui object |
| | | this.gui_object = function(name, id) |
| | | { |
| | | this.gui_objects[name] = id; |
| | | this.gui_objects[name] = this.loaded ? rcube_find_object(id) : id; |
| | | }; |
| | | |
| | | // register a container object |
| | |
| | | return; |
| | | } |
| | | |
| | | // Enable debug console |
| | | if (!window.console || !window.console.log) { |
| | | window.console = new rcube_console(); |
| | | } |
| | | else { |
| | | $('#console').hide(); |
| | | } |
| | | |
| | | // find all registered gui containers |
| | | for (var n in this.gui_containers) |
| | | this.gui_containers[n] = $('#'+this.gui_containers[n]); |
| | |
| | | } |
| | | |
| | | // enable general commands |
| | | this.enable_command('logout', 'mail', 'addressbook', 'settings', 'save-pref', true); |
| | | this.enable_command('logout', 'mail', 'addressbook', 'settings', 'save-pref', 'compose', 'undo', true); |
| | | |
| | | if (this.env.permaurl) |
| | | this.enable_command('permaurl', true); |
| | |
| | | |
| | | case 'mail': |
| | | // enable mail commands |
| | | this.enable_command('list', 'checkmail', 'compose', 'add-contact', 'search', 'reset-search', 'collapse-folder', true); |
| | | this.enable_command('list', 'checkmail', 'add-contact', 'search', 'reset-search', 'collapse-folder', true); |
| | | |
| | | if (this.gui_objects.messagelist) { |
| | | |
| | |
| | | $(this.gui_objects.qsearchbox).focusin(function() { rcmail.message_list.blur(); }); |
| | | } |
| | | |
| | | if (this.env.trash_mailbox && this.env.mailbox != this.env.trash_mailbox) |
| | | if (!this.env.flag_for_deletion && this.env.trash_mailbox && this.env.mailbox != this.env.trash_mailbox) |
| | | this.set_alttext('delete', 'movemessagetotrash'); |
| | | |
| | | this.env.message_commands = ['show', 'reply', 'reply-all', 'reply-list', 'forward', |
| | |
| | | } |
| | | // show printing dialog |
| | | else if (this.env.action == 'print' && this.env.uid) |
| | | window.print(); |
| | | if (bw.safari) |
| | | window.setTimeout('window.print()', 10); |
| | | else |
| | | window.print(); |
| | | |
| | | // get unread count for each mailbox |
| | | if (this.gui_objects.mailboxlist) { |
| | |
| | | if (this.gui_objects.folderlist) |
| | | this.env.contactfolders = $.extend($.extend({}, this.env.address_sources), this.env.contactgroups); |
| | | |
| | | this.enable_command('add', 'import', this.env.writable_source); |
| | | this.enable_command('list', 'listgroup', 'listsearch', 'advanced-search', true); |
| | | |
| | | if (this.gui_objects.contactslist) { |
| | | |
| | | this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, |
| | |
| | | $(this.gui_objects.qsearchbox).focusin(function() { rcmail.contact_list.blur(); }); |
| | | } |
| | | |
| | | this.enable_command('group-create', this.env.address_sources[this.env.source].groups); |
| | | this.update_group_commands(); |
| | | this.command('list'); |
| | | } |
| | | |
| | | this.set_page_buttons(); |
| | |
| | | this.enable_command('show', 'edit', true); |
| | | // register handlers for group assignment via checkboxes |
| | | if (this.gui_objects.editform) { |
| | | $('input.groupmember').change(function(){ |
| | | var cmd = this.checked ? 'group-addmembers' : 'group-delmembers'; |
| | | ref.http_post(cmd, '_cid='+urlencode(ref.env.cid) |
| | | + '&_source='+urlencode(ref.env.source) |
| | | + '&_gid='+urlencode(this.value)); |
| | | $('input.groupmember').change(function() { |
| | | ref.group_member_change(this.checked ? 'add' : 'del', ref.env.cid, ref.env.source, this.value); |
| | | }); |
| | | } |
| | | } |
| | |
| | | if (this.env.action == 'add' || this.env.action == 'edit') |
| | | this.init_contact_form(); |
| | | } |
| | | |
| | | if (this.gui_objects.qsearchbox) { |
| | | this.enable_command('search', 'reset-search', 'moveto', true); |
| | | $(this.gui_objects.qsearchbox).select(); |
| | | } |
| | | |
| | | if (this.contact_list && this.contact_list.rowcount > 0) |
| | | this.enable_command('export', true); |
| | | |
| | | this.enable_command('add', 'import', this.env.writable_source); |
| | | this.enable_command('list', 'listgroup', 'advanced-search', true); |
| | | break; |
| | | |
| | | |
| | | case 'settings': |
| | | this.enable_command('preferences', 'identities', 'save', 'folders', true); |
| | |
| | | $('#rcmloginpwd').focus(); |
| | | |
| | | // detect client timezone |
| | | $('#rcmlogintz').val(new Date().getTimezoneOffset() / -60); |
| | | var tz = new Date().getTimezoneOffset() / -60; |
| | | var stdtz = new Date().getStdTimezoneOffset() / -60; |
| | | $('#rcmlogintz').val(stdtz); |
| | | $('#rcmlogindst').val(tz > stdtz ? 1 : 0); |
| | | |
| | | // display 'loading' message on form submit, lock submit button |
| | | $('form').submit(function () { |
| | |
| | | break; |
| | | } |
| | | |
| | | // prevent from form submit with Enter key in file input fields |
| | | if (bw.ie) |
| | | $('input[type=file]').keydown(function(e) { if (e.keyCode == '13') e.preventDefault(); }); |
| | | |
| | | // flag object as complete |
| | | this.loaded = true; |
| | | |
| | | // show message |
| | | if (this.pending_message) |
| | | this.display_message(this.pending_message[0], this.pending_message[1]); |
| | | this.display_message(this.pending_message[0], this.pending_message[1], this.pending_message[2]); |
| | | |
| | | // map implicit containers |
| | | if (this.gui_objects.folderlist) |
| | |
| | | this.start_keepalive(); |
| | | }; |
| | | |
| | | this.log = function(msg) |
| | | { |
| | | if (window.console && console.log) |
| | | console.log(msg); |
| | | }; |
| | | |
| | | /*********************************************************/ |
| | | /********* client command interface *********/ |
| | |
| | | // execute a specific command on the web client |
| | | this.command = function(command, props, obj) |
| | | { |
| | | var ret; |
| | | |
| | | if (obj && obj.blur) |
| | | obj.blur(); |
| | | |
| | |
| | | |
| | | // process external commands |
| | | if (typeof this.command_handlers[command] === 'function') { |
| | | var ret = this.command_handlers[command](props, obj); |
| | | ret = this.command_handlers[command](props, obj); |
| | | return ret !== undefined ? ret : (obj ? false : true); |
| | | } |
| | | else if (typeof this.command_handlers[command] === 'string') { |
| | | var ret = window[this.command_handlers[command]](props, obj); |
| | | ret = window[this.command_handlers[command]](props, obj); |
| | | return ret !== undefined ? ret : (obj ? false : true); |
| | | } |
| | | |
| | | // trigger plugin hooks |
| | | this.triggerEvent('actionbefore', {props:props, action:command}); |
| | | var ret = this.triggerEvent('before'+command, props); |
| | | ret = this.triggerEvent('before'+command, props); |
| | | if (ret !== undefined) { |
| | | // abort if one the handlers returned false |
| | | // abort if one of the handlers returned false |
| | | if (ret === false) |
| | | return false; |
| | | else |
| | | props = ret; |
| | | } |
| | | |
| | | ret = undefined; |
| | | |
| | | // process internal command |
| | | switch (command) { |
| | |
| | | break; |
| | | |
| | | case 'list': |
| | | if (this.task=='mail') { |
| | | if (!this.env.search_request || (props && props != this.env.mailbox)) |
| | | this.reset_qsearch(); |
| | | |
| | | this.reset_qsearch(); |
| | | if (this.task == 'mail') { |
| | | this.list_mailbox(props); |
| | | |
| | | if (this.env.trash_mailbox) |
| | | if (this.env.trash_mailbox && !this.env.flag_for_deletion) |
| | | this.set_alttext('delete', this.env.mailbox != this.env.trash_mailbox ? 'movemessagetotrash' : 'deletemessage'); |
| | | } |
| | | else if (this.task == 'addressbook') { |
| | | if (!this.env.search_request || (props != this.env.source)) |
| | | this.reset_qsearch(); |
| | | |
| | | this.list_contacts(props); |
| | | this.enable_command('add', 'import', this.env.writable_source); |
| | | } |
| | | break; |
| | | |
| | |
| | | } |
| | | // contacts/identities |
| | | else { |
| | | if ((input = $("input[name='_name']", form)) &&input.length && input.val() == '') { |
| | | alert(this.get_label('nonamewarning')); |
| | | input.focus(); |
| | | break; |
| | | // reload form |
| | | if (props == 'reload') { |
| | | form.action += '?_reload=1'; |
| | | } |
| | | else if (this.task == 'settings' && (this.env.identities_level % 2) == 0 && |
| | | (input = $("input[name='_email']", form)) && input.length&& !rcube_check_email(input.val()) |
| | | (input = $("input[name='_email']", form)) && input.length && !rcube_check_email(input.val()) |
| | | ) { |
| | | alert(this.get_label('noemailwarning')); |
| | | input.focus(); |
| | |
| | | // clear empty input fields |
| | | $('input.placeholder').each(function(){ if (this.value == this._placeholder) this.value = ''; }); |
| | | } |
| | | |
| | | // add selected source (on the list) |
| | | if (parent.rcmail && parent.rcmail.env.source) |
| | | form.action = this.add_url(form.action, '_orig_source', parent.rcmail.env.source); |
| | | |
| | | form.submit(); |
| | | } |
| | |
| | | var qstring = '_mbox='+urlencode(this.env.mailbox)+'&_uid='+this.env.uid+'&_part='+props.part; |
| | | |
| | | // open attachment in frame if it's of a supported mimetype |
| | | if (this.env.uid && props.mimetype && $.inArray(props.mimetype, this.mimetypes)>=0) { |
| | | if (this.env.uid && props.mimetype && this.env.mimetypes && $.inArray(props.mimetype, this.env.mimetypes)>=0) { |
| | | if (props.mimetype == 'text/html') |
| | | qstring += '&_safe=1'; |
| | | this.attachment_win = window.open(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', 'rcubemailattachment'); |
| | |
| | | break; |
| | | |
| | | case 'compose': |
| | | var url = this.env.comm_path+'&_action=compose'; |
| | | var url = this.url('mail/compose'); |
| | | |
| | | if (this.task == 'mail') { |
| | | url += '&_mbox='+urlencode(this.env.mailbox); |
| | |
| | | } |
| | | |
| | | if (a_cids.length) |
| | | this.http_post('mailto', {_cid: a_cids.join(','), _source: this.env.source}, true); |
| | | this.http_post('mailto', { _cid: a_cids.join(','), _source: this.env.source}, true); |
| | | else if (this.env.group) |
| | | this.http_post('mailto', { _gid: this.env.group, _source: this.env.source}, true); |
| | | |
| | | break; |
| | | } |
| | | else if (props) |
| | | url += '&_to='+urlencode(props); |
| | | |
| | | this.redirect(url); |
| | | break; |
| | |
| | | |
| | | // reset quicksearch |
| | | case 'reset-search': |
| | | var s = this.env.search_request; |
| | | var n, s = this.env.search_request || this.env.qsearch; |
| | | |
| | | this.reset_qsearch(); |
| | | this.select_all_mode = false; |
| | | |
| | | if (s && this.env.mailbox) |
| | | this.list_mailbox(this.env.mailbox); |
| | | this.list_mailbox(this.env.mailbox, 1); |
| | | else if (s && this.task == 'addressbook') { |
| | | if (this.env.source == '') { |
| | | for (var n in this.env.address_sources) break; |
| | | for (n in this.env.address_sources) break; |
| | | this.env.source = n; |
| | | this.env.group = ''; |
| | | } |
| | | this.list_contacts(this.env.source, this.env.group); |
| | | this.list_contacts(this.env.source, this.env.group, 1); |
| | | } |
| | | break; |
| | | |
| | | case 'listgroup': |
| | | this.reset_qsearch(); |
| | | this.list_contacts(props.source, props.id); |
| | | break; |
| | | |
| | |
| | | this.goto_url('settings/' + command); |
| | | break; |
| | | |
| | | case 'undo': |
| | | this.http_request('undo', '', this.display_message('', 'loading')); |
| | | break; |
| | | |
| | | // unified command call (command name == function name) |
| | | default: |
| | | var func = command.replace(/-/g, '_'); |
| | | if (this[func] && typeof this[func] === 'function') |
| | | this[func](props); |
| | | if (this[func] && typeof this[func] === 'function') { |
| | | ret = this[func](props); |
| | | } |
| | | break; |
| | | } |
| | | |
| | | this.triggerEvent('after'+command, props); |
| | | if (this.triggerEvent('after'+command, props) === false) |
| | | ret = false; |
| | | this.triggerEvent('actionafter', {props:props, action:command}); |
| | | |
| | | return obj ? false : true; |
| | | return ret === false ? false : obj ? false : true; |
| | | }; |
| | | |
| | | // set command(s) enabled or disabled |
| | |
| | | this.drag_menu = function(e, target) |
| | | { |
| | | var modkey = rcube_event.get_modifier(e), |
| | | menu = $('#'+this.gui_objects.message_dragmenu); |
| | | menu = this.gui_objects.message_dragmenu; |
| | | |
| | | if (menu && modkey == SHIFT_KEY && this.commands['copy']) { |
| | | var pos = rcube_event.get_mouse_pos(e); |
| | | this.env.drag_target = target; |
| | | menu.css({top: (pos.y-10)+'px', left: (pos.x-10)+'px'}).show(); |
| | | $(menu).css({top: (pos.y-10)+'px', left: (pos.x-10)+'px'}).show(); |
| | | return true; |
| | | } |
| | | |
| | |
| | | |
| | | this.drag_menu_action = function(action) |
| | | { |
| | | var menu = $('#'+this.gui_objects.message_dragmenu); |
| | | var menu = this.gui_objects.message_dragmenu; |
| | | if (menu) { |
| | | menu.hide(); |
| | | $(menu).hide(); |
| | | } |
| | | this.command(action, this.env.drag_target); |
| | | this.env.drag_target = null; |
| | |
| | | var toffset = -moffset-boffset; |
| | | var li, div, pos, mouse, check, oldclass, |
| | | layerclass = 'draglayernormal'; |
| | | |
| | | |
| | | if (this.contact_list && this.contact_list.draglayer) |
| | | oldclass = this.contact_list.draglayer.attr('class'); |
| | | |
| | |
| | | ul.show(); |
| | | div.removeClass('collapsed').addClass('expanded'); |
| | | var reg = new RegExp('&'+urlencode(id)+'&'); |
| | | this.set_env('collapsed_folders', this.env.collapsed_folders.replace(reg, '')); |
| | | this.env.collapsed_folders = this.env.collapsed_folders.replace(reg, ''); |
| | | } |
| | | else { |
| | | ul.hide(); |
| | | div.removeClass('expanded').addClass('collapsed'); |
| | | this.set_env('collapsed_folders', this.env.collapsed_folders+'&'+urlencode(id)+'&'); |
| | | this.env.collapsed_folders = this.env.collapsed_folders+'&'+urlencode(id)+'&'; |
| | | |
| | | // select parent folder if one of its childs is currently selected |
| | | if (this.env.mailbox.indexOf(id + this.env.delimiter) == 0) |
| | |
| | | this.doc_mouse_up = function(e) |
| | | { |
| | | var model, list, li, id; |
| | | |
| | | // ignore event if jquery UI dialog is open |
| | | if ($(rcube_event.get_target(e)).closest('.ui-dialog, .ui-widget-overlay').length) |
| | | return; |
| | | |
| | | if (list = this.message_list) { |
| | | if (!rcube_mouse_is_over(e, list.list.parentNode)) |
| | |
| | | |
| | | this.msglist_keypress = function(list) |
| | | { |
| | | if (list.modkey == CONTROL_KEY) |
| | | return; |
| | | |
| | | if (list.key_pressed == list.ENTER_KEY) |
| | | this.command('show'); |
| | | else if (list.key_pressed == list.DELETE_KEY) |
| | | this.command('delete'); |
| | | else if (list.key_pressed == list.BACKSPACE_KEY) |
| | | else if (list.key_pressed == list.DELETE_KEY || list.key_pressed == list.BACKSPACE_KEY) |
| | | this.command('delete'); |
| | | else if (list.key_pressed == 33) |
| | | this.command('previouspage'); |
| | |
| | | } |
| | | |
| | | if ((found = $.inArray('flag', this.env.coltypes)) >= 0) |
| | | this.set_env('flagged_col', found); |
| | | this.env.flagged_col = found; |
| | | |
| | | if ((found = $.inArray('subject', this.env.coltypes)) >= 0) |
| | | this.set_env('subject_col', found); |
| | | this.env.subject_col = found; |
| | | |
| | | this.command('save-pref', { name: 'list_cols', value: this.env.coltypes, session: 'list_attrib/columns' }); |
| | | }; |
| | |
| | | if (!this.gui_objects.messagelist || !this.message_list) |
| | | return false; |
| | | |
| | | // Prevent from adding messages from different folder (#1487752) |
| | | if (flags.mbox != this.env.mailbox && !flags.skip_mbox_check) |
| | | return false; |
| | | |
| | | if (!this.env.messages[uid]) |
| | | this.env.messages[uid] = {}; |
| | | |
| | | // merge flags over local message object |
| | | $.extend(this.env.messages[uid], { |
| | | deleted: flags.deleted?1:0, |
| | | replied: flags.replied?1:0, |
| | | unread: flags.unread?1:0, |
| | | replied: flags.answered?1:0, |
| | | unread: !flags.seen?1:0, |
| | | forwarded: flags.forwarded?1:0, |
| | | flagged: flags.flagged?1:0, |
| | | has_children: flags.has_children?1:0, |
| | |
| | | flags: flags.extra_flags |
| | | }); |
| | | |
| | | var c, html, tree = expando = '', |
| | | var c, n, col, html, tree = '', expando = '', |
| | | list = this.message_list, |
| | | rows = list.rows, |
| | | tbody = this.gui_objects.messagelist.tBodies[0], |
| | | rowcount = tbody.rows.length, |
| | | even = rowcount%2, |
| | | message = this.env.messages[uid], |
| | | css_class = 'message' |
| | | + (even ? ' even' : ' odd') |
| | | + (flags.unread ? ' unread' : '') |
| | | + (!flags.seen ? ' unread' : '') |
| | | + (flags.deleted ? ' deleted' : '') |
| | | + (flags.flagged ? ' flagged' : '') |
| | | + (flags.unread_children && !flags.unread && !this.env.autoexpand_threads ? ' unroot' : '') |
| | | + (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'), |
| | | col = document.createElement('td'); |
| | | row = document.createElement('tr'); |
| | | |
| | | row.id = 'rcmrow'+uid; |
| | | row.className = css_class; |
| | |
| | | css_class += ' status'; |
| | | if (flags.deleted) |
| | | css_class += ' deleted'; |
| | | else if (flags.unread) |
| | | else if (!flags.seen) |
| | | css_class += ' unread'; |
| | | else if (flags.unread_children > 0) |
| | | css_class += ' unreadchildren'; |
| | | } |
| | | if (flags.replied) |
| | | if (flags.answered) |
| | | css_class += ' replied'; |
| | | if (flags.forwarded) |
| | | css_class += ' forwarded'; |
| | |
| | | |
| | | // threads |
| | | if (this.env.threading) { |
| | | // This assumes that div width is hardcoded to 15px, |
| | | var width = message.depth * 15; |
| | | if (message.depth) { |
| | | // This assumes that div width is hardcoded to 15px, |
| | | tree += '<span id="rcmtab' + uid + '" class="branch" style="width:' + (message.depth * 15) + 'px;"> </span>'; |
| | | |
| | | if ((rows[message.parent_uid] && rows[message.parent_uid].expanded === false) |
| | | || ((this.env.autoexpand_threads == 0 || this.env.autoexpand_threads == 2) && |
| | | (!rows[message.parent_uid] || !rows[message.parent_uid].expanded)) |
| | |
| | | if (message.expanded === undefined && (this.env.autoexpand_threads == 1 || (this.env.autoexpand_threads == 2 && message.unread_children))) { |
| | | message.expanded = true; |
| | | } |
| | | } |
| | | |
| | | if (width) |
| | | tree += '<span id="rcmtab' + uid + '" class="branch" style="width:' + width + 'px;"> </span>'; |
| | | |
| | | if (message.has_children && !message.depth) |
| | | expando = '<div id="rcmexpando' + uid + '" class="' + (message.expanded ? 'expanded' : 'collapsed') + '"> </div>'; |
| | | } |
| | | } |
| | | |
| | | tree += '<span id="msgicn'+uid+'" class="'+css_class+'"> </span>'; |
| | |
| | | } |
| | | |
| | | // add each submitted col |
| | | for (var n in this.env.coltypes) { |
| | | for (n in this.env.coltypes) { |
| | | c = this.env.coltypes[n]; |
| | | col = document.createElement('td'); |
| | | col.className = String(c).toLowerCase(); |
| | |
| | | else if (c == 'status') { |
| | | if (flags.deleted) |
| | | css_class = 'deleted'; |
| | | else if (flags.unread) |
| | | else if (!flags.seen) |
| | | css_class = 'unread'; |
| | | else if (flags.unread_children > 0) |
| | | css_class = 'unreadchildren'; |
| | |
| | | } |
| | | else if (c == 'threads') |
| | | html = expando; |
| | | else if (c == 'subject') |
| | | else if (c == 'subject') { |
| | | if (bw.ie) |
| | | col.onmouseover = function() { rcube_webmail.long_subject_title_ie(this, message.depth+1); }; |
| | | html = tree + cols[c]; |
| | | } |
| | | else if (c == 'priority') { |
| | | if (flags.prio > 0 && flags.prio < 6) |
| | | html = '<span class="prio'+flags.prio+'"> </span>'; |
| | | else |
| | | html = ' '; |
| | | } |
| | | else |
| | | html = cols[c]; |
| | | |
| | |
| | | if (action == 'preview' && String(target.location.href).indexOf(url) >= 0) |
| | | this.show_contentframe(true); |
| | | else { |
| | | if (!this.env.frame_lock) { |
| | | (this.is_framed() ? parent.rcmail : this).env.frame_lock = this.set_busy(true, 'loading'); |
| | | } |
| | | this.location_href(this.env.comm_path+url, target); |
| | | this.location_href(this.env.comm_path+url, target, true); |
| | | |
| | | // mark as read and change mbox unread counter |
| | | if (action == 'preview' && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread && this.env.preview_pane_mark_read >= 0) { |
| | |
| | | this.set_busy(false, null, this.env.frame_lock); |
| | | }; |
| | | |
| | | this.lock_frame = function() |
| | | { |
| | | if (!this.env.frame_lock) |
| | | (this.is_framed() ? parent.rcmail : this).env.frame_lock = this.set_busy(true, 'loading'); |
| | | }; |
| | | |
| | | // list a specific page |
| | | this.list_page = function(page) |
| | | { |
| | |
| | | // list messages of a specific mailbox using filter |
| | | this.filter_mailbox = function(filter) |
| | | { |
| | | var search, lock = this.set_busy(true, 'searching'); |
| | | |
| | | if (this.gui_objects.qsearchbox) |
| | | search = this.gui_objects.qsearchbox.value; |
| | | var lock = this.set_busy(true, 'searching'); |
| | | |
| | | this.clear_message_list(); |
| | | |
| | | // reset vars |
| | | this.env.current_page = 1; |
| | | this.http_request('search', '_filter='+filter |
| | | + (search ? '&_q='+urlencode(search) : '') |
| | | + (this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : ''), lock); |
| | | this.http_request('search', this.search_params(false, filter), lock); |
| | | }; |
| | | |
| | | // list messages of a specific mailbox |
| | |
| | | if (mbox != this.env.mailbox || (mbox == this.env.mailbox && !page && !sort)) |
| | | url += '&_refresh=1'; |
| | | |
| | | this.select_folder(mbox, this.env.mailbox); |
| | | this.select_folder(mbox); |
| | | this.env.mailbox = mbox; |
| | | |
| | | // load message list remotely |
| | |
| | | new_row = tbody.firstChild; |
| | | |
| | | while (new_row) { |
| | | if (new_row.nodeType == 1 && (r = this.message_list.rows[new_row.uid]) |
| | | && r.unread_children) { |
| | | if (new_row.nodeType == 1 && (r = this.message_list.rows[new_row.uid]) && r.unread_children) { |
| | | this.message_list.expand_all(r); |
| | | this.set_unread_children(r.uid); |
| | | } |
| | |
| | | }; |
| | | |
| | | // Initializes threads indicators/expanders after list update |
| | | this.init_threads = function(roots) |
| | | this.init_threads = function(roots, mbox) |
| | | { |
| | | // #1487752 |
| | | if (mbox && mbox != this.env.mailbox) |
| | | return false; |
| | | |
| | | for (var n=0, len=roots.length; n<len; n++) |
| | | this.add_tree_icons(roots[n]); |
| | | this.expand_threads(); |
| | |
| | | // if there is a trash mailbox defined and we're not currently in it |
| | | else { |
| | | // if shift was pressed delete it immediately |
| | | if (list && list.shiftkey) { |
| | | if (list && list.modkey == SHIFT_KEY) { |
| | | if (confirm(this.get_label('deletemessagesconfirm'))) |
| | | this.permanently_remove_messages(); |
| | | } |
| | |
| | | |
| | | this.expunge_mailbox = function(mbox) |
| | | { |
| | | var lock = false, |
| | | url = '_mbox='+urlencode(mbox); |
| | | var lock, url = '_mbox='+urlencode(mbox); |
| | | |
| | | // lock interface if it's the active mailbox |
| | | if (mbox == this.env.mailbox) { |
| | | lock = this.set_busy(true, 'loading'); |
| | | url += '&_reload=1'; |
| | | } |
| | | lock = this.set_busy(true, 'loading'); |
| | | url += '&_reload=1'; |
| | | if (this.env.search_request) |
| | | url += '&_search='+this.env.search_request; |
| | | } |
| | | |
| | | // send request to server |
| | | this.http_post('expunge', url, lock); |
| | |
| | | input_subject = $("input[name='_subject']"), |
| | | input_message = $("[name='_message']").get(0), |
| | | html_mode = $("input[name='_is_html']").val() == '1', |
| | | ac_fields = ['cc', 'bcc', 'replyto', 'followupto']; |
| | | ac_fields = ['cc', 'bcc', 'replyto', 'followupto'], |
| | | ac_props; |
| | | |
| | | // configure parallel autocompletion |
| | | if (this.env.autocomplete_threads > 0) { |
| | | ac_props = { |
| | | threads: this.env.autocomplete_threads, |
| | | sources: this.env.autocomplete_sources |
| | | }; |
| | | } |
| | | |
| | | // init live search events |
| | | this.init_address_input_events(input_to); |
| | | this.init_address_input_events(input_to, ac_props); |
| | | for (var i in ac_fields) { |
| | | this.init_address_input_events($("[name='_"+ac_fields[i]+"']")); |
| | | this.init_address_input_events($("[name='_"+ac_fields[i]+"']"), ac_props); |
| | | } |
| | | |
| | | if (!html_mode) { |
| | | this.set_caret_pos(input_message, this.env.top_posting ? 0 : $(input_message).val().length); |
| | | // add signature according to selected identity |
| | | // if we have HTML editor, signature is added in callback |
| | | if (input_from.attr('type') == 'select-one' && $("input[name='_draft_saveid']").val() == '') { |
| | | if (input_from.prop('type') == 'select-one' && $("input[name='_draft_saveid']").val() == '') { |
| | | this.change_identity(input_from[0]); |
| | | } |
| | | } |
| | |
| | | this.auto_save_start(); |
| | | }; |
| | | |
| | | this.init_address_input_events = function(obj) |
| | | this.init_address_input_events = function(obj, props) |
| | | { |
| | | obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e){ return ref.ksearch_keydown(e, this); }) |
| | | obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e) { return ref.ksearch_keydown(e, this, props); }) |
| | | .attr('autocomplete', 'off'); |
| | | }; |
| | | |
| | |
| | | input_message = $("[name='_message']"); |
| | | |
| | | // check sender (if have no identities) |
| | | if (input_from.attr('type') == 'text' && !rcube_check_email(input_from.val(), true)) { |
| | | if (input_from.prop('type') == 'text' && !rcube_check_email(input_from.val(), true)) { |
| | | alert(this.get_label('nosenderwarning')); |
| | | input_from.focus(); |
| | | return false; |
| | |
| | | sig = this.env.signatures[sig].is_html ? this.env.signatures[sig].plain_text : this.env.signatures[sig].text; |
| | | sig = sig.replace(/\r\n/g, '\n'); |
| | | |
| | | if (!sig.match(/^--[ -]\n/)) |
| | | if (!sig.match(/^--[ -]\n/m)) |
| | | sig = sig_separator + '\n' + sig; |
| | | |
| | | p = this.env.sig_above ? message.indexOf(sig) : message.lastIndexOf(sig); |
| | |
| | | sig = this.env.signatures[id]['is_html'] ? this.env.signatures[id]['plain_text'] : this.env.signatures[id]['text']; |
| | | sig = sig.replace(/\r\n/g, '\n'); |
| | | |
| | | if (!sig.match(/^--[ -]\n/)) |
| | | if (!sig.match(/^--[ -]\n/m)) |
| | | sig = sig_separator + '\n' + sig; |
| | | |
| | | if (this.env.sig_above) { |
| | |
| | | if (this.env.signatures[id]) { |
| | | if (this.env.signatures[id].is_html) { |
| | | sig = this.env.signatures[id].text; |
| | | if (!this.env.signatures[id].plain_text.match(/^--[ -]\r?\n/)) |
| | | if (!this.env.signatures[id].plain_text.match(/^--[ -]\r?\n/m)) |
| | | sig = sig_separator + '<br />' + sig; |
| | | } |
| | | else { |
| | | sig = this.env.signatures[id].text; |
| | | if (!sig.match(/^--[ -]\r?\n/)) |
| | | if (!sig.match(/^--[ -]\r?\n/m)) |
| | | sig = sig_separator + '\n' + sig; |
| | | sig = '<pre>' + sig + '</pre>'; |
| | | } |
| | |
| | | return false; |
| | | |
| | | // get file input field, count files on capable browser |
| | | var field = $('input[type=file]', form).get(0), |
| | | var i, size = 0, field = $('input[type=file]', form).get(0), |
| | | files = field.files ? field.files.length : field.value ? 1 : 0; |
| | | |
| | | // create hidden iframe and post upload form |
| | | if (files) { |
| | | // check file size |
| | | if (field.files && this.env.max_filesize && this.env.filesizeerror) { |
| | | for (i=0; i<files; i++) |
| | | size += field.files[i].size; |
| | | if (size && size > this.env.max_filesize) { |
| | | this.display_message(this.env.filesizeerror, 'error'); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | var frame_name = this.async_upload_form(form, 'upload', function(e) { |
| | | var d, content = ''; |
| | | try { |
| | |
| | | }); |
| | | |
| | | // display upload indicator and cancel button |
| | | var content = this.get_label('uploading' + (files > 1 ? 'many' : '')), |
| | | var content = '<span>' + this.get_label('uploading' + (files > 1 ? 'many' : '')) + '</span>', |
| | | ts = frame_name.replace(/^rcmupload/, ''); |
| | | |
| | | if (this.env.loadingicon) |
| | |
| | | if (this.env.cancelicon) |
| | | content = '<a title="'+this.get_label('cancel')+'" onclick="return rcmail.cancel_attachment_upload(\''+ts+'\', \''+frame_name+'\');" href="#cancelupload"><img src="'+this.env.cancelicon+'" alt="" /></a>'+content; |
| | | this.add2attachment_list(ts, { name:'', html:content, complete:false }); |
| | | |
| | | // upload progress support |
| | | if (this.env.upload_progress_time) { |
| | | this.upload_progress_start('upload', ts); |
| | | } |
| | | } |
| | | |
| | | // set reference to the form object |
| | |
| | | return false; |
| | | }; |
| | | |
| | | this.upload_progress_start = function(action, name) |
| | | { |
| | | window.setTimeout(function() { rcmail.http_request(action, {_progress: name}); }, |
| | | this.env.upload_progress_time * 1000); |
| | | }; |
| | | |
| | | this.upload_progress_update = function(param) |
| | | { |
| | | var elem = $('#'+param.name + '> span'); |
| | | |
| | | if (!elem.length || !param.text) |
| | | return; |
| | | |
| | | elem.text(param.text); |
| | | |
| | | if (!param.done) |
| | | this.upload_progress_start(param.action, param.name); |
| | | }; |
| | | |
| | | // send remote request to add a new contact |
| | | this.add_contact = function(value) |
| | | { |
| | |
| | | this.qsearch = function(value) |
| | | { |
| | | if (value != '') { |
| | | var n, addurl = '', mods_arr = [], |
| | | mods = this.env.search_mods, |
| | | mbox = this.env.mailbox, |
| | | lock = this.set_busy(true, 'searching'); |
| | | var n, lock = this.set_busy(true, 'searching'); |
| | | |
| | | if (this.message_list) { |
| | | if (this.message_list) |
| | | this.clear_message_list(); |
| | | if (mods) |
| | | mods = mods[mbox] ? mods[mbox] : mods['*']; |
| | | } else if (this.contact_list) { |
| | | else if (this.contact_list) |
| | | this.list_contacts_clear(); |
| | | } |
| | | |
| | | // reset vars |
| | | this.env.current_page = 1; |
| | | r = this.http_request('search', this.search_params(value) |
| | | + (this.env.source ? '&_source='+urlencode(this.env.source) : '') |
| | | + (this.env.group ? '&_gid='+urlencode(this.env.group) : ''), lock); |
| | | |
| | | this.env.qsearch = {lock: lock, request: r}; |
| | | } |
| | | }; |
| | | |
| | | // build URL params for search |
| | | this.search_params = function(search, filter) |
| | | { |
| | | var n, url = [], mods_arr = [], |
| | | mods = this.env.search_mods, |
| | | mbox = this.env.mailbox; |
| | | |
| | | if (!filter && this.gui_objects.search_filter) |
| | | filter = this.gui_objects.search_filter.value; |
| | | |
| | | if (!search && this.gui_objects.qsearchbox) |
| | | search = this.gui_objects.qsearchbox.value; |
| | | |
| | | if (filter) |
| | | url.push('_filter=' + urlencode(filter)); |
| | | |
| | | if (search) { |
| | | url.push('_q='+urlencode(search)); |
| | | |
| | | if (mods && this.message_list) |
| | | mods = mods[mbox] ? mods[mbox] : mods['*']; |
| | | |
| | | if (mods) { |
| | | for (n in mods) |
| | | mods_arr.push(n); |
| | | addurl += '&_headers='+mods_arr.join(','); |
| | | url.push('_headers='+mods_arr.join(',')); |
| | | } |
| | | |
| | | if (this.gui_objects.search_filter) |
| | | addurl += '&_filter=' + this.gui_objects.search_filter.value; |
| | | |
| | | // reset vars |
| | | this.env.current_page = 1; |
| | | this.http_request('search', '_q='+urlencode(value) |
| | | + (mbox ? '&_mbox='+urlencode(mbox) : '') |
| | | + (this.env.source ? '&_source='+urlencode(this.env.source) : '') |
| | | + (this.env.group ? '&_gid='+urlencode(this.env.group) : '') |
| | | + (addurl ? addurl : ''), lock); |
| | | } |
| | | return true; |
| | | |
| | | if (mbox) |
| | | url.push('_mbox='+urlencode(mbox)); |
| | | |
| | | return url.join('&'); |
| | | }; |
| | | |
| | | // reset quick-search form |
| | |
| | | if (this.gui_objects.qsearchbox) |
| | | this.gui_objects.qsearchbox.value = ''; |
| | | |
| | | if (this.env.qsearch) |
| | | this.abort_request(this.env.qsearch); |
| | | |
| | | this.env.qsearch = null; |
| | | this.env.search_request = null; |
| | | return true; |
| | | this.env.search_id = null; |
| | | }; |
| | | |
| | | this.sent_successfully = function(type, msg) |
| | |
| | | /*********************************************************/ |
| | | |
| | | // handler for keyboard events on address-fields |
| | | this.ksearch_keydown = function(e, obj) |
| | | this.ksearch_keydown = function(e, obj, props) |
| | | { |
| | | if (this.ksearch_timer) |
| | | clearTimeout(this.ksearch_timer); |
| | | |
| | | var highlight; |
| | | var key = rcube_event.get_keycode(e); |
| | | var mod = rcube_event.get_modifier(e); |
| | | var highlight, |
| | | key = rcube_event.get_keycode(e), |
| | | mod = rcube_event.get_modifier(e); |
| | | |
| | | switch (key) { |
| | | case 38: // key up |
| | |
| | | |
| | | return rcube_event.cancel(e); |
| | | |
| | | case 9: // tab |
| | | if (mod == SHIFT_KEY) |
| | | break; |
| | | case 9: // tab |
| | | if (mod == SHIFT_KEY || !this.ksearch_visible()) { |
| | | this.ksearch_hide(); |
| | | return; |
| | | } |
| | | |
| | | case 13: // enter |
| | | if (this.ksearch_selected===null || !this.ksearch_input || !this.ksearch_value) |
| | | break; |
| | | case 13: // enter |
| | | if (!this.ksearch_visible()) |
| | | return false; |
| | | |
| | | // insert selected address and hide ksearch pane |
| | | this.insert_recipient(this.ksearch_selected); |
| | |
| | | |
| | | case 27: // escape |
| | | this.ksearch_hide(); |
| | | break; |
| | | return; |
| | | |
| | | case 37: // left |
| | | case 39: // right |
| | |
| | | } |
| | | |
| | | // start timer |
| | | this.ksearch_timer = window.setTimeout(function(){ ref.ksearch_get_results(); }, 200); |
| | | this.ksearch_timer = window.setTimeout(function(){ ref.ksearch_get_results(props); }, 200); |
| | | this.ksearch_input = obj; |
| | | |
| | | return true; |
| | | }; |
| | | |
| | | this.ksearch_visible = function() |
| | | { |
| | | return (this.ksearch_selected !== null && this.ksearch_selected !== undefined && this.ksearch_value); |
| | | }; |
| | | |
| | | this.ksearch_select = function(node) |
| | |
| | | |
| | | this.insert_recipient = function(id) |
| | | { |
| | | if (!this.env.contacts[id] || !this.ksearch_input) |
| | | if (id === null || !this.env.contacts[id] || !this.ksearch_input) |
| | | return; |
| | | |
| | | // get cursor pos |
| | | var inp_value = this.ksearch_input.value, |
| | | cpos = this.get_caret_pos(this.ksearch_input), |
| | | p = inp_value.lastIndexOf(this.ksearch_value, cpos), |
| | | trigger = false, |
| | | insert = '', |
| | | |
| | | // replace search string with full address |
| | | pre = inp_value.substring(0, p), |
| | | end = inp_value.substring(p+this.ksearch_value.length, inp_value.length); |
| | | |
| | | this.ksearch_destroy(); |
| | | |
| | | // insert all members of a group |
| | | if (typeof this.env.contacts[id] === 'object' && this.env.contacts[id].id) { |
| | | insert += this.env.contacts[id].name + ', '; |
| | | this.group2expand = $.extend({}, this.env.contacts[id]); |
| | | this.group2expand.input = this.ksearch_input; |
| | | this.http_request('group-expand', '_source='+urlencode(this.env.contacts[id].source)+'&_gid='+urlencode(this.env.contacts[id].id), false); |
| | | this.http_request('mail/group-expand', '_source='+urlencode(this.env.contacts[id].source)+'&_gid='+urlencode(this.env.contacts[id].id), false); |
| | | } |
| | | else if (typeof this.env.contacts[id] === 'string') |
| | | else if (typeof this.env.contacts[id] === 'string') { |
| | | insert = this.env.contacts[id] + ', '; |
| | | trigger = true; |
| | | } |
| | | |
| | | this.ksearch_input.value = pre + insert + end; |
| | | |
| | |
| | | cpos = p+insert.length; |
| | | if (this.ksearch_input.setSelectionRange) |
| | | this.ksearch_input.setSelectionRange(cpos, cpos); |
| | | |
| | | if (trigger) |
| | | this.triggerEvent('autocomplete_insert', { field:this.ksearch_input, insert:insert }); |
| | | }; |
| | | |
| | | this.replace_group_recipients = function(id, recipients) |
| | | { |
| | | if (this.group2expand && this.group2expand.id == id) { |
| | | this.group2expand.input.value = this.group2expand.input.value.replace(this.group2expand.name, recipients); |
| | | this.triggerEvent('autocomplete_insert', { field:this.group2expand.input, insert:recipients }); |
| | | this.group2expand = null; |
| | | } |
| | | }; |
| | | |
| | | // address search processor |
| | | this.ksearch_get_results = function() |
| | | this.ksearch_get_results = function(props) |
| | | { |
| | | var inp_value = this.ksearch_input ? this.ksearch_input.value : null; |
| | | |
| | |
| | | var cpos = this.get_caret_pos(this.ksearch_input), |
| | | p = inp_value.lastIndexOf(',', cpos-1), |
| | | q = inp_value.substring(p+1, cpos), |
| | | min = this.env.autocomplete_min_length; |
| | | min = this.env.autocomplete_min_length, |
| | | ac = this.ksearch_data; |
| | | |
| | | // trim query string |
| | | q = $.trim(q); |
| | |
| | | if (q == this.ksearch_value) |
| | | return; |
| | | |
| | | this.ksearch_destroy(); |
| | | |
| | | if (q.length && q.length < min) { |
| | | if (!this.env.acinfo) { |
| | | this.env.acinfo = this.display_message( |
| | | if (!this.ksearch_info) { |
| | | this.ksearch_info = this.display_message( |
| | | this.get_label('autocompletechars').replace('$min', min)); |
| | | } |
| | | return; |
| | | } |
| | | else if (this.env.acinfo) { |
| | | this.hide_message(this.env.acinfo); |
| | | } |
| | | |
| | | var old_value = this.ksearch_value; |
| | |
| | | if (!q.length) |
| | | return; |
| | | |
| | | // ...new search value contains old one and previous search result was empty |
| | | if (old_value && old_value.length && this.env.contacts && !this.env.contacts.length && q.indexOf(old_value) == 0) |
| | | // ...new search value contains old one and previous search was not finished or its result was empty |
| | | if (old_value && old_value.length && q.indexOf(old_value) == 0 && (!ac || !ac.num) && this.env.contacts && !this.env.contacts.length) |
| | | return; |
| | | |
| | | var lock = this.display_message(this.get_label('searching'), 'loading'); |
| | | this.http_post('autocomplete', '_search='+urlencode(q), lock); |
| | | var i, lock, source, xhr, reqid = new Date().getTime(), |
| | | threads = props && props.threads ? props.threads : 1, |
| | | sources = props && props.sources ? props.sources : [], |
| | | action = props && props.action ? props.action : 'mail/autocomplete'; |
| | | |
| | | this.ksearch_data = {id: reqid, sources: sources.slice(), action: action, |
| | | locks: [], requests: [], num: sources.length}; |
| | | |
| | | for (i=0; i<threads; i++) { |
| | | source = this.ksearch_data.sources.shift(); |
| | | if (threads > 1 && source === null) |
| | | break; |
| | | |
| | | lock = this.display_message(this.get_label('searching'), 'loading'); |
| | | xhr = this.http_post(action, '_search='+urlencode(q)+'&_id='+reqid |
| | | + (source ? '&_source='+urlencode(source) : ''), lock); |
| | | |
| | | this.ksearch_data.locks.push(lock); |
| | | this.ksearch_data.requests.push(xhr); |
| | | } |
| | | }; |
| | | |
| | | this.ksearch_query_results = function(results, search) |
| | | this.ksearch_query_results = function(results, search, reqid) |
| | | { |
| | | // search stopped in meantime? |
| | | if (!this.ksearch_value) |
| | | return; |
| | | |
| | | // ignore this outdated search response |
| | | if (this.ksearch_value && search != this.ksearch_value) |
| | | if (this.ksearch_input && search != this.ksearch_value) |
| | | return; |
| | | |
| | | this.env.contacts = results ? results : []; |
| | | this.ksearch_display_results(this.env.contacts); |
| | | }; |
| | | |
| | | this.ksearch_display_results = function (a_results) |
| | | { |
| | | // display search results |
| | | if (a_results.length && this.ksearch_input && this.ksearch_value) { |
| | | var p, ul, li, text, s_val = this.ksearch_value; |
| | | var ul, li, text, init, |
| | | value = this.ksearch_value, |
| | | data = this.ksearch_data, |
| | | maxlen = this.env.autocomplete_max ? this.env.autocomplete_max : 15; |
| | | |
| | | // create results pane if not present |
| | | if (!this.ksearch_pane) { |
| | | ul = $('<ul>'); |
| | | this.ksearch_pane = $('<div>').attr('id', 'rcmKSearchpane').css({ position:'absolute', 'z-index':30000 }).append(ul).appendTo(document.body); |
| | | this.ksearch_pane.__ul = ul[0]; |
| | | } |
| | | // create results pane if not present |
| | | if (!this.ksearch_pane) { |
| | | ul = $('<ul>'); |
| | | this.ksearch_pane = $('<div>').attr('id', 'rcmKSearchpane') |
| | | .css({ position:'absolute', 'z-index':30000 }).append(ul).appendTo(document.body); |
| | | this.ksearch_pane.__ul = ul[0]; |
| | | } |
| | | |
| | | // remove all search results |
| | | ul = this.ksearch_pane.__ul; |
| | | ul = this.ksearch_pane.__ul; |
| | | |
| | | // remove all search results or add to existing list if parallel search |
| | | if (reqid && this.ksearch_pane.data('reqid') == reqid) { |
| | | maxlen -= ul.childNodes.length; |
| | | } |
| | | else { |
| | | this.ksearch_pane.data('reqid', reqid); |
| | | init = 1; |
| | | // reset content |
| | | ul.innerHTML = ''; |
| | | this.env.contacts = []; |
| | | // move the results pane right under the input box |
| | | var pos = $(this.ksearch_input).offset(); |
| | | this.ksearch_pane.css({ left:pos.left+'px', top:(pos.top + this.ksearch_input.offsetHeight)+'px', display: 'none'}); |
| | | } |
| | | |
| | | // add each result line to list |
| | | for (i=0; i < a_results.length; i++) { |
| | | text = typeof a_results[i] === 'object' ? a_results[i].name : a_results[i]; |
| | | // add each result line to list |
| | | if (results && results.length) { |
| | | for (i=0; i < results.length && maxlen > 0; i++) { |
| | | text = typeof results[i] === 'object' ? results[i].name : results[i]; |
| | | li = document.createElement('LI'); |
| | | li.innerHTML = text.replace(new RegExp('('+RegExp.escape(s_val)+')', 'ig'), '##$1%%').replace(/</g, '<').replace(/>/g, '>').replace(/##([^%]+)%%/g, '<b>$1</b>'); |
| | | li.innerHTML = text.replace(new RegExp('('+RegExp.escape(value)+')', 'ig'), '##$1%%').replace(/</g, '<').replace(/>/g, '>').replace(/##([^%]+)%%/g, '<b>$1</b>'); |
| | | li.onmouseover = function(){ ref.ksearch_select(this); }; |
| | | li.onmouseup = function(){ ref.ksearch_click(this) }; |
| | | li._rcm_id = i; |
| | | li._rcm_id = this.env.contacts.length + i; |
| | | ul.appendChild(li); |
| | | maxlen -= 1; |
| | | } |
| | | |
| | | // select the first |
| | | $(ul.firstChild).attr('id', 'rcmksearchSelected').addClass('selected'); |
| | | this.ksearch_selected = 0; |
| | | |
| | | // move the results pane right under the input box and make it visible |
| | | var pos = $(this.ksearch_input).offset(); |
| | | this.ksearch_pane.css({ left:pos.left+'px', top:(pos.top + this.ksearch_input.offsetHeight)+'px' }).show(); |
| | | } |
| | | // hide results pane |
| | | else |
| | | this.ksearch_hide(); |
| | | |
| | | if (ul.childNodes.length) { |
| | | this.ksearch_pane.show(); |
| | | // select the first |
| | | if (!this.env.contacts.length) { |
| | | $('li:first', ul).attr('id', 'rcmksearchSelected').addClass('selected'); |
| | | this.ksearch_selected = 0; |
| | | } |
| | | } |
| | | |
| | | if (results && results.length) |
| | | this.env.contacts = this.env.contacts.concat(results); |
| | | |
| | | // run next parallel search |
| | | if (data.id == reqid) { |
| | | data.num--; |
| | | if (maxlen > 0 && data.sources.length) { |
| | | var lock, xhr, source = data.sources.shift(); |
| | | if (source) { |
| | | lock = this.display_message(this.get_label('searching'), 'loading'); |
| | | xhr = this.http_post(data.action, '_search='+urlencode(value)+'&_id='+reqid |
| | | +'&_source='+urlencode(source), lock); |
| | | |
| | | this.ksearch_data.locks.push(lock); |
| | | this.ksearch_data.requests.push(xhr); |
| | | } |
| | | } |
| | | else if (!maxlen) { |
| | | if (!this.ksearch_msg) |
| | | this.ksearch_msg = this.display_message(this.get_label('autocompletemore')); |
| | | // abort pending searches |
| | | this.ksearch_abort(); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | this.ksearch_click = function(node) |
| | |
| | | if (this.ksearch_timer) |
| | | clearTimeout(this.ksearch_timer); |
| | | |
| | | this.ksearch_value = ''; |
| | | this.ksearch_input = null; |
| | | this.ksearch_hide(); |
| | | }; |
| | | |
| | | |
| | | this.ksearch_hide = function() |
| | | { |
| | | this.ksearch_selected = null; |
| | | this.ksearch_value = ''; |
| | | |
| | | if (this.ksearch_pane) |
| | | this.ksearch_pane.hide(); |
| | | }; |
| | | |
| | | this.ksearch_destroy(); |
| | | }; |
| | | |
| | | // Clears autocomplete data/requests |
| | | this.ksearch_destroy = function() |
| | | { |
| | | this.ksearch_abort(); |
| | | |
| | | if (this.ksearch_info) |
| | | this.hide_message(this.ksearch_info); |
| | | |
| | | if (this.ksearch_msg) |
| | | this.hide_message(this.ksearch_msg); |
| | | |
| | | this.ksearch_data = null; |
| | | this.ksearch_info = null; |
| | | this.ksearch_msg = null; |
| | | } |
| | | |
| | | // Aborts pending autocomplete requests |
| | | this.ksearch_abort = function() |
| | | { |
| | | var i, len, ac = this.ksearch_data; |
| | | |
| | | if (!ac) |
| | | return; |
| | | |
| | | for (i=0, len=ac.locks.length; i<len; i++) |
| | | this.abort_request({request: ac.requests[i], lock: ac.locks[i]}); |
| | | }; |
| | | |
| | | |
| | | /*********************************************************/ |
| | |
| | | } |
| | | } |
| | | |
| | | this.enable_command('compose', list.selection.length > 0); |
| | | this.enable_command('compose', this.env.group || list.selection.length > 0); |
| | | this.enable_command('edit', id && writable); |
| | | this.enable_command('delete', list.selection.length && writable); |
| | | |
| | |
| | | |
| | | this.list_contacts = function(src, group, page) |
| | | { |
| | | var add_url = '', |
| | | var folder, add_url = '', |
| | | target = window; |
| | | |
| | | if (!src) |
| | |
| | | else if (group != this.env.group) |
| | | page = this.env.current_page = 1; |
| | | |
| | | this.select_folder((group ? 'G'+src+group : src), (this.env.group ? 'G'+this.env.source+this.env.group : this.env.source)); |
| | | if (this.env.search_id) |
| | | folder = 'S'+this.env.search_id; |
| | | else |
| | | folder = group ? 'G'+src+group : src; |
| | | |
| | | this.select_folder(folder); |
| | | |
| | | this.env.source = src; |
| | | this.env.group = group; |
| | |
| | | if (group) |
| | | url += '&_gid='+group; |
| | | |
| | | // also send search request to get the right messages |
| | | if (this.env.search_request) |
| | | // also send search request to get the right messages |
| | | if (this.env.search_request) |
| | | url += '&_search='+this.env.search_request; |
| | | |
| | | this.http_request('list', url, lock); |
| | |
| | | { |
| | | this.contact_list.clear(true); |
| | | this.show_contentframe(false); |
| | | this.enable_command('delete', 'compose', false); |
| | | this.enable_command('delete', false); |
| | | this.enable_command('compose', this.env.group ? true : false); |
| | | }; |
| | | |
| | | // load contact record |
| | |
| | | add_url = '&_framed=1'; |
| | | target = window.frames[this.env.contentframe]; |
| | | this.show_contentframe(true); |
| | | |
| | | // load dummy content |
| | | if (!cid) { |
| | | // unselect selected row(s) |
| | | this.contact_list.clear_selection(); |
| | | this.enable_command('delete', 'compose', false); |
| | | } |
| | | } |
| | | else if (framed) |
| | | return false; |
| | |
| | | if (this.env.group) |
| | | add_url += '&_gid='+urlencode(this.env.group); |
| | | |
| | | this.set_busy(true); |
| | | this.location_href(this.env.comm_path+'&_action='+action+'&_source='+urlencode(this.env.source)+'&_cid='+urlencode(cid) + add_url, target); |
| | | this.location_href(this.env.comm_path+'&_action='+action |
| | | +'&_source='+urlencode(this.env.source) |
| | | +'&_cid='+urlencode(cid) + add_url, target, true); |
| | | } |
| | | return true; |
| | | }; |
| | | |
| | | // add/delete member to/from the group |
| | | this.group_member_change = function(what, cid, source, gid) |
| | | { |
| | | what = what == 'add' ? 'add' : 'del'; |
| | | var lock = this.display_message(this.get_label(what == 'add' ? 'addingmember' : 'removingmember'), 'loading'); |
| | | |
| | | this.http_post('group-'+what+'members', '_cid='+urlencode(cid) |
| | | + '&_source='+urlencode(source) |
| | | + '&_gid='+urlencode(gid), lock); |
| | | }; |
| | | |
| | | // copy a contact to the specified target (group or directory) |
| | |
| | | if (!cid) |
| | | cid = this.contact_list.get_selection().join(','); |
| | | |
| | | if (to.type == 'group' && to.source == this.env.source) { |
| | | this.http_post('group-addmembers', '_cid='+urlencode(cid) |
| | | + '&_source='+urlencode(this.env.source) |
| | | + '&_gid='+urlencode(to.id)); |
| | | } |
| | | if (to.type == 'group' && to.source == this.env.source) |
| | | this.group_member_change('add', cid, to.source, to.id); |
| | | else if (to.type == 'group' && !this.env.address_sources[to.source].readonly) { |
| | | var lock = this.display_message(this.get_label('copyingcontact'), 'loading'); |
| | | this.http_post('copy', '_cid='+urlencode(cid) |
| | | + '&_source='+urlencode(this.env.source) |
| | | + '&_to='+urlencode(to.source) |
| | | + '&_togid='+urlencode(to.id) |
| | | + (this.env.group ? '&_gid='+urlencode(this.env.group) : '')); |
| | | + (this.env.group ? '&_gid='+urlencode(this.env.group) : ''), lock); |
| | | } |
| | | else if (to.id != this.env.source && cid && this.env.address_sources[to.id] && !this.env.address_sources[to.id].readonly) { |
| | | var lock = this.display_message(this.get_label('copyingcontact'), 'loading'); |
| | | this.http_post('copy', '_cid='+urlencode(cid) |
| | | + '&_source='+urlencode(this.env.source) |
| | | + '&_to='+urlencode(to.id) |
| | | + (this.env.group ? '&_gid='+urlencode(this.env.group) : '')); |
| | | + (this.env.group ? '&_gid='+urlencode(this.env.group) : ''), lock); |
| | | } |
| | | }; |
| | | |
| | | this.delete_contacts = function() |
| | | { |
| | | // exit if no mailbox specified or if selection is empty |
| | | var selection = this.contact_list.get_selection(); |
| | | if (!(selection.length || this.env.cid) || !confirm(this.get_label('deletecontactconfirm'))) |
| | | var selection = this.contact_list.get_selection(), |
| | | undelete = this.env.address_sources[this.env.source].undelete; |
| | | |
| | | if (!(selection.length || this.env.cid) || (!undelete && !confirm(this.get_label('deletecontactconfirm')))) |
| | | return; |
| | | |
| | | var id, n, a_cids = [], qs = ''; |
| | |
| | | qs += '&_search='+this.env.search_request; |
| | | |
| | | // send request to server |
| | | this.http_post('delete', '_cid='+urlencode(a_cids.join(','))+'&_source='+urlencode(this.env.source)+'&_from='+(this.env.action ? this.env.action : '')+qs); |
| | | this.http_post('delete', '_cid='+urlencode(a_cids.join(',')) |
| | | +'&_source='+urlencode(this.env.source) |
| | | +'&_from='+(this.env.action ? this.env.action : '')+qs, |
| | | this.display_message(this.get_label('contactdeleting'), 'loading')); |
| | | |
| | | return true; |
| | | }; |
| | | |
| | | // update a contact record in the list |
| | | this.update_contact_row = function(cid, cols_arr, newcid) |
| | | this.update_contact_row = function(cid, cols_arr, newcid, source) |
| | | { |
| | | var c, row, list = this.contact_list; |
| | | |
| | | cid = String(cid).replace(this.identifier_expr, '_'); |
| | | |
| | | // when in searching mode, concat cid with the source name |
| | | if (!list.rows[cid]) { |
| | | cid = cid+'-'+source; |
| | | if (newcid) |
| | | newcid = newcid+'-'+source; |
| | | } |
| | | |
| | | if (list.rows[cid] && (row = list.rows[cid].obj)) { |
| | | for (c=0; c<cols_arr.length; c++) |
| | |
| | | // add row to contacts list |
| | | this.add_contact_row = function(cid, cols, select) |
| | | { |
| | | if (!this.gui_objects.contactslist || !this.gui_objects.contactslist.tBodies[0]) |
| | | if (!this.gui_objects.contactslist) |
| | | return false; |
| | | |
| | | var tbody = this.gui_objects.contactslist.tBodies[0], |
| | | rowcount = tbody.rows.length, |
| | | even = rowcount%2, |
| | | var c, list = this.contact_list, |
| | | row = document.createElement('tr'); |
| | | |
| | | row.id = 'rcmrow'+String(cid).replace(this.identifier_expr, '_'); |
| | | row.className = 'contact '+(even ? 'even' : 'odd'); |
| | | row.className = 'contact'; |
| | | |
| | | if (this.contact_list.in_selection(cid)) |
| | | if (list.in_selection(cid)) |
| | | row.className += ' selected'; |
| | | |
| | | // add each submitted col |
| | | for (var c in cols) { |
| | | for (c in cols) { |
| | | col = document.createElement('td'); |
| | | col.className = String(c).toLowerCase(); |
| | | col.innerHTML = cols[c]; |
| | | row.appendChild(col); |
| | | } |
| | | |
| | | this.contact_list.insert_row(row); |
| | | list.insert_row(row); |
| | | |
| | | this.enable_command('export', (this.contact_list.rowcount > 0)); |
| | | this.enable_command('export', list.rowcount > 0); |
| | | }; |
| | | |
| | | this.init_contact_form = function() |
| | |
| | | this.selectedIndex = 0; |
| | | }); |
| | | |
| | | // enable date pickers on date fields |
| | | if ($.datepicker && this.env.date_format) { |
| | | $.datepicker.setDefaults({ |
| | | dateFormat: this.env.date_format, |
| | | changeMonth: true, |
| | | changeYear: true, |
| | | yearRange: '-100:+10', |
| | | showOtherMonths: true, |
| | | selectOtherMonths: true, |
| | | monthNamesShort: this.env.month_names, |
| | | onSelect: function(dateText) { $(this).focus().val(dateText) } |
| | | }); |
| | | $('input.datepicker').datepicker(); |
| | | } |
| | | |
| | | $("input[type='text']:visible").first().focus(); |
| | | }; |
| | | |
| | | this.group_create = function() |
| | | { |
| | | if (!this.gui_objects.folderlist || !this.env.address_sources[this.env.source].groups) |
| | | return; |
| | | |
| | | if (!this.name_input) { |
| | | this.name_input = $('<input>').attr('type', 'text'); |
| | | this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); }); |
| | | this.name_input_li = $('<li>').addClass('contactgroup').append(this.name_input); |
| | | |
| | | var li = this.get_folder_li(this.env.source) |
| | | this.name_input_li.insertAfter(li); |
| | | } |
| | | |
| | | this.name_input.select().focus(); |
| | | this.add_input_row('contactgroup'); |
| | | }; |
| | | |
| | | this.group_rename = function() |
| | |
| | | |
| | | this.group_delete = function() |
| | | { |
| | | if (this.env.group) |
| | | this.http_post('group-delete', '_source='+urlencode(this.env.source)+'&_gid='+urlencode(this.env.group), true); |
| | | if (this.env.group && confirm(this.get_label('deletegroupconfirm'))) { |
| | | var lock = this.set_busy(true, 'groupdeleting'); |
| | | this.http_post('group-delete', '_source='+urlencode(this.env.source)+'&_gid='+urlencode(this.env.group), lock); |
| | | } |
| | | }; |
| | | |
| | | // callback from server upon group-delete command |
| | |
| | | this.list_contacts(prop.source, 0); |
| | | }; |
| | | |
| | | // @TODO: maybe it would be better to use popup instead of inserting input to the list? |
| | | this.add_input_row = function(type) |
| | | { |
| | | if (!this.gui_objects.folderlist) |
| | | return; |
| | | |
| | | if (!this.name_input) { |
| | | this.name_input = $('<input>').attr('type', 'text').data('tt', type); |
| | | 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) : this.get_folder_li(this.env.source); |
| | | this.name_input_li.insertAfter(li); |
| | | } |
| | | |
| | | this.name_input.select().focus(); |
| | | }; |
| | | |
| | | // handler for keyboard events on the input field |
| | | this.add_input_keydown = function(e) |
| | | { |
| | | var key = rcube_event.get_keycode(e); |
| | | var key = rcube_event.get_keycode(e), |
| | | input = $(e.target), itype = input.data('tt'); |
| | | |
| | | // enter |
| | | if (key == 13) { |
| | | var newname = this.name_input.val(); |
| | | var newname = input.val(); |
| | | |
| | | if (newname) { |
| | | var lock = this.set_busy(true, 'loading'); |
| | | if (this.env.group_renaming) |
| | | |
| | | if (itype == 'contactsearch') |
| | | this.http_post('search-create', '_search='+urlencode(this.env.search_request)+'&_name='+urlencode(newname), lock); |
| | | else if (this.env.group_renaming) |
| | | this.http_post('group-rename', '_source='+urlencode(this.env.source)+'&_gid='+urlencode(this.env.group)+'&_name='+urlencode(newname), lock); |
| | | else |
| | | this.http_post('group-create', '_source='+urlencode(this.env.source)+'&_name='+urlencode(newname), lock); |
| | |
| | | this.reset_add_input(); |
| | | |
| | | prop.type = 'group'; |
| | | var key = 'G'+prop.source+prop.id; |
| | | this.env.contactfolders[key] = this.env.contactgroups[key] = prop; |
| | | var key = 'G'+prop.source+prop.id, |
| | | link = $('<a>').attr('href', '#') |
| | | .attr('rel', prop.source+':'+prop.id) |
| | | .click(function() { return rcmail.command('listgroup', prop, this); }) |
| | | .html(prop.name), |
| | | li = $('<li>').attr({id: 'rcmli'+key.replace(this.identifier_expr, '_'), 'class': 'contactgroup'}) |
| | | .append(link); |
| | | |
| | | var link = $('<a>').attr('href', '#') |
| | | .attr('rel', prop.source+':'+prop.id) |
| | | .bind('click', function() { return rcmail.command('listgroup', prop, this);}) |
| | | .html(prop.name); |
| | | var li = $('<li>').attr('id', 'rcmli'+key.replace(this.identifier_expr, '_')) |
| | | .addClass('contactgroup') |
| | | .append(link) |
| | | .insertAfter(this.get_folder_li(prop.source)); |
| | | this.env.contactfolders[key] = this.env.contactgroups[key] = prop; |
| | | this.add_contact_group_row(prop, li); |
| | | |
| | | this.triggerEvent('group_insert', { id:prop.id, source:prop.source, name:prop.name, li:li[0] }); |
| | | }; |
| | |
| | | |
| | | // group ID has changed, replace link node and identifiers |
| | | if (li && prop.newid) { |
| | | var newkey = 'G'+prop.source+prop.newid; |
| | | var newkey = 'G'+prop.source+prop.newid, |
| | | newprop = $.extend({}, prop);; |
| | | |
| | | li.id = String('rcmli'+newkey).replace(this.identifier_expr, '_'); |
| | | this.env.contactfolders[newkey] = this.env.contactfolders[key]; |
| | | this.env.contactfolders[newkey].id = prop.newid; |
| | | this.env.group = prop.newid; |
| | | |
| | | var newprop = $.extend({}, prop); |
| | | delete this.env.contactfolders[key]; |
| | | delete this.env.contactgroups[key]; |
| | | |
| | | newprop.id = prop.newid; |
| | | newprop.type = 'group'; |
| | | |
| | | link = $('<a>').attr('href', '#') |
| | | .attr('rel', prop.source+':'+prop.newid) |
| | | .bind('click', function() { return rcmail.command('listgroup', newprop, this);}) |
| | | .click(function() { return rcmail.command('listgroup', newprop, this); }) |
| | | .html(prop.name); |
| | | $(li).children().replaceWith(link); |
| | | } |
| | |
| | | link.innerHTML = prop.name; |
| | | |
| | | this.env.contactfolders[key].name = this.env.contactgroups[key].name = prop.name; |
| | | this.add_contact_group_row(prop, $(li), true); |
| | | |
| | | this.triggerEvent('group_update', { id:prop.id, source:prop.source, name:prop.name, li:li[0], newid:prop.newid }); |
| | | }; |
| | | |
| | | // add contact group row to the list, with sorting |
| | | this.add_contact_group_row = function(prop, li, reloc) |
| | | { |
| | | var row, name = prop.name.toUpperCase(), |
| | | sibling = this.get_folder_li(prop.source), |
| | | prefix = 'rcmliG'+(prop.source).replace(this.identifier_expr, '_'); |
| | | |
| | | // When renaming groups, we need to remove it from DOM and insert it in the proper place |
| | | if (reloc) { |
| | | row = li.clone(true); |
| | | li.remove(); |
| | | } |
| | | else |
| | | row = li; |
| | | |
| | | $('li[id^="'+prefix+'"]', this.gui_objects.folderlist).each(function(i, elem) { |
| | | if (name >= $(this).text().toUpperCase()) |
| | | sibling = elem; |
| | | else |
| | | return false; |
| | | }); |
| | | |
| | | row.insertAfter(sibling); |
| | | }; |
| | | |
| | | this.update_group_commands = function() |
| | | { |
| | | var source = this.env.source != '' ? this.env.address_sources[this.env.source] : null; |
| | | this.enable_command('group-create', (source && source.groups && !source.readonly)); |
| | | this.enable_command('group-rename', 'group-delete', (source && source.groups && this.env.group && !source.readonly)); |
| | | }; |
| | | |
| | | this.init_edit_field = function(col, elem) |
| | |
| | | |
| | | elem.focus(function(){ ref.focus_textfield(this); }) |
| | | .blur(function(){ ref.blur_textfield(this); }) |
| | | .each(function(){ this._placeholder = this.title = ref.env.coltypes[col].label; ref.blur_textfield(this); }); |
| | | .each(function(){ this._placeholder = this.title = (ref.env.coltypes[col].label || ''); ref.blur_textfield(this); }); |
| | | }; |
| | | |
| | | this.insert_edit_field = function(col, section, menu) |
| | |
| | | .appendTo(cell); |
| | | |
| | | this.init_edit_field(col, input); |
| | | |
| | | if (colprop.type == 'date' && $.datepicker) |
| | | input.datepicker(); |
| | | } |
| | | else if (colprop.type == 'composite') { |
| | | var childcol, cp, first, templ, cols = [], suffices = []; |
| | |
| | | this.set_photo_actions = function(id) |
| | | { |
| | | var n, buttons = this.buttons['upload-photo']; |
| | | for (n=0; n < buttons.length; n++) |
| | | for (n=0; buttons && n < buttons.length; n++) |
| | | $('#'+buttons[n].id).html(this.get_label(id == '-del-' ? 'addphoto' : 'replacephoto')); |
| | | |
| | | $('#ff_photo').val(id); |
| | |
| | | this.contact_list.clear_selection(); |
| | | } |
| | | |
| | | this.location_href(this.env.comm_path+'&_action=search'+add_url, target); |
| | | this.location_href(this.env.comm_path+'&_action=search'+add_url, target, true); |
| | | |
| | | return true; |
| | | }; |
| | |
| | | // unselect directory/group |
| | | this.unselect_directory = function() |
| | | { |
| | | if (this.env.address_sources.length > 1 || this.env.group != '') { |
| | | this.select_folder('', (this.env.group ? 'G'+this.env.source+this.env.group : this.env.source)); |
| | | this.env.group = ''; |
| | | this.env.source = ''; |
| | | this.select_folder(''); |
| | | this.enable_command('search-delete', false); |
| | | }; |
| | | |
| | | // callback for creating a new saved search record |
| | | this.insert_saved_search = function(name, id) |
| | | { |
| | | this.reset_add_input(); |
| | | |
| | | var key = 'S'+id, |
| | | link = $('<a>').attr('href', '#') |
| | | .attr('rel', id) |
| | | .click(function() { return rcmail.command('listsearch', id, this); }) |
| | | .html(name), |
| | | li = $('<li>').attr({id: 'rcmli'+key.replace(this.identifier_expr, '_'), 'class': 'contactsearch'}) |
| | | .append(link), |
| | | prop = {name:name, id:id, li:li[0]}; |
| | | |
| | | this.add_saved_search_row(prop, li); |
| | | this.select_folder('S'+id); |
| | | this.enable_command('search-delete', true); |
| | | this.env.search_id = id; |
| | | |
| | | this.triggerEvent('abook_search_insert', prop); |
| | | }; |
| | | |
| | | // add saved search row to the list, with sorting |
| | | this.add_saved_search_row = function(prop, li, reloc) |
| | | { |
| | | var row, sibling, name = prop.name.toUpperCase(); |
| | | |
| | | // When renaming groups, we need to remove it from DOM and insert it in the proper place |
| | | if (reloc) { |
| | | row = li.clone(true); |
| | | li.remove(); |
| | | } |
| | | else |
| | | row = li; |
| | | |
| | | $('li[class~="contactsearch"]', this.gui_objects.folderlist).each(function(i, elem) { |
| | | if (!sibling) |
| | | sibling = this.previousSibling; |
| | | |
| | | if (name >= $(this).text().toUpperCase()) |
| | | sibling = elem; |
| | | else |
| | | return false; |
| | | }); |
| | | |
| | | if (sibling) |
| | | row.insertAfter(sibling); |
| | | else |
| | | row.appendTo(this.gui_objects.folderlist); |
| | | }; |
| | | |
| | | // creates an input for saved search name |
| | | this.search_create = function() |
| | | { |
| | | this.add_input_row('contactsearch'); |
| | | }; |
| | | |
| | | this.search_delete = function() |
| | | { |
| | | if (this.env.search_request) { |
| | | var lock = this.set_busy(true, 'savedsearchdeleting'); |
| | | this.http_post('search-delete', '_sid='+urlencode(this.env.search_id), lock); |
| | | } |
| | | }; |
| | | |
| | | // callback from server upon search-delete command |
| | | this.remove_search_item = function(id) |
| | | { |
| | | var li, key = 'S'+id; |
| | | if ((li = this.get_folder_li(key))) { |
| | | this.triggerEvent('search_delete', { id:id, li:li }); |
| | | |
| | | li.parentNode.removeChild(li); |
| | | } |
| | | |
| | | this.env.search_id = null; |
| | | this.env.search_request = null; |
| | | this.list_contacts_clear(); |
| | | this.reset_qsearch(); |
| | | this.enable_command('search-delete', 'search-create', false); |
| | | }; |
| | | |
| | | this.listsearch = function(id) |
| | | { |
| | | var folder, lock = this.set_busy(true, 'searching'); |
| | | |
| | | if (this.contact_list) { |
| | | this.list_contacts_clear(); |
| | | } |
| | | |
| | | this.reset_qsearch(); |
| | | this.select_folder('S'+id); |
| | | |
| | | // reset vars |
| | | this.env.current_page = 1; |
| | | this.http_request('search', '_sid='+urlencode(id), lock); |
| | | }; |
| | | |
| | | |
| | |
| | | // preferences section select and load options frame |
| | | this.section_select = function(list) |
| | | { |
| | | var id = list.get_single_selection(); |
| | | var id = list.get_single_selection(), add_url = '', target = window; |
| | | |
| | | if (id) { |
| | | var add_url = '', target = window; |
| | | this.set_busy(true); |
| | | |
| | | if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) { |
| | | add_url = '&_framed=1'; |
| | | target = window.frames[this.env.contentframe]; |
| | | } |
| | | this.location_href(this.env.comm_path+'&_action=edit-prefs&_section='+id+add_url, target); |
| | | this.location_href(this.env.comm_path+'&_action=edit-prefs&_section='+id+add_url, target, true); |
| | | } |
| | | |
| | | return true; |
| | |
| | | row.obj.onmouseout = function() { p.unfocus_subscription(row.id); }; |
| | | }; |
| | | this.subscription_list.init(); |
| | | $('#mailboxroot') |
| | | .mouseover(function(){ p.focus_subscription(this.id); }) |
| | | .mouseout(function(){ p.unfocus_subscription(this.id); }) |
| | | }; |
| | | |
| | | this.focus_subscription = function(id) |
| | |
| | | |
| | | if (this.drag_active && this.env.mailbox && (row = document.getElementById(id))) |
| | | if (this.env.subscriptionrows[id] && |
| | | (folder = this.env.subscriptionrows[id][0])) { |
| | | (folder = this.env.subscriptionrows[id][0]) !== null |
| | | ) { |
| | | if (this.check_droptarget(folder) && |
| | | !this.env.subscriptionrows[this.get_folder_row_id(this.env.mailbox)][2] && |
| | | (folder != this.env.mailbox.replace(reg, '')) && |
| | | (!folder.match(new RegExp('^'+RegExp.escape(this.env.mailbox+this.env.delimiter))))) { |
| | | this.set_env('dstfolder', folder); |
| | | (!folder.match(new RegExp('^'+RegExp.escape(this.env.mailbox+this.env.delimiter)))) |
| | | ) { |
| | | this.env.dstfolder = folder; |
| | | $(row).addClass('droptarget'); |
| | | } |
| | | } |
| | | else if (this.env.mailbox.match(new RegExp(delim))) { |
| | | this.set_env('dstfolder', this.env.delimiter); |
| | | $(this.subscription_list.frame).addClass('droptarget'); |
| | | } |
| | | }; |
| | | |
| | |
| | | { |
| | | var row = $('#'+id); |
| | | |
| | | this.set_env('dstfolder', null); |
| | | this.env.dstfolder = null; |
| | | if (this.env.subscriptionrows[id] && row[0]) |
| | | row.removeClass('droptarget'); |
| | | else |
| | |
| | | if (list && (id = list.get_single_selection()) && |
| | | (folder = this.env.subscriptionrows['rcmrow'+id]) |
| | | ) { |
| | | this.set_env('mailbox', folder[0]); |
| | | this.env.mailbox = folder[0]; |
| | | this.show_folder(folder[0]); |
| | | this.enable_command('delete-folder', !folder[2]); |
| | | } |
| | |
| | | var delim = RegExp.escape(this.env.delimiter), |
| | | reg = RegExp('['+delim+']?[^'+delim+']+$'); |
| | | |
| | | if (this.env.mailbox && this.env.dstfolder && (this.env.dstfolder != this.env.mailbox) && |
| | | if (this.env.mailbox && this.env.dstfolder !== null && (this.env.dstfolder != this.env.mailbox) && |
| | | (this.env.dstfolder != this.env.mailbox.replace(reg, '')) |
| | | ) { |
| | | reg = new RegExp('[^'+delim+']*['+delim+']', 'g'); |
| | | var lock = this.set_busy(true, 'foldermoving'), |
| | | basename = this.env.mailbox.replace(reg, ''), |
| | | newname = this.env.dstfolder==this.env.delimiter ? basename : this.env.dstfolder+this.env.delimiter+basename; |
| | | var basename = this.env.mailbox.replace(reg, ''), |
| | | newname = this.env.dstfolder === '' ? basename : this.env.dstfolder+this.env.delimiter+basename; |
| | | |
| | | this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.mailbox)+'&_folder_newname='+urlencode(newname), lock); |
| | | if (newname != this.env.mailbox) { |
| | | this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.mailbox)+'&_folder_newname='+urlencode(newname), this.set_busy(true, 'foldermoving')); |
| | | this.subscription_list.draglayer.hide(); |
| | | } |
| | | } |
| | | this.drag_active = false; |
| | | this.unfocus_subscription(this.get_folder_row_id(this.env.dstfolder)); |
| | |
| | | }; |
| | | |
| | | // Add folder row to the table and initialize it |
| | | this.add_folder_row = function (name, display_name, protected, subscribed, skip_init, class_name) |
| | | this.add_folder_row = function (name, display_name, is_protected, subscribed, skip_init, class_name) |
| | | { |
| | | if (!this.gui_objects.subscriptionlist) |
| | | return false; |
| | | |
| | | var row, n, i, tmp, folders, len, list = [], slist = [], |
| | | var row, n, i, tmp, folders, rowid, list = [], slist = [], |
| | | tbody = this.gui_objects.subscriptionlist.tBodies[0], |
| | | refrow = $('tr', tbody).get(0), |
| | | refrow = $('tr', tbody).get(1), |
| | | id = 'rcmrow'+((new Date).getTime()); |
| | | |
| | | if (!refrow) { |
| | |
| | | |
| | | // update subscription checkbox |
| | | $('input[name="_subscribed[]"]', row).val(name) |
| | | .prop({checked: subscribed ? true : false, disabled: protected ? true : false}); |
| | | .prop({checked: subscribed ? true : false, disabled: is_protected ? true : false}); |
| | | |
| | | // add to folder/row-ID map |
| | | this.env.subscriptionrows[id] = [name, display_name, 0]; |
| | | |
| | | // sort folders, to find a place where to insert the row |
| | | folders = this.env.subscriptionrows; |
| | | folders = []; |
| | | $.each(this.env.subscriptionrows, function(k,v){ folders.push(v) }); |
| | | folders.sort(function(a,b){ return a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : 0) }); |
| | | |
| | | for (n in folders) { |
| | | // protected folder |
| | | if (folders[n][2]) { |
| | |
| | | tmp = null; |
| | | } |
| | | } |
| | | list.sort(); |
| | | // make sure protected folders (and their subs) are on top |
| | | list = slist.concat(list); |
| | | |
| | | // check if subfolder of a protected folder |
| | | for (n=0; n<slist.length; n++) { |
| | | if (name.indexOf(slist[n]+this.env.delimiter) == 0) |
| | | rowid = this.get_folder_row_id(slist[n]); |
| | | } |
| | | |
| | | // find folder position after sorting |
| | | for (n=0, len=list.length; n<len; n++) { |
| | | if (list[n] == name) |
| | | break; |
| | | for (n=0; !rowid && n<list.length; n++) { |
| | | if (n && list[n] == name) |
| | | rowid = this.get_folder_row_id(list[n-1]); |
| | | } |
| | | |
| | | // add row to the table |
| | | if (n && n < len) |
| | | $('#'+this.get_folder_row_id(list[n-1])).after(row); |
| | | if (rowid) |
| | | $('#'+rowid).after(row); |
| | | else |
| | | row.appendTo(tbody); |
| | | |
| | |
| | | }; |
| | | |
| | | // replace an existing table row with a new folder line (with subfolders) |
| | | this.replace_folder_row = function(oldfolder, newfolder, display_name, protected, class_name) |
| | | this.replace_folder_row = function(oldfolder, newfolder, display_name, is_protected, class_name) |
| | | { |
| | | if (!this.gui_objects.subscriptionlist) |
| | | return false; |
| | |
| | | |
| | | // replace an existing table row |
| | | this._remove_folder_row(id); |
| | | row = $(this.add_folder_row(newfolder, display_name, protected, subscribed, true, class_name)); |
| | | row = $(this.add_folder_row(newfolder, display_name, is_protected, subscribed, true, class_name)); |
| | | |
| | | // detect tree depth change |
| | | if (len = list.length) { |
| | |
| | | this.show_contentframe(true); |
| | | } |
| | | else { |
| | | if (!this.env.frame_lock) { |
| | | (parent.rcmail ? parent.rcmail : this).env.frame_lock = this.set_busy(true, 'loading'); |
| | | } |
| | | this.location_href(this.env.comm_path+url, target); |
| | | this.location_href(this.env.comm_path+url, target, true); |
| | | } |
| | | }; |
| | | |
| | |
| | | /********* GUI functionality *********/ |
| | | /*********************************************************/ |
| | | |
| | | var init_button = function(cmd, prop) |
| | | { |
| | | var elm = document.getElementById(prop.id); |
| | | if (!elm) |
| | | return; |
| | | |
| | | var preload = false; |
| | | if (prop.type == 'image') { |
| | | elm = elm.parentNode; |
| | | preload = true; |
| | | } |
| | | |
| | | elm._command = cmd; |
| | | elm._id = prop.id; |
| | | if (prop.sel) { |
| | | elm.onmousedown = function(e){ return rcmail.button_sel(this._command, this._id); }; |
| | | elm.onmouseup = function(e){ return rcmail.button_out(this._command, this._id); }; |
| | | if (preload) |
| | | new Image().src = prop.sel; |
| | | } |
| | | if (prop.over) { |
| | | elm.onmouseover = function(e){ return rcmail.button_over(this._command, this._id); }; |
| | | elm.onmouseout = function(e){ return rcmail.button_out(this._command, this._id); }; |
| | | if (preload) |
| | | new Image().src = prop.over; |
| | | } |
| | | }; |
| | | |
| | | // enable/disable buttons for page shifting |
| | | this.set_page_buttons = function() |
| | | { |
| | |
| | | continue; |
| | | |
| | | for (var i=0; i< this.buttons[cmd].length; i++) { |
| | | var prop = this.buttons[cmd][i]; |
| | | var elm = document.getElementById(prop.id); |
| | | if (!elm) |
| | | continue; |
| | | |
| | | var preload = false; |
| | | if (prop.type == 'image') { |
| | | elm = elm.parentNode; |
| | | preload = true; |
| | | } |
| | | |
| | | elm._command = cmd; |
| | | elm._id = prop.id; |
| | | if (prop.sel) { |
| | | elm.onmousedown = function(e){ return rcmail.button_sel(this._command, this._id); }; |
| | | elm.onmouseup = function(e){ return rcmail.button_out(this._command, this._id); }; |
| | | if (preload) |
| | | new Image().src = prop.sel; |
| | | } |
| | | if (prop.over) { |
| | | elm.onmouseover = function(e){ return rcmail.button_over(this._command, this._id); }; |
| | | elm.onmouseout = function(e){ return rcmail.button_out(this._command, this._id); }; |
| | | if (preload) |
| | | new Image().src = prop.over; |
| | | } |
| | | init_button(cmd, this.buttons[cmd][i]); |
| | | } |
| | | } |
| | | }; |
| | |
| | | if (elem._placeholder && (!$elem.val() || $elem.val() == elem._placeholder)) |
| | | $elem.addClass('placeholder').attr('spellcheck', false).val(elem._placeholder); |
| | | }; |
| | | |
| | | |
| | | // write to the document/window title |
| | | this.set_pagetitle = function(title) |
| | | { |
| | |
| | | }; |
| | | |
| | | // display a system message, list of types in common.css (below #message definition) |
| | | this.display_message = function(msg, type) |
| | | this.display_message = function(msg, type, timeout) |
| | | { |
| | | // pass command to parent window |
| | | if (this.is_framed()) |
| | | return parent.rcmail.display_message(msg, type); |
| | | return parent.rcmail.display_message(msg, type, timeout); |
| | | |
| | | if (!this.gui_objects.message) { |
| | | // save message in order to display after page loaded |
| | | if (type != 'loading') |
| | | this.pending_message = new Array(msg, type); |
| | | this.pending_message = new Array(msg, type, timeout); |
| | | return false; |
| | | } |
| | | |
| | | type = type ? type : 'notice'; |
| | | |
| | | var ref = this, |
| | | key = msg, |
| | | key = String(msg).replace(this.identifier_expr, '_'), |
| | | date = new Date(), |
| | | id = type + date.getTime(), |
| | | id = type + date.getTime(); |
| | | |
| | | if (!timeout) |
| | | timeout = this.message_time * (type == 'error' || type == 'warning' ? 2 : 1); |
| | | |
| | | |
| | | if (type == 'loading') { |
| | | key = 'loading'; |
| | | timeout = this.env.request_timeout * 1000; |
| | |
| | | obj.click(function() { return ref.hide_message(obj); }); |
| | | } |
| | | |
| | | window.setTimeout(function() { ref.hide_message(id, type == 'loading'); }, timeout); |
| | | if (timeout > 0) |
| | | window.setTimeout(function() { ref.hide_message(id, type == 'loading'); }, timeout); |
| | | return id; |
| | | }; |
| | | |
| | |
| | | }; |
| | | |
| | | // mark a mailbox as selected and set environment variable |
| | | this.select_folder = function(name, old, prefix) |
| | | this.select_folder = function(name, prefix) |
| | | { |
| | | if (this.gui_objects.folderlist) { |
| | | var current_li, target_li; |
| | | |
| | | if ((current_li = this.get_folder_li(old, prefix))) { |
| | | $(current_li).removeClass('selected').addClass('unfocused'); |
| | | if ((current_li = $('li.selected', this.gui_objects.folderlist))) { |
| | | current_li.removeClass('selected').addClass('unfocused'); |
| | | } |
| | | if ((target_li = this.get_folder_li(name, prefix))) { |
| | | $(target_li).removeClass('unfocused').addClass('selected'); |
| | | } |
| | | |
| | | // trigger event hook |
| | | this.triggerEvent('selectfolder', { folder:name, old:old, prefix:prefix }); |
| | | this.triggerEvent('selectfolder', { folder:name, prefix:prefix }); |
| | | } |
| | | }; |
| | | |
| | |
| | | this.env.status_col = null; |
| | | |
| | | if ((n = $.inArray('subject', this.env.coltypes)) >= 0) { |
| | | this.set_env('subject_col', n); |
| | | this.env.subject_col = n; |
| | | if (list) |
| | | list.subject_col = n; |
| | | } |
| | | if ((n = $.inArray('flag', this.env.coltypes)) >= 0) |
| | | this.set_env('flagged_col', n); |
| | | this.env.flagged_col = n; |
| | | if ((n = $.inArray('status', this.env.coltypes)) >= 0) |
| | | this.set_env('status_col', n); |
| | | this.env.status_col = n; |
| | | |
| | | if (list) |
| | | list.init_header(); |
| | | }; |
| | | |
| | | // replace content of row count display |
| | | this.set_rowcount = function(text) |
| | | this.set_rowcount = function(text, mbox) |
| | | { |
| | | // #1487752 |
| | | if (mbox && mbox != this.env.mailbox) |
| | | return false; |
| | | |
| | | $(this.gui_objects.countdisplay).html(text); |
| | | |
| | | // update page navigation buttons |
| | |
| | | url = '?_task=utils&_action=html2text', |
| | | lock = this.set_busy(true, 'converting'); |
| | | |
| | | console.log('HTTP POST: ' + url); |
| | | this.log('HTTP POST: ' + url); |
| | | |
| | | $.ajax({ type: 'POST', url: url, data: htmlText, contentType: 'application/octet-stream', |
| | | error: function(o, status, err) { rcmail.http_error(o, status, err, lock); }, |
| | | success: function(data) { rcmail.set_busy(false, null, lock); $(document.getElementById(id)).val(data); console.log(data); } |
| | | success: function(data) { rcmail.set_busy(false, null, lock); $(document.getElementById(id)).val(data); rcmail.log(data); } |
| | | }); |
| | | }; |
| | | |
| | |
| | | /********************************************************/ |
| | | /********* remote request methods *********/ |
| | | /********************************************************/ |
| | | |
| | | |
| | | // compose a valid url with the given parameters |
| | | this.url = function(action, query) |
| | | { |
| | |
| | | var base = this.env.comm_path; |
| | | |
| | | // overwrite task name |
| | | if (query._action.match(/([a-z]+)\/([a-z-_]+)/)) { |
| | | if (query._action.match(/([a-z]+)\/([a-z0-9-_.]+)/)) { |
| | | query._action = RegExp.$2; |
| | | base = base.replace(/\_task=[a-z]+/, '_task='+RegExp.$1); |
| | | } |
| | |
| | | this.redirect(this.url(action, query)); |
| | | }; |
| | | |
| | | this.location_href = function(url, target) |
| | | this.location_href = function(url, target, frame) |
| | | { |
| | | if (frame) |
| | | this.lock_frame(); |
| | | |
| | | // simulate real link click to force IE to send referer header |
| | | if (bw.ie && target == window) |
| | | $('<a>').attr('href', url).appendTo(document.body).get(0).click(); |
| | |
| | | url += '&_remote=1'; |
| | | |
| | | // send request |
| | | console.log('HTTP GET: ' + url); |
| | | $.ajax({ |
| | | this.log('HTTP GET: ' + url); |
| | | |
| | | return $.ajax({ |
| | | type: 'GET', url: url, data: { _unlock:(lock?lock:0) }, dataType: 'json', |
| | | success: function(data){ ref.http_response(data); }, |
| | | error: function(o, status, err) { rcmail.http_error(o, status, err, lock); } |
| | |
| | | } |
| | | |
| | | // send request |
| | | console.log('HTTP POST: ' + url); |
| | | $.ajax({ |
| | | this.log('HTTP POST: ' + url); |
| | | |
| | | return $.ajax({ |
| | | type: 'POST', url: url, data: postdata, dataType: 'json', |
| | | success: function(data){ ref.http_response(data); }, |
| | | error: function(o, status, err) { rcmail.http_error(o, status, err, lock); } |
| | | }); |
| | | }; |
| | | |
| | | // aborts ajax request |
| | | this.abort_request = function(r) |
| | | { |
| | | if (r.request) |
| | | r.request.abort(); |
| | | if (r.lock) |
| | | this.set_busy(false, null, r.lock); |
| | | }; |
| | | |
| | | // handle HTTP response |
| | |
| | | |
| | | // if we get javascript code from server -> execute it |
| | | if (response.exec) { |
| | | console.log(response.exec); |
| | | this.log(response.exec); |
| | | eval(response.exec); |
| | | } |
| | | |
| | |
| | | case 'check-recent': |
| | | case 'getunread': |
| | | case 'search': |
| | | this.env.qsearch = null; |
| | | case 'list': |
| | | if (this.task == 'mail') { |
| | | this.enable_command('show', 'expunge', 'select-all', 'select-none', 'sort', (this.env.messagecount > 0)); |
| | |
| | | this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); |
| | | |
| | | if (response.action == 'list' || response.action == 'search') { |
| | | var source = this.env.source != '' ? this.env.address_sources[this.env.source] : null; |
| | | this.enable_command('group-create', (source && source.groups && !source.readonly)); |
| | | this.enable_command('group-rename', 'group-delete', (source && source.groups && this.env.group && !source.readonly)); |
| | | this.enable_command('search-create', this.env.source == ''); |
| | | this.enable_command('search-delete', this.env.search_id); |
| | | this.update_group_commands(); |
| | | this.triggerEvent('listupdate', { folder:this.env.source, rowcount:this.contact_list.rowcount }); |
| | | } |
| | | } |
| | |
| | | var ts = new Date().getTime(), |
| | | frame_name = 'rcmupload'+ts; |
| | | |
| | | // upload progress support |
| | | if (this.env.upload_progress_name) { |
| | | var fname = this.env.upload_progress_name, |
| | | field = $('input[name='+fname+']', form); |
| | | |
| | | if (!field.length) { |
| | | field = $('<input>').attr({type: 'hidden', name: fname}); |
| | | field.prependTo(form); |
| | | } |
| | | |
| | | field.val(ts); |
| | | } |
| | | |
| | | // have to do it this way for IE |
| | | // otherwise the form will be posted to a new window |
| | | if (document.all) { |
| | |
| | | // handle upload errors, parsing iframe content in onload |
| | | $(frame_name).bind('load', {ts:ts}, onload); |
| | | |
| | | form.target = frame_name; |
| | | form.action = this.url(action, { _id:this.env.compose_id||'', _uploadid:ts }); |
| | | form.setAttribute('method', 'POST'); |
| | | form.setAttribute('enctype', 'multipart/form-data'); |
| | | form.submit(); |
| | | $(form).attr({ |
| | | target: frame_name, |
| | | action: this.url(action, { _id:this.env.compose_id||'', _uploadid:ts }), |
| | | method: 'POST'}) |
| | | .attr(form.encoding ? 'encoding' : 'enctype', 'multipart/form-data') |
| | | .submit(); |
| | | |
| | | return frame_name; |
| | | }; |
| | |
| | | if (this.env.keep_alive && !this.env.framed && this.task == 'mail' && this.gui_objects.mailboxlist) |
| | | this._int = setInterval(function(){ ref.check_for_recent(false); }, this.env.keep_alive * 1000); |
| | | else if (this.env.keep_alive && !this.env.framed && this.task != 'login' && this.env.action != 'print') |
| | | this._int = setInterval(function(){ ref.http_request('keep-alive'); }, this.env.keep_alive * 1000); |
| | | this._int = setInterval(function(){ ref.keep_alive(); }, this.env.keep_alive * 1000); |
| | | }; |
| | | |
| | | // sends keep-alive signal |
| | | this.keep_alive = function() |
| | | { |
| | | if (!this.busy) |
| | | this.http_request('keep-alive'); |
| | | }; |
| | | |
| | | // sends request to check for recent messages |
| | |
| | | |
| | | if (elm.type == 'hidden') |
| | | continue; |
| | | |
| | | // remember which elem was disabled before lock |
| | | if (lock && elm.disabled) |
| | | this.disabled_form_elements.push(elm); |
| | | else if (lock || $.inArray(elm, this.disabled_form_elements)<0) |
| | | // check this.disabled_form_elements before inArray() as a workaround for FF5 bug |
| | | // http://bugs.jquery.com/ticket/9873 |
| | | else if (lock || (this.disabled_form_elements && $.inArray(elm, this.disabled_form_elements)<0)) |
| | | elm.disabled = lock; |
| | | } |
| | | }; |
| | |
| | | } |
| | | }; |
| | | |
| | | rcube_webmail.long_subject_title_ie = function(elem, indent) |
| | | { |
| | | if (!elem.title) { |
| | | var $elem = $(elem), |
| | | txt = $.trim($elem.text()), |
| | | tmp = $('<span>').text(txt) |
| | | .css({'position': 'absolute', 'float': 'left', 'visibility': 'hidden', |
| | | 'font-size': $elem.css('font-size'), 'font-weight': $elem.css('font-weight')}) |
| | | .appendTo($('body')), |
| | | w = tmp.width(); |
| | | |
| | | tmp.remove(); |
| | | if (w + indent * 15 > $elem.width()) |
| | | elem.title = txt; |
| | | } |
| | | }; |
| | | |
| | | // copy event engine prototype |
| | | rcube_webmail.prototype.addEventListener = rcube_event_engine.prototype.addEventListener; |
| | | rcube_webmail.prototype.removeEventListener = rcube_event_engine.prototype.removeEventListener; |