| | |
| | | request_timeout: 180, // seconds |
| | | draft_autosave: 0, // seconds |
| | | comm_path: './', |
| | | blankpage: 'program/resources/blank.gif', |
| | | recipients_separator: ',', |
| | | recipients_delimiter: ', ', |
| | | popup_width: 1150, |
| | |
| | | this.goto_url('error', '_code=0x199'); |
| | | return; |
| | | } |
| | | |
| | | if (!this.env.blankpage) |
| | | this.env.blankpage = this.assets_path('program/resources/blank.gif'); |
| | | |
| | | // find all registered gui containers |
| | | for (n in this.gui_containers) |
| | |
| | | this.enable_command('download', 'print', true); |
| | | // show printing dialog |
| | | else if (this.env.action == 'print' && this.env.uid) { |
| | | if (bw.safari) |
| | | setTimeout('window.print()', 10); |
| | | else |
| | | window.print(); |
| | | this.print_dialog(); |
| | | } |
| | | |
| | | // get unread count for each mailbox |
| | |
| | | this.enable_command('save', true); |
| | | if (this.env.action == 'add' || this.env.action == 'edit' || this.env.action == 'search') |
| | | this.init_contact_form(); |
| | | } |
| | | else if (this.env.action == 'print') { |
| | | this.print_dialog(); |
| | | } |
| | | |
| | | break; |
| | |
| | | |
| | | // show message |
| | | if (this.pending_message) |
| | | this.display_message(this.pending_message[0], this.pending_message[1], this.pending_message[2]); |
| | | this.display_message.apply(this, this.pending_message); |
| | | |
| | | // 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', |
| | | parent_focus: true, |
| | | id_encode: this.html_identifier_encode, |
| | | id_decode: this.html_identifier_decode, |
| | | check_droptarget: function(node) { return !node.virtual && ref.check_droptarget(node.id) } |
| | |
| | | this.treelist |
| | | .addEventListener('collapse', function(node) { ref.folder_collapsed(node) }) |
| | | .addEventListener('expand', function(node) { ref.folder_collapsed(node) }) |
| | | .addEventListener('beforeselect', function(node) { return !ref.busy; }) |
| | | .addEventListener('select', function(node) { ref.triggerEvent('selectfolder', { folder:node.id, prefix:'rcmli' }) }); |
| | | } |
| | | |
| | |
| | | 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) |
| | | if (this.busy && !(command == 'reset-search' && this.last_command == 'search')) |
| | | // do nothing if interface is locked by another command |
| | | // with exception for searching reset and menu |
| | | if (this.busy && !(command == 'reset-search' && this.last_command == 'search') && !command.match(/^menu-/)) |
| | | return false; |
| | | |
| | | // let the browser handle this click (shift/ctrl usually opens the link in a new window/tab) |
| | |
| | | |
| | | // check input before leaving compose step |
| | | if (this.task == 'mail' && this.env.action == 'compose' && $.inArray(command, this.env.compose_commands) < 0 && !this.env.server_error) { |
| | | if (this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning'))) |
| | | if (!this.env.is_sent && this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning'))) |
| | | return false; |
| | | |
| | | // remove copy from local storage if compose screen is left intentionally |
| | |
| | | |
| | | case 'list': |
| | | if (props && props != '') { |
| | | this.reset_qsearch(); |
| | | this.reset_qsearch(true); |
| | | } |
| | | if (this.env.action == 'compose' && this.env.extwin) { |
| | | window.close(); |
| | |
| | | else { |
| | | // reload form |
| | | if (props == 'reload') { |
| | | form.action += '?_reload=1'; |
| | | 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()) |
| | |
| | | url = {}; |
| | | |
| | | if (this.task == 'mail') { |
| | | url._mbox = this.env.mailbox; |
| | | url = {_mbox: this.env.mailbox, _search: this.env.search_request}; |
| | | if (props) |
| | | url._to = props; |
| | | // also send search request so we can go back to search result after message is sent |
| | | if (this.env.search_request) |
| | | url._search = this.env.search_request; |
| | | } |
| | | // modify url if we're in addressbook |
| | | else if (this.task == 'addressbook') { |
| | |
| | | break; |
| | | |
| | | case 'send': |
| | | if (!props.nocheck && !this.check_compose_input(command)) |
| | | if (!props.nocheck && !this.env.is_sent && !this.check_compose_input(command)) |
| | | break; |
| | | |
| | | // Reset the auto-save timer |
| | |
| | | case 'reply-list': |
| | | case 'reply': |
| | | if (uid = this.get_single_uid()) { |
| | | url = {_reply_uid: uid, _mbox: this.get_message_mailbox(uid)}; |
| | | url = {_reply_uid: uid, _mbox: this.get_message_mailbox(uid), _search: this.env.search_request}; |
| | | if (command == 'reply-all') |
| | | // do reply-list, when list is detected and popup menu wasn't used |
| | | url._all = (!props && this.env.reply_all_mode == 1 && this.commands['reply-list'] ? 'list' : 'all'); |
| | |
| | | break; |
| | | |
| | | case 'print': |
| | | if (this.env.action == 'get') { |
| | | if (this.task == 'addressbook') { |
| | | if (uid = this.contact_list.get_single_selection()) { |
| | | url = '&_action=print&_cid=' + uid; |
| | | if (this.env.source) |
| | | url += '&_source=' + urlencode(this.env.source); |
| | | this.open_window(this.env.comm_path + url, true, true); |
| | | } |
| | | } |
| | | else if (this.env.action == 'get') { |
| | | this.gui_objects.messagepartframe.contentWindow.print(); |
| | | } |
| | | else if (uid = this.get_single_uid()) { |
| | |
| | | case 'reset-search': |
| | | var n, s = this.env.search_request || this.env.qsearch; |
| | | |
| | | this.reset_qsearch(); |
| | | this.reset_qsearch(true); |
| | | this.select_all_mode = false; |
| | | |
| | | if (s && this.env.action == 'compose') { |
| | |
| | | |
| | | if (task == 'mail') |
| | | url += '&_mbox=INBOX'; |
| | | else if (task == 'logout' && !this.env.server_error) |
| | | else if (task == 'logout' && !this.env.server_error) { |
| | | url += '&_token=' + this.env.request_token; |
| | | this.clear_compose_data(); |
| | | } |
| | | |
| | | this.redirect(url); |
| | | }; |
| | |
| | | if (!url) |
| | | url = this.env.comm_path; |
| | | |
| | | return url.replace(/_task=[a-z0-9_-]+/i, '_task='+task); |
| | | if (url.match(/[?&]_task=[a-zA-Z0-9_-]+/)) |
| | | return url.replace(/_task=[a-zA-Z0-9_-]+/, '_task=' + task); |
| | | else |
| | | return url.replace(/\?.*$/, '') + '?_task=' + task; |
| | | }; |
| | | |
| | | this.reload = function(delay) |
| | |
| | | |
| | | this.folder_collapsed = function(node) |
| | | { |
| | | var prefname = this.env.task == 'addressbook' ? 'collapsed_abooks' : 'collapsed_folders'; |
| | | var prefname = this.env.task == 'addressbook' ? 'collapsed_abooks' : 'collapsed_folders', |
| | | old = this.env[prefname]; |
| | | |
| | | if (node.collapsed) { |
| | | this.env[prefname] = this.env[prefname] + '&'+urlencode(node.id)+'&'; |
| | |
| | | } |
| | | |
| | | if (!this.drag_active) { |
| | | this.command('save-pref', { name: prefname, value: this.env[prefname] }); |
| | | if (old !== this.env[prefname]) |
| | | this.command('save-pref', { name: prefname, value: this.env[prefname] }); |
| | | |
| | | if (this.env.unread_counts) |
| | | this.set_unread_count_display(node.id, false); |
| | |
| | | } |
| | | skip = obj.data('parent'); |
| | | } |
| | | }, 10); |
| | | }, 10, e); |
| | | }; |
| | | |
| | | // global keypress event handler |
| | |
| | | // attach events |
| | | $.each(fn, function(i, f) { |
| | | row[i].onclick = function(e) { f(e); return rcube_event.cancel(e); }; |
| | | if (bw.touch) { |
| | | if (bw.touch && row[i].addEventListener) { |
| | | row[i].addEventListener('touchend', function(e) { |
| | | if (e.changedTouches.length == 1) { |
| | | f(e); |
| | |
| | | } |
| | | if (flags.forwarded) { |
| | | status_class += ' forwarded'; |
| | | status_label += this.get_label('replied') + ' '; |
| | | status_label += this.get_label('forwarded') + ' '; |
| | | } |
| | | |
| | | // update selection |
| | |
| | | if (preview && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread && this.env.preview_pane_mark_read > 0) { |
| | | this.preview_read_timer = setTimeout(function() { |
| | | ref.set_unread_message(id, ref.env.mailbox); |
| | | ref.http_post('mark', {_uid: id, _flag: 'read', _quiet: 1}); |
| | | ref.http_post('mark', {_uid: id, _flag: 'read', _mbox: ref.env.mailbox, _quiet: 1}); |
| | | }, this.env.preview_pane_mark_read * 1000); |
| | | } |
| | | } |
| | |
| | | // list messages of a specific mailbox using filter |
| | | this.filter_mailbox = function(filter) |
| | | { |
| | | if (this.filter_disabled) |
| | | return; |
| | | |
| | | var lock = this.set_busy(true, 'searching'); |
| | | |
| | | this.clear_message_list(); |
| | |
| | | if (sort) |
| | | url._sort = sort; |
| | | |
| | | // also send search request to get the right messages |
| | | if (this.env.search_request) |
| | | url._search = this.env.search_request; |
| | | |
| | | // set page=1 if changeing to another mailbox |
| | | // folder change, reset page, search scope, etc. |
| | | if (this.env.mailbox != mbox) { |
| | | page = 1; |
| | | this.env.current_page = page; |
| | | this.env.search_scope = 'base'; |
| | | this.select_all_mode = false; |
| | | this.reset_search_filter(); |
| | | } |
| | | // also send search request to get the right messages |
| | | else if (this.env.search_request) |
| | | url._search = this.env.search_request; |
| | | |
| | | if (!update_only) { |
| | | // unselect selected messages and clear the list and message data |
| | |
| | | selection.push(selected[i]); |
| | | |
| | | this.message_list.selection = selection; |
| | | |
| | | // reset preview frame, if currently previewed message is not selected (has been removed) |
| | | try { |
| | | var win = this.get_frame_window(this.env.contentframe), |
| | | id = win.rcmail.env.uid; |
| | | |
| | | if (id && $.inArray(id, selection) < 0) |
| | | this.show_contentframe(false); |
| | | } |
| | | catch (e) {}; |
| | | }; |
| | | |
| | | // expand all threads with unread children |
| | | this.expand_unread = function() |
| | | { |
| | | var r, tbody = this.gui_objects.messagelist.tBodies[0], |
| | | var r, tbody = this.message_list.tbody, |
| | | new_row = tbody.firstChild; |
| | | |
| | | while (new_row) { |
| | |
| | | if (!this.gui_objects.messageform) |
| | | return false; |
| | | |
| | | var i, input_from = $("[name='_from']"), |
| | | var i, pos, input_from = $("[name='_from']"), |
| | | input_to = $("[name='_to']"), |
| | | input_subject = $("input[name='_subject']"), |
| | | input_message = $("[name='_message']").get(0), |
| | |
| | | } |
| | | |
| | | if (!html_mode) { |
| | | this.set_caret_pos(input_message, this.env.top_posting ? 0 : $(input_message).val().length); |
| | | pos = this.env.top_posting ? 0 : input_message.value.length; |
| | | this.set_caret_pos(input_message, pos); |
| | | |
| | | // add signature according to selected identity |
| | | // if we have HTML editor, signature is added in callback |
| | | if (input_from.prop('type') == 'select-one') { |
| | | this.change_identity(input_from[0]); |
| | | } |
| | | |
| | | // scroll to the bottom of the textarea (#1490114) |
| | | if (pos) { |
| | | $(input_message).scrollTop(input_message.scrollHeight); |
| | | } |
| | | } |
| | | |
| | | // check for locally stored compose data |
| | | this.compose_restore_dialog(0, html_mode) |
| | | if (this.env.save_localstorage) |
| | | this.compose_restore_dialog(0, html_mode) |
| | | |
| | | if (input_to.val() == '') |
| | | input_to.focus(); |
| | |
| | | this.get_label('restoremessage'), |
| | | [{ |
| | | text: this.get_label('restore'), |
| | | 'class': 'mainaction', |
| | | click: function(){ |
| | | ref.restore_compose_form(key, html_mode); |
| | | ref.remove_compose_data(key); // remove old copy |
| | |
| | | }, |
| | | { |
| | | text: this.get_label('delete'), |
| | | 'class': 'delete', |
| | | click: function(){ |
| | | ref.remove_compose_data(key); |
| | | $(this).dialog('close'); |
| | |
| | | .attr({ 'autocomplete': 'off', 'aria-autocomplete': 'list', 'aria-expanded': 'false', 'role': 'combobox' }); |
| | | }; |
| | | |
| | | this.submit_messageform = function(draft) |
| | | this.submit_messageform = function(draft, saveonly) |
| | | { |
| | | var form = this.gui_objects.messageform; |
| | | |
| | | if (!form) |
| | | return; |
| | | |
| | | // the message has been sent but not saved, ask the user what to do |
| | | if (!saveonly && this.env.is_sent) { |
| | | return this.show_popup_dialog(this.get_label('messageissent'), '', |
| | | [{ |
| | | text: this.get_label('save'), |
| | | 'class': 'mainaction', |
| | | click: function() { |
| | | ref.submit_messageform(false, true); |
| | | $(this).dialog('close'); |
| | | } |
| | | }, |
| | | { |
| | | text: this.get_label('cancel'), |
| | | click: function() { |
| | | $(this).dialog('close'); |
| | | } |
| | | }] |
| | | ); |
| | | } |
| | | |
| | | // all checks passed, send message |
| | | var msgid = this.set_busy(true, draft ? 'savingmessage' : 'sendingmessage'), |
| | | var msgid = this.set_busy(true, draft || saveonly ? 'savingmessage' : 'sendingmessage'), |
| | | lang = this.spellcheck_lang(), |
| | | files = []; |
| | | |
| | |
| | | form.action = this.add_url(form.action, '_unlock', msgid); |
| | | form.action = this.add_url(form.action, '_lang', lang); |
| | | form.action = this.add_url(form.action, '_framed', 1); |
| | | |
| | | if (saveonly) { |
| | | form.action = this.add_url(form.action, '_saveonly', 1); |
| | | } |
| | | |
| | | // register timer to notify about connection timeout |
| | | this.submit_timer = setTimeout(function(){ |
| | |
| | | this.toggle_editor = function(props, obj, e) |
| | | { |
| | | // @todo: this should work also with many editors on page |
| | | var result = this.editor.toggle(props.html); |
| | | var result = this.editor.toggle(props.html, props.noconvert || false); |
| | | |
| | | // satisfy the expectations of aftertoggle-editor event subscribers |
| | | props.mode = props.html ? 'html' : 'plain'; |
| | | |
| | | if (!result && e) { |
| | | // fix selector value if operation failed |
| | | $(e.target).filter('select').val(props.html ? 'plain' : 'html'); |
| | | props.mode = props.html ? 'plain' : 'html'; |
| | | $(e.target).filter('select').val(props.mode); |
| | | } |
| | | |
| | | if (result) { |
| | |
| | | this.save_response = function() |
| | | { |
| | | // show dialog to enter a name and to modify the text to be saved |
| | | var buttons = {}, text = this.editor.get_content(true, true), |
| | | var buttons = {}, text = this.editor.get_content({selection: true, format: 'text', nosig: true}), |
| | | html = '<form class="propform">' + |
| | | '<div class="prop block"><label>' + this.get_label('responsename') + '</label>' + |
| | | '<input type="text" name="name" id="ffresponsename" size="40" /></div>' + |
| | |
| | | $(this).dialog('close'); |
| | | }; |
| | | |
| | | this.show_popup_dialog(html, this.gettext('newresponse'), buttons); |
| | | this.show_popup_dialog(html, this.gettext('newresponse'), buttons, {button_classes: ['mainaction']}); |
| | | |
| | | $('#ffresponsetext').val(text); |
| | | $('#ffresponsename').select(); |
| | |
| | | |
| | | this.set_draft_id = function(id) |
| | | { |
| | | var rc; |
| | | |
| | | if (id && id != this.env.draft_id) { |
| | | if (rc = this.opener()) { |
| | | // refresh the drafts folder in opener window |
| | | if (rc.env.task == 'mail' && rc.env.action == '' && rc.env.mailbox == this.env.drafts_mailbox) |
| | | rc.command('checkmail'); |
| | | } |
| | | var filter = {task: 'mail', action: ''}, |
| | | rc = this.opener(false, filter) || this.opener(true, filter); |
| | | |
| | | // refresh the drafts folder in the opener window |
| | | if (rc && rc.env.mailbox == this.env.drafts_mailbox) |
| | | rc.command('checkmail'); |
| | | |
| | | this.env.draft_id = id; |
| | | $("input[name='_draft_saveid']").val(id); |
| | |
| | | } |
| | | |
| | | // save compose form content to local storage every 5 seconds |
| | | if (!this.local_save_timer && window.localStorage) { |
| | | if (!this.local_save_timer && window.localStorage && this.env.save_localstorage) { |
| | | // track typing activity and only save on changes |
| | | this.compose_type_activity = this.compose_type_activity_last = 0; |
| | | $(document).bind('keypress', function(e){ ref.compose_type_activity++; }); |
| | |
| | | if (val = $('[name="_' + hash_fields[i] + '"]').val()) |
| | | str += val + ':'; |
| | | |
| | | str += this.editor.get_content(); |
| | | str += this.editor.get_content({refresh: false}); |
| | | |
| | | if (this.env.attachments) |
| | | for (id in this.env.attachments) |
| | |
| | | // store the contents of the compose form to localstorage |
| | | this.save_compose_form_local = function() |
| | | { |
| | | // feature is disabled |
| | | if (!this.env.save_localstorage) |
| | | return; |
| | | |
| | | var formdata = { session:this.env.session_id, changed:new Date().getTime() }, |
| | | ed, empty = true; |
| | | |
| | |
| | | |
| | | // initialize HTML editor |
| | | if ((formdata._is_html == '1' && !html_mode) || (formdata._is_html != '1' && html_mode)) { |
| | | this.command('toggle-editor', {id: this.env.composebody, html: !html_mode}); |
| | | this.command('toggle-editor', {id: this.env.composebody, html: !html_mode, noconvert: true}); |
| | | } |
| | | } |
| | | }; |
| | |
| | | this.local_storage_remove_item('compose.index'); |
| | | }; |
| | | |
| | | |
| | | this.change_identity = function(obj, show_sig) |
| | | { |
| | | if (!obj || !obj.options) |
| | |
| | | |
| | | if (!show_sig) |
| | | show_sig = this.env.show_sig; |
| | | |
| | | var id = obj.options[obj.selectedIndex].value, |
| | | sig = this.env.identity, |
| | | delim = this.env.recipients_separator, |
| | | rx_delim = RegExp.escape(delim); |
| | | |
| | | // enable manual signature insert |
| | | if (this.env.signatures && this.env.signatures[id]) { |
| | | this.enable_command('insert-sig', true); |
| | | this.env.compose_commands.push('insert-sig'); |
| | | } |
| | | else |
| | | this.enable_command('insert-sig', false); |
| | | |
| | | // first function execution |
| | | if (!this.env.identities_initialized) { |
| | |
| | | if (this.env.opened_extwin) |
| | | return; |
| | | } |
| | | |
| | | var id = obj.options[obj.selectedIndex].value, |
| | | sig = this.env.identity, |
| | | delim = this.env.recipients_separator, |
| | | rx_delim = RegExp.escape(delim); |
| | | |
| | | // update reply-to/bcc fields with addresses defined in identities |
| | | $.each(['replyto', 'bcc'], function() { |
| | |
| | | if (old_val || new_val) |
| | | input.val(input_val).change(); |
| | | }); |
| | | |
| | | // enable manual signature insert |
| | | if (this.env.signatures && this.env.signatures[id]) { |
| | | this.enable_command('insert-sig', true); |
| | | this.env.compose_commands.push('insert-sig'); |
| | | } |
| | | else |
| | | this.enable_command('insert-sig', false); |
| | | |
| | | this.editor.change_signature(id, show_sig); |
| | | this.env.identity = id; |
| | |
| | | return url; |
| | | }; |
| | | |
| | | // reset search filter |
| | | this.reset_search_filter = function() |
| | | { |
| | | this.filter_disabled = true; |
| | | if (this.gui_objects.search_filter) |
| | | $(this.gui_objects.search_filter).val('ALL').change(); |
| | | this.filter_disabled = false; |
| | | }; |
| | | |
| | | // reset quick-search form |
| | | this.reset_qsearch = function() |
| | | this.reset_qsearch = function(all) |
| | | { |
| | | if (this.gui_objects.qsearchbox) |
| | | this.gui_objects.qsearchbox.value = ''; |
| | | |
| | | if (this.env.qsearch) |
| | | this.abort_request(this.env.qsearch); |
| | | |
| | | if (all) { |
| | | this.env.search_scope = 'base'; |
| | | this.reset_search_filter(); |
| | | } |
| | | |
| | | this.env.qsearch = null; |
| | | this.env.search_request = null; |
| | |
| | | (this.env.search_request && (this.env.search_scope || 'base') != 'base'); |
| | | }; |
| | | |
| | | this.sent_successfully = function(type, msg, folders) |
| | | // action executed after mail is sent |
| | | this.sent_successfully = function(type, msg, folders, save_error) |
| | | { |
| | | this.display_message(msg, type); |
| | | this.compose_skip_unsavedcheck = true; |
| | | |
| | | if (this.env.extwin) { |
| | | this.lock_form(this.gui_objects.messageform); |
| | | if (!save_error) |
| | | this.lock_form(this.gui_objects.messageform); |
| | | |
| | | var rc = this.opener(); |
| | | var filter = {task: 'mail', action: ''}, |
| | | rc = this.opener(false, filter) || this.opener(true, filter); |
| | | |
| | | 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) { |
| | | if (folders && $.inArray(rc.env.mailbox, folders) >= 0) { |
| | | rc.command('checkmail'); |
| | | } |
| | | } |
| | | |
| | | setTimeout(function() { window.close(); }, 1000); |
| | | if (!save_error) |
| | | setTimeout(function() { window.close(); }, 1000); |
| | | } |
| | | else { |
| | | else if (!save_error) { |
| | | // before redirect we need to wait some time for Chrome (#1486177) |
| | | setTimeout(function() { ref.list_mailbox(); }, 500); |
| | | } |
| | | |
| | | if (save_error) |
| | | this.env.is_sent = true; |
| | | }; |
| | | |
| | | |
| | |
| | | this.ksearch_destroy(); |
| | | |
| | | // insert all members of a group |
| | | if (typeof this.env.contacts[id] === 'object' && this.env.contacts[id].type == 'group') { |
| | | if (typeof this.env.contacts[id] === 'object' && this.env.contacts[id].type == 'group' && !this.env.contacts[id].email) { |
| | | insert += this.env.contacts[id].name + this.env.recipients_delimiter; |
| | | this.group2expand[this.env.contacts[id].id] = $.extend({ input: this.ksearch_input }, this.env.contacts[id]); |
| | | this.http_request('mail/group-expand', {_source: this.env.contacts[id].source, _gid: this.env.contacts[id].id}, false); |
| | |
| | | id = i + this.env.contacts.length; |
| | | $('<li>').attr('id', 'rcmkSearchItem' + id) |
| | | .attr('role', 'option') |
| | | .html(this.quote_html(text.replace(new RegExp('('+RegExp.escape(value)+')', 'ig'), '##$1%%')).replace(/##([^%]+)%%/g, '<b>$1</b>')) |
| | | .html('<i class="icon"></i>' + this.quote_html(text.replace(new RegExp('('+RegExp.escape(value)+')', 'ig'), '##$1%%')).replace(/##([^%]+)%%/g, '<b>$1</b>')) |
| | | .addClass(type || '') |
| | | .appendTo(ul) |
| | | .mouseover(function() { ref.ksearch_select(this); }) |
| | |
| | | clearTimeout(this.preview_timer); |
| | | |
| | | var n, id, sid, contact, writable = false, |
| | | selected = list.selection.length, |
| | | source = this.env.source ? this.env.address_sources[this.env.source] : null; |
| | | |
| | | // we don't have dblclick handler here, so use 200 instead of this.dblclick_time |
| | | if (id = list.get_single_selection()) |
| | | if (this.env.contentframe && (id = list.get_single_selection())) |
| | | this.preview_timer = setTimeout(function(){ ref.load_contact(id, 'show'); }, 200); |
| | | else if (this.env.contentframe) |
| | | this.show_contentframe(false); |
| | | |
| | | if (list.selection.length) { |
| | | if (selected) { |
| | | list.draggable = false; |
| | | |
| | | // no source = search result, we'll need to detect if any of |
| | |
| | | |
| | | // if a group is currently selected, and there is at least one contact selected |
| | | // thend we can enable the group-remove-selected command |
| | | this.enable_command('group-remove-selected', this.env.group && list.selection.length > 0 && writable); |
| | | this.enable_command('compose', this.env.group || list.selection.length > 0); |
| | | this.enable_command('export-selected', 'copy', list.selection.length > 0); |
| | | this.enable_command('group-remove-selected', this.env.group && selected && writable); |
| | | this.enable_command('compose', this.env.group || selected); |
| | | this.enable_command('print', selected == 1); |
| | | this.enable_command('export-selected', 'copy', selected > 0); |
| | | this.enable_command('edit', id && writable); |
| | | this.enable_command('delete', 'move', list.selection.length > 0 && writable); |
| | | this.enable_command('delete', 'move', selected && writable); |
| | | |
| | | return false; |
| | | }; |
| | |
| | | |
| | | if (!src) |
| | | src = this.env.source; |
| | | |
| | | if (refresh) |
| | | group = this.env.group; |
| | | |
| | | if (page && this.current_page == page && src == this.env.source && group == this.env.group) |
| | | return false; |
| | |
| | | this.contact_list.data = {}; |
| | | this.contact_list.clear(true); |
| | | this.show_contentframe(false); |
| | | this.enable_command('delete', 'move', 'copy', false); |
| | | this.enable_command('compose', this.env.group ? true : false); |
| | | this.enable_command('delete', 'move', 'copy', 'print', false); |
| | | this.enable_command('compose', this.env.group); |
| | | }; |
| | | |
| | | this.set_group_prop = function(prop) |
| | |
| | | this.contact_list.clear_selection(); |
| | | |
| | | this.enable_command('compose', rec && rec.email); |
| | | this.enable_command('export-selected', rec && rec._type != 'group'); |
| | | this.enable_command('export-selected', 'print', rec && rec._type != 'group'); |
| | | } |
| | | else if (framed) |
| | | return false; |
| | |
| | | dateFormat: this.env.date_format, |
| | | changeMonth: true, |
| | | changeYear: true, |
| | | yearRange: '-100:+10', |
| | | yearRange: '-120:+10', |
| | | showOtherMonths: true, |
| | | selectOtherMonths: true, |
| | | onSelect: function(dateText) { $(this).focus().val(dateText) } |
| | | selectOtherMonths: true |
| | | // onSelect: function(dateText) { $(this).focus().val(dateText); } |
| | | }); |
| | | $('input.datepicker').datepicker(); |
| | | } |
| | |
| | | this.show_popup_dialog(content, this.get_label('newgroup'), |
| | | [{ |
| | | text: this.get_label('save'), |
| | | 'class': 'mainaction', |
| | | click: function() { |
| | | var name; |
| | | |
| | |
| | | this.show_popup_dialog(content, this.get_label('grouprename'), |
| | | [{ |
| | | text: this.get_label('save'), |
| | | 'class': 'mainaction', |
| | | click: function() { |
| | | var name; |
| | | |
| | |
| | | this.show_popup_dialog(content, this.get_label('searchsave'), |
| | | [{ |
| | | text: this.get_label('save'), |
| | | 'class': 'mainaction', |
| | | click: function() { |
| | | var name; |
| | | |
| | |
| | | this.subscription_list = new rcube_treelist_widget(this.gui_objects.subscriptionlist, { |
| | | selectable: true, |
| | | tabexit: false, |
| | | parent_focus: true, |
| | | id_prefix: 'rcmli', |
| | | id_encode: this.html_identifier_encode, |
| | | id_decode: this.html_identifier_decode, |
| | |
| | | // on the list when dragging starts (and stops), this is slow, but |
| | | // I didn't find a method to check droptarget on over event |
| | | accept: function(node) { |
| | | if (!$(node).is('.mailbox')) |
| | | return false; |
| | | |
| | | var source_folder = ref.folder_id2name($(node).attr('id')), |
| | | dest_folder = ref.folder_id2name(this.id), |
| | | source = ref.env.subscriptionrows[source_folder], |
| | |
| | | |
| | | this.folder_id2name = function(id) |
| | | { |
| | | return ref.html_identifier_decode(id.replace(/^rcmli/, '')); |
| | | return id ? ref.html_identifier_decode(id.replace(/^rcmli/, '')) : null; |
| | | }; |
| | | |
| | | this.subscription_select = function(id) |
| | |
| | | }; |
| | | |
| | | // display a system message, list of types in common.css (below #message definition) |
| | | this.display_message = function(msg, type, timeout) |
| | | this.display_message = function(msg, type, timeout, key) |
| | | { |
| | | // pass command to parent window |
| | | if (this.is_framed()) |
| | |
| | | if (!this.gui_objects.message) { |
| | | // save message in order to display after page loaded |
| | | if (type != 'loading') |
| | | this.pending_message = [msg, type, timeout]; |
| | | this.pending_message = [msg, type, timeout, key]; |
| | | return 1; |
| | | } |
| | | |
| | | type = type ? type : 'notice'; |
| | | if (!type) |
| | | type = 'notice'; |
| | | |
| | | var key = this.html_identifier(msg), |
| | | date = new Date(), |
| | | if (!key) |
| | | key = this.html_identifier(msg); |
| | | |
| | | var date = new Date(), |
| | | id = type + date.getTime(); |
| | | |
| | | if (!timeout) |
| | | timeout = this.message_time * (type == 'error' || type == 'warning' ? 2 : 1); |
| | | if (!timeout) { |
| | | switch (type) { |
| | | case 'error': |
| | | case 'warning': |
| | | timeout = this.message_time * 2; |
| | | break; |
| | | |
| | | case 'uploading': |
| | | timeout = 0; |
| | | break; |
| | | |
| | | default: |
| | | timeout = this.message_time; |
| | | } |
| | | } |
| | | |
| | | if (type == 'loading') { |
| | | key = 'loading'; |
| | |
| | | if (type == 'loading') { |
| | | this.messages[key].labels = [{'id': id, 'msg': msg}]; |
| | | } |
| | | else { |
| | | else if (type != 'uploading') { |
| | | obj.click(function() { return ref.hide_message(obj); }) |
| | | .attr('role', 'alert'); |
| | | } |
| | |
| | | |
| | | if (timeout > 0) |
| | | setTimeout(function() { ref.hide_message(id, type != 'loading'); }, timeout); |
| | | |
| | | return id; |
| | | }; |
| | | |
| | |
| | | this.messages = {}; |
| | | }; |
| | | |
| | | // display uploading message with progress indicator |
| | | // data should contain: name, total, current, percent, text |
| | | this.display_progress = function(data) |
| | | { |
| | | if (!data || !data.name) |
| | | return; |
| | | |
| | | var msg = this.messages['progress' + data.name]; |
| | | |
| | | if (!data.label) |
| | | data.label = this.get_label('uploadingmany'); |
| | | |
| | | if (!msg) { |
| | | if (!data.percent || data.percent < 100) |
| | | this.display_message(data.label, 'uploading', 0, 'progress' + data.name); |
| | | return; |
| | | } |
| | | |
| | | if (!data.total || data.percent >= 100) { |
| | | this.hide_message(msg.obj); |
| | | return; |
| | | } |
| | | |
| | | if (data.text) |
| | | data.label += ' ' + data.text; |
| | | |
| | | msg.obj.text(data.label); |
| | | }; |
| | | |
| | | // open a jquery UI dialog with the given content |
| | | this.show_popup_dialog = function(content, title, buttons, options) |
| | | { |
| | |
| | | else |
| | | popup.html(content); |
| | | |
| | | popup.dialog($.extend({ |
| | | options = $.extend({ |
| | | title: title, |
| | | buttons: buttons, |
| | | modal: true, |
| | | resizable: true, |
| | | width: 500, |
| | | close: function(event, ui) { $(this).remove(); } |
| | | }, options || {})); |
| | | }, options || {}); |
| | | |
| | | popup.dialog(options); |
| | | |
| | | // resize and center popup |
| | | var win = $(window), w = win.width(), h = win.height(), |
| | |
| | | popup.dialog('option', { |
| | | height: Math.min(h - 40, height + 75 + (buttons ? 50 : 0)), |
| | | width: Math.min(w - 20, width + 36) |
| | | }); |
| | | |
| | | // assign special classes to dialog buttons |
| | | $.each(options.button_classes || [], function(i, v) { |
| | | if (v) $($('.ui-dialog-buttonpane button.ui-button', popup.parent()).get(i)).addClass(v); |
| | | }); |
| | | |
| | | return popup; |
| | |
| | | this.set_quota = function(content) |
| | | { |
| | | if (this.gui_objects.quotadisplay && content && content.type == 'text') |
| | | $(this.gui_objects.quotadisplay).html(content.percent+'%').attr('title', content.title); |
| | | $(this.gui_objects.quotadisplay).text((content.percent||0) + '%').attr('title', content.title); |
| | | |
| | | this.triggerEvent('setquota', content); |
| | | this.env.quota_content = content; |
| | |
| | | // truncate stack down to the one containing the ref link |
| | | for (var i = this.menu_stack.length - 1; stack && i >= 0; i--) { |
| | | if (!$(ref).parents('#'+this.menu_stack[i]).length) |
| | | this.hide_menu(this.menu_stack[i]); |
| | | this.hide_menu(this.menu_stack[i], event); |
| | | } |
| | | if (stack && this.menu_stack.length) { |
| | | obj.data('parent', $.last(this.menu_stack)); |
| | |
| | | }; |
| | | |
| | | // send a http request to the server |
| | | this.http_request = function(action, query, lock) |
| | | this.http_request = function(action, data, lock) |
| | | { |
| | | var url = this.url(action, query); |
| | | if (typeof data !== 'object') |
| | | data = rcube_parse_query(data); |
| | | |
| | | data._remote = 1; |
| | | data._unlock = lock ? lock : 0; |
| | | |
| | | // trigger plugin hook |
| | | var result = this.triggerEvent('request'+action, query); |
| | | var result = this.triggerEvent('request' + action, data); |
| | | |
| | | if (result !== undefined) { |
| | | // abort if one the handlers returned false |
| | | if (result === false) |
| | | return false; |
| | | else |
| | | url = this.url(action, result); |
| | | // abort if one of the handlers returned false |
| | | if (result === false) { |
| | | if (data._unlock) |
| | | this.set_busy(false, null, data._unlock); |
| | | return false; |
| | | } |
| | | else if (result !== undefined) { |
| | | data = result; |
| | | if (data._action) { |
| | | action = data._action; |
| | | delete data._action; |
| | | } |
| | | } |
| | | |
| | | url += '&_remote=1'; |
| | | var url = this.url(action, data); |
| | | |
| | | // send request |
| | | this.log('HTTP GET: ' + url); |
| | |
| | | this.start_keepalive(); |
| | | |
| | | return $.ajax({ |
| | | type: 'GET', url: url, data: { _unlock:(lock?lock:0) }, dataType: 'json', |
| | | success: function(data){ ref.http_response(data); }, |
| | | type: 'GET', url: url, dataType: 'json', |
| | | success: function(data) { ref.http_response(data); }, |
| | | error: function(o, status, err) { ref.http_error(o, status, err, lock, action); } |
| | | }); |
| | | }; |
| | | |
| | | // send a http POST request to the server |
| | | this.http_post = function(action, postdata, lock) |
| | | this.http_post = function(action, data, lock) |
| | | { |
| | | var url = this.url(action); |
| | | if (typeof data !== 'object') |
| | | data = rcube_parse_query(data); |
| | | |
| | | if (postdata && typeof postdata === 'object') { |
| | | postdata._remote = 1; |
| | | postdata._unlock = (lock ? lock : 0); |
| | | } |
| | | else |
| | | postdata += (postdata ? '&' : '') + '_remote=1' + (lock ? '&_unlock='+lock : ''); |
| | | data._remote = 1; |
| | | data._unlock = lock ? lock : 0; |
| | | |
| | | // trigger plugin hook |
| | | var result = this.triggerEvent('request'+action, postdata); |
| | | if (result !== undefined) { |
| | | // abort if one of the handlers returned false |
| | | if (result === false) |
| | | return false; |
| | | else |
| | | postdata = result; |
| | | var result = this.triggerEvent('request'+action, data); |
| | | |
| | | // abort if one of the handlers returned false |
| | | if (result === false) { |
| | | if (data._unlock) |
| | | this.set_busy(false, null, data._unlock); |
| | | return false; |
| | | } |
| | | else if (result !== undefined) { |
| | | data = result; |
| | | if (data._action) { |
| | | action = data._action; |
| | | delete data._action; |
| | | } |
| | | } |
| | | |
| | | var url = this.url(action); |
| | | |
| | | // send request |
| | | this.log('HTTP POST: ' + url); |
| | |
| | | this.start_keepalive(); |
| | | |
| | | return $.ajax({ |
| | | type: 'POST', url: url, data: postdata, dataType: 'json', |
| | | type: 'POST', url: url, data: data, dataType: 'json', |
| | | success: function(data){ ref.http_response(data); }, |
| | | error: function(o, status, err) { ref.http_error(o, status, err, lock, action); } |
| | | }); |
| | |
| | | this.enable_command('compose', (uid && this.contact_list.rows[uid])); |
| | | this.enable_command('delete', 'edit', writable); |
| | | this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); |
| | | this.enable_command('export-selected', false); |
| | | this.enable_command('export-selected', 'print', false); |
| | | } |
| | | |
| | | case 'move': |
| | |
| | | }; |
| | | |
| | | // get window.opener.rcmail if available |
| | | this.opener = function() |
| | | this.opener = function(deep, filter) |
| | | { |
| | | var i, win = window.opener; |
| | | |
| | | // catch Error: Permission denied to access property rcmail |
| | | try { |
| | | if (window.opener && !opener.closed && opener.rcmail) |
| | | return opener.rcmail; |
| | | if (win && !win.closed) { |
| | | // try parent of the opener window, e.g. preview frame |
| | | if (deep && (!win.rcmail || win.rcmail.env.framed) && win.parent && win.parent.rcmail) |
| | | win = win.parent; |
| | | |
| | | if (win.rcmail && filter) |
| | | for (i in filter) |
| | | if (win.rcmail.env[i] != filter[i]) |
| | | return; |
| | | |
| | | return win.rcmail; |
| | | } |
| | | } |
| | | catch (e) {} |
| | | }; |
| | |
| | | // and return the message uid |
| | | this.get_single_uid = function() |
| | | { |
| | | return this.env.uid ? this.env.uid : (this.message_list ? this.message_list.get_single_selection() : null); |
| | | var uid = this.env.uid || (this.message_list ? this.message_list.get_single_selection() : null); |
| | | var result = ref.triggerEvent('get_single_uid', { uid: uid }); |
| | | return result || uid; |
| | | }; |
| | | |
| | | // same as above but for contacts |
| | | this.get_single_cid = function() |
| | | { |
| | | return this.env.cid ? this.env.cid : (this.contact_list ? this.contact_list.get_single_selection() : null); |
| | | var cid = this.env.cid || (this.contact_list ? this.contact_list.get_single_selection() : null); |
| | | var result = ref.triggerEvent('get_single_cid', { cid: cid }); |
| | | return result || cid; |
| | | }; |
| | | |
| | | // get the IMP mailbox of the message with the given UID |
| | |
| | | |
| | | img.onload = function() { ref.env.browser_capabilities.tif = 1; }; |
| | | img.onerror = function() { ref.env.browser_capabilities.tif = 0; }; |
| | | img.src = 'program/resources/blank.tif'; |
| | | img.src = this.assets_path('program/resources/blank.tif'); |
| | | }; |
| | | |
| | | this.pdf_support_check = function() |
| | |
| | | if (plugin && plugin.enabledPlugin) |
| | | return 1; |
| | | |
| | | if (window.ActiveXObject) { |
| | | if ('ActiveXObject' in window) { |
| | | try { |
| | | if (plugin = new ActiveXObject("AcroPDF.PDF")) |
| | | return 1; |
| | |
| | | if (plugin && plugin.enabledPlugin) |
| | | return 1; |
| | | |
| | | if (window.ActiveXObject) { |
| | | if ('ActiveXObject' in window) { |
| | | try { |
| | | if (plugin = new ActiveXObject("ShockwaveFlash.ShockwaveFlash")) |
| | | return 1; |
| | |
| | | } |
| | | |
| | | return 0; |
| | | }; |
| | | |
| | | this.assets_path = function(path) |
| | | { |
| | | if (this.env.assets_path && !path.startsWith(this.env.assets_path)) { |
| | | path = this.env.assets_path + path; |
| | | } |
| | | |
| | | return path; |
| | | }; |
| | | |
| | | // Cookie setter |
| | |
| | | // wrapper for localStorage.getItem(key) |
| | | this.local_storage_get_item = function(key, deflt, encrypted) |
| | | { |
| | | var item; |
| | | var item, result; |
| | | |
| | | // TODO: add encryption |
| | | try { |
| | | item = localStorage.getItem(this.get_local_storage_prefix() + key); |
| | | result = JSON.parse(item); |
| | | } |
| | | catch (e) { } |
| | | |
| | | return item !== null ? JSON.parse(item) : (deflt || null); |
| | | return result || deflt || null; |
| | | }; |
| | | |
| | | // wrapper for localStorage.setItem(key, data) |
| | |
| | | return false; |
| | | } |
| | | }; |
| | | |
| | | this.print_dialog = function() |
| | | { |
| | | if (bw.safari) |
| | | setTimeout('window.print()', 10); |
| | | else |
| | | window.print(); |
| | | }; |
| | | } // end object rcube_webmail |
| | | |
| | | |
| | |
| | | if (!elem.title) { |
| | | var $elem = $(elem); |
| | | if ($elem.width() + (indent || 0) * 15 > $elem.parent().width()) |
| | | elem.title = $elem.text(); |
| | | elem.title = rcube_webmail.subject_text(elem); |
| | | } |
| | | }; |
| | | |
| | |
| | | |
| | | tmp.remove(); |
| | | if (w + $('span.branch', $elem).width() * 15 > $elem.width()) |
| | | elem.title = txt; |
| | | elem.title = rcube_webmail.subject_text(elem); |
| | | } |
| | | }; |
| | | |
| | | rcube_webmail.subject_text = function(elem) |
| | | { |
| | | var t = $(elem).clone(); |
| | | t.find('.skip-on-drag').remove(); |
| | | return t.text(); |
| | | }; |
| | | |
| | | rcube_webmail.prototype.get_cookie = getCookie; |
| | | |
| | | // copy event engine prototype |