| | |
| | | this.onloads = []; |
| | | this.messages = {}; |
| | | this.group2expand = {}; |
| | | this.http_request_jobs = {}; |
| | | |
| | | // webmail client settings |
| | | this.dblclick_time = 500; |
| | |
| | | multiselect:true, multiexpand:true, draggable:true, keyboard:true, |
| | | column_movable:this.env.col_movable, dblclick_time:this.dblclick_time |
| | | }); |
| | | this.message_list.row_init = function(o){ p.init_message_row(o); }; |
| | | this.message_list.addEventListener('dblclick', function(o){ p.msglist_dbl_click(o); }); |
| | | this.message_list.addEventListener('click', function(o){ p.msglist_click(o); }); |
| | | this.message_list.addEventListener('keypress', function(o){ p.msglist_keypress(o); }); |
| | | this.message_list.addEventListener('select', function(o){ p.msglist_select(o); }); |
| | | this.message_list.addEventListener('dragstart', function(o){ p.drag_start(o); }); |
| | | this.message_list.addEventListener('dragmove', function(e){ p.drag_move(e); }); |
| | | this.message_list.addEventListener('dragend', function(e){ p.drag_end(e); }); |
| | | this.message_list.addEventListener('expandcollapse', function(e){ p.msglist_expand(e); }); |
| | | this.message_list.addEventListener('column_replace', function(e){ p.msglist_set_coltypes(e); }); |
| | | this.message_list.addEventListener('listupdate', function(e){ p.triggerEvent('listupdate', e); }); |
| | | this.message_list |
| | | .addEventListener('initrow', function(o) { p.init_message_row(o); }) |
| | | .addEventListener('dblclick', function(o) { p.msglist_dbl_click(o); }) |
| | | .addEventListener('click', function(o) { p.msglist_click(o); }) |
| | | .addEventListener('keypress', function(o) { p.msglist_keypress(o); }) |
| | | .addEventListener('select', function(o) { p.msglist_select(o); }) |
| | | .addEventListener('dragstart', function(o) { p.drag_start(o); }) |
| | | .addEventListener('dragmove', function(e) { p.drag_move(e); }) |
| | | .addEventListener('dragend', function(e) { p.drag_end(e); }) |
| | | .addEventListener('expandcollapse', function(o) { p.msglist_expand(o); }) |
| | | .addEventListener('column_replace', function(o) { p.msglist_set_coltypes(o); }) |
| | | .addEventListener('listupdate', function(o) { p.triggerEvent('listupdate', o); }) |
| | | .init(); |
| | | |
| | | document.onmouseup = function(e){ return p.doc_mouse_up(e); }; |
| | | this.gui_objects.messagelist.parentNode.onmousedown = function(e){ return p.click_on_list(e); }; |
| | | |
| | | this.message_list.init(); |
| | | this.enable_command('toggle_status', 'toggle_flag', 'sort', true); |
| | | |
| | | // load messages |
| | |
| | | if (this.gui_objects.contactslist) { |
| | | this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, |
| | | { multiselect:true, draggable:false, keyboard:false }); |
| | | this.contact_list.addEventListener('select', function(o){ ref.compose_recipient_select(o); }); |
| | | this.contact_list.addEventListener('dblclick', function(o){ ref.compose_add_recipient('to'); }); |
| | | this.contact_list.init(); |
| | | this.contact_list |
| | | .addEventListener('initrow', function(o) { p.triggerEvent('insertrow', { cid:o.uid, row:o }); }) |
| | | .addEventListener('select', function(o) { ref.compose_recipient_select(o); }) |
| | | .addEventListener('dblclick', function(o) { ref.compose_add_recipient('to'); }) |
| | | .init(); |
| | | } |
| | | |
| | | if (this.gui_objects.addressbookslist) { |
| | |
| | | if (this.gui_objects.contactslist) { |
| | | this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, |
| | | {multiselect:true, draggable:this.gui_objects.folderlist?true:false, keyboard:true}); |
| | | this.contact_list.row_init = function(row){ p.triggerEvent('insertrow', { cid:row.uid, row:row }); }; |
| | | this.contact_list.addEventListener('keypress', function(o){ p.contactlist_keypress(o); }); |
| | | this.contact_list.addEventListener('select', function(o){ p.contactlist_select(o); }); |
| | | this.contact_list.addEventListener('dragstart', function(o){ p.drag_start(o); }); |
| | | this.contact_list.addEventListener('dragmove', function(e){ p.drag_move(e); }); |
| | | this.contact_list.addEventListener('dragend', function(e){ p.drag_end(e); }); |
| | | this.contact_list.init(); |
| | | this.contact_list |
| | | .addEventListener('initrow', function(o) { p.triggerEvent('insertrow', { cid:o.uid, row:o }); }) |
| | | .addEventListener('keypress', function(o) { p.contactlist_keypress(o); }) |
| | | .addEventListener('select', function(o) { p.contactlist_select(o); }) |
| | | .addEventListener('dragstart', function(o) { p.drag_start(o); }) |
| | | .addEventListener('dragmove', function(e) { p.drag_move(e); }) |
| | | .addEventListener('dragend', function(e) { p.drag_end(e); }) |
| | | .init(); |
| | | |
| | | if (this.env.cid) |
| | | this.contact_list.highlight_row(this.env.cid); |
| | |
| | | } |
| | | |
| | | if (this.gui_objects.identitieslist) { |
| | | this.identity_list = new rcube_list_widget(this.gui_objects.identitieslist, {multiselect:false, draggable:false, keyboard:false}); |
| | | this.identity_list.addEventListener('select', function(o){ p.identity_select(o); }); |
| | | this.identity_list.init(); |
| | | this.identity_list.focus(); |
| | | this.identity_list = new rcube_list_widget(this.gui_objects.identitieslist, |
| | | {multiselect:false, draggable:false, keyboard:false}); |
| | | this.identity_list |
| | | .addEventListener('select', function(o) { p.identity_select(o); }) |
| | | .init() |
| | | .focus(); |
| | | |
| | | if (this.env.iid) |
| | | this.identity_list.highlight_row(this.env.iid); |
| | | } |
| | | else if (this.gui_objects.sectionslist) { |
| | | this.sections_list = new rcube_list_widget(this.gui_objects.sectionslist, {multiselect:false, draggable:false, keyboard:false}); |
| | | this.sections_list.addEventListener('select', function(o){ p.section_select(o); }); |
| | | this.sections_list.init(); |
| | | this.sections_list.focus(); |
| | | this.sections_list |
| | | .addEventListener('select', function(o) { p.section_select(o); }) |
| | | .init() |
| | | .focus(); |
| | | } |
| | | else if (this.gui_objects.subscriptionlist) { |
| | | this.init_subscription_list(); |
| | | } |
| | | else if (this.gui_objects.responseslist) { |
| | | this.responses_list = new rcube_list_widget(this.gui_objects.responseslist, {multiselect:false, draggable:false, keyboard:false}); |
| | | this.responses_list.addEventListener('select', function(list) { |
| | | var win, id = list.get_single_selection(); |
| | | p.enable_command('delete', !!id && $.inArray(id, p.env.readonly_responses) < 0); |
| | | if (id && (win = p.get_frame_window(p.env.contentframe))) { |
| | | p.set_busy(true); |
| | | p.location_href({ _action:'edit-response', _key:id, _framed:1 }, win); |
| | | } |
| | | }); |
| | | this.responses_list.init(); |
| | | this.responses_list.focus(); |
| | | this.responses_list |
| | | .addEventListener('select', function(list) { |
| | | var win, id = list.get_single_selection(); |
| | | p.enable_command('delete', !!id && $.inArray(id, p.env.readonly_responses) < 0); |
| | | if (id && (win = p.get_frame_window(p.env.contentframe))) { |
| | | p.set_busy(true); |
| | | p.location_href({ _action:'edit-response', _key:id, _framed:1 }, win); |
| | | } |
| | | }) |
| | | .init() |
| | | .focus(); |
| | | } |
| | | |
| | | break; |
| | |
| | | id_prefix: 'rcmli', |
| | | id_encode: this.html_identifier_encode, |
| | | id_decode: this.html_identifier_decode, |
| | | check_droptarget: function(node){ return !node.virtual && ref.check_droptarget(node.id) } |
| | | check_droptarget: function(node) { return !node.virtual && ref.check_droptarget(node.id) } |
| | | }); |
| | | this.treelist.addEventListener('collapse', function(node){ ref.folder_collapsed(node) }); |
| | | this.treelist.addEventListener('expand', function(node){ ref.folder_collapsed(node) }); |
| | | this.treelist.addEventListener('select', function(node){ ref.triggerEvent('selectfolder', { folder:node.id, prefix:'rcmli' }) }); |
| | | this.treelist |
| | | .addEventListener('collapse', function(node) { ref.folder_collapsed(node) }) |
| | | .addEventListener('expand', function(node) { ref.folder_collapsed(node) }) |
| | | .addEventListener('select', function(node) { ref.triggerEvent('selectfolder', { folder:node.id, prefix:'rcmli' }) }); |
| | | } |
| | | } |
| | | |
| | |
| | | case 'move': |
| | | case 'moveto': // deprecated |
| | | if (this.task == 'mail') |
| | | this.move_messages(props); |
| | | this.move_messages(props, obj); |
| | | else if (this.task == 'addressbook') |
| | | this.move_contacts(props); |
| | | break; |
| | | |
| | | case 'copy': |
| | | if (this.task == 'mail') |
| | | this.copy_messages(props); |
| | | this.copy_messages(props, obj); |
| | | else if (this.task == 'addressbook') |
| | | this.copy_contacts(props); |
| | | break; |
| | |
| | | |
| | | this.drag_start = function(list) |
| | | { |
| | | var model = this.task == 'mail' ? this.env.mailboxes : this.env.contactfolders; |
| | | |
| | | this.drag_active = true; |
| | | |
| | | if (this.preview_timer) |
| | |
| | | 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_message(id, 'unread', false); |
| | | ref.update_thread_root(id, 'read'); |
| | | if (ref.env.unread_counts[ref.env.mailbox]) { |
| | | ref.env.unread_counts[ref.env.mailbox] -= 1; |
| | | ref.set_unread_count(ref.env.mailbox, ref.env.unread_counts[ref.env.mailbox], ref.env.mailbox == 'INBOX'); |
| | |
| | | if (!row) |
| | | return false; |
| | | |
| | | if (flag == 'unread') |
| | | if (flag == 'unread') { |
| | | if (row.unread != status) |
| | | this.update_thread_root(uid, status ? 'unread' : 'read'); |
| | | row.unread = status; |
| | | } |
| | | else if(flag == 'deleted') |
| | | row.deleted = status; |
| | | else if (flag == 'replied') |
| | |
| | | }; |
| | | |
| | | // copy selected messages to the specified mailbox |
| | | this.copy_messages = function(mbox) |
| | | this.copy_messages = function(mbox, obj) |
| | | { |
| | | if (mbox && typeof mbox === 'object') |
| | | mbox = mbox.id; |
| | | else if (!mbox) |
| | | return this.folder_selector(obj, function(folder) { ref.command('copy', folder); }); |
| | | |
| | | // exit if current or no mailbox specified |
| | | if (!mbox || mbox == this.env.mailbox) |
| | |
| | | }; |
| | | |
| | | // move selected messages to the specified mailbox |
| | | this.move_messages = function(mbox) |
| | | this.move_messages = function(mbox, obj) |
| | | { |
| | | if (mbox && typeof mbox === 'object') |
| | | mbox = mbox.id; |
| | | else if (!mbox) |
| | | return this.folder_selector(obj, function(folder) { ref.command('move', folder); }); |
| | | |
| | | // exit if current or no mailbox specified |
| | | if (!mbox || mbox == this.env.mailbox) |
| | |
| | | // delete selected messages from the current mailbox |
| | | this.delete_messages = function(event) |
| | | { |
| | | var uid, i, len, trash = this.env.trash_mailbox, |
| | | list = this.message_list, |
| | | selection = list ? list.get_selection() : []; |
| | | |
| | | // exit if no mailbox specified or if selection is empty |
| | | if (!this.env.uid && !selection.length) |
| | | return; |
| | | |
| | | // also select childs of collapsed rows |
| | | for (i=0, len=selection.length; i<len; i++) { |
| | | uid = selection[i]; |
| | | if (list.rows[uid].has_children && !list.rows[uid].expanded) |
| | | list.select_children(uid); |
| | | } |
| | | var list = this.message_list, trash = this.env.trash_mailbox; |
| | | |
| | | // if config is set to flag for deletion |
| | | if (this.env.flag_for_deletion) { |
| | |
| | | this._with_selected_messages('delete', post_data); |
| | | }; |
| | | |
| | | // Send a specifc move/delete request with UIDs of all selected messages |
| | | // Send a specific move/delete request with UIDs of all selected messages |
| | | // @private |
| | | this._with_selected_messages = function(action, post_data, lock) |
| | | { |
| | |
| | | this.set_message(a_uids[i], 'unread', (flag == 'unread' ? true : false)); |
| | | |
| | | this.http_post('mark', post_data, lock); |
| | | |
| | | for (i=0; i<len; i++) |
| | | this.update_thread_root(a_uids[i], flag); |
| | | }; |
| | | |
| | | // set image to flagged or unflagged |
| | |
| | | { |
| | | var rc; |
| | | |
| | | if (!this.env.draft_id && id && (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'); |
| | | 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'); |
| | | } |
| | | |
| | | this.env.draft_id = id; |
| | | $("input[name='_draft_saveid']").val(id); |
| | | |
| | | this.remove_compose_data(this.env.compose_id); |
| | | } |
| | | |
| | | this.env.draft_id = id; |
| | | $("input[name='_draft_saveid']").val(id); |
| | | |
| | | this.remove_compose_data(this.env.compose_id); |
| | | }; |
| | | |
| | | this.auto_save_start = function() |
| | |
| | | p = inp_value.lastIndexOf(this.env.recipients_separator, cpos-1), |
| | | q = inp_value.substring(p+1, cpos), |
| | | min = this.env.autocomplete_min_length, |
| | | ac = this.ksearch_data; |
| | | data = this.ksearch_data; |
| | | |
| | | // trim query string |
| | | q = $.trim(q); |
| | |
| | | return; |
| | | |
| | | // ...new search value contains old one and previous search was not finished or its result was empty |
| | | if (old_value && old_value.length && q.startsWith(old_value) && (!ac || ac.num <= 0) && this.env.contacts && !this.env.contacts.length) |
| | | if (old_value && old_value.length && q.startsWith(old_value) && (!data || data.num <= 0) && this.env.contacts && !this.env.contacts.length) |
| | | return; |
| | | |
| | | var i, lock, source, xhr, reqid = new Date().getTime(), |
| | | post_data = {_search: q, _id: reqid}, |
| | | threads = props && props.threads ? props.threads : 1, |
| | | sources = props && props.sources ? props.sources : [], |
| | | action = props && props.action ? props.action : 'mail/autocomplete'; |
| | | var sources = props && props.sources ? props.sources : ['']; |
| | | var reqid = this.multi_thread_http_request({ |
| | | items: sources, |
| | | threads: props && props.threads ? props.threads : 1, |
| | | action: props && props.action ? props.action : 'mail/autocomplete', |
| | | postdata: { _search:q, _source:'%s' }, |
| | | lock: this.display_message(this.get_label('searching'), 'loading') |
| | | }); |
| | | |
| | | 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 === undefined) |
| | | break; |
| | | |
| | | post_data._source = source ? source : ''; |
| | | lock = this.display_message(this.get_label('searching'), 'loading'); |
| | | xhr = this.http_post(action, post_data, lock); |
| | | |
| | | this.ksearch_data.locks.push(lock); |
| | | this.ksearch_data.requests.push(xhr); |
| | | } |
| | | this.ksearch_data = { id:reqid, sources:sources.slice(), num:sources.length }; |
| | | }; |
| | | |
| | | this.ksearch_query_results = function(results, search, reqid) |
| | | { |
| | | // trigger multi-thread http response callback |
| | | this.multi_thread_http_response(results, reqid); |
| | | |
| | | // search stopped in meantime? |
| | | if (!this.ksearch_value) |
| | | return; |
| | |
| | | // display search results |
| | | var i, len, 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 (len) |
| | | 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(), post_data; |
| | | if (source) { |
| | | post_data = {_search: value, _id: reqid, _source: source}; |
| | | lock = this.display_message(this.get_label('searching'), 'loading'); |
| | | xhr = this.http_post(data.action, post_data, 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(); |
| | | } |
| | | } |
| | | if (this.ksearch_data.id == reqid) |
| | | this.ksearch_data.num--; |
| | | }; |
| | | |
| | | this.ksearch_click = function(node) |
| | |
| | | // Clears autocomplete data/requests |
| | | this.ksearch_destroy = function() |
| | | { |
| | | this.ksearch_abort(); |
| | | if (this.ksearch_data) |
| | | this.multi_thread_request_abort(this.ksearch_data.id); |
| | | |
| | | if (this.ksearch_info) |
| | | this.hide_message(this.ksearch_info); |
| | |
| | | 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]}); |
| | | }; |
| | | |
| | | |
| | |
| | | { |
| | | var key = 'G'+prop.source+prop.id; |
| | | if (this.treelist.remove(key)) { |
| | | this.triggerEvent('group_delete', { source:prop.source, id:prop.id }); |
| | | delete this.env.contactfolders[key]; |
| | | delete this.env.contactgroups[key]; |
| | | } |
| | |
| | | |
| | | this.subscription_list = new rcube_list_widget(this.gui_objects.subscriptionlist, |
| | | {multiselect:false, draggable:true, keyboard:false, toggleselect:true}); |
| | | this.subscription_list.addEventListener('select', function(o){ p.subscription_select(o); }); |
| | | this.subscription_list.addEventListener('dragstart', function(o){ p.drag_active = true; }); |
| | | this.subscription_list.addEventListener('dragend', function(o){ p.subscription_move_folder(o); }); |
| | | this.subscription_list.row_init = function (row) { |
| | | row.obj.onmouseover = function() { p.focus_subscription(row.id); }; |
| | | row.obj.onmouseout = function() { p.unfocus_subscription(row.id); }; |
| | | }; |
| | | this.subscription_list.init(); |
| | | this.subscription_list |
| | | .addEventListener('select', function(o){ p.subscription_select(o); }) |
| | | .addEventListener('dragstart', function(o){ p.drag_active = true; }) |
| | | .addEventListener('dragend', function(o){ p.subscription_move_folder(o); }) |
| | | .addEventListener('initrow', function (row) { |
| | | row.obj.onmouseover = function() { p.focus_subscription(row.id); }; |
| | | row.obj.onmouseout = function() { p.unfocus_subscription(row.id); }; |
| | | }) |
| | | .init(); |
| | | |
| | | $('#mailboxroot') |
| | | .mouseover(function(){ p.focus_subscription(this.id); }) |
| | |
| | | .prop({checked: subscribed ? true : false, disabled: is_protected ? true : false}); |
| | | |
| | | // add to folder/row-ID map |
| | | this.env.subscriptionrows[id] = [name, display_name, 0]; |
| | | this.env.subscriptionrows[id] = [name, display_name, false]; |
| | | |
| | | // sort folders (to find a place where to insert the row) |
| | | // replace delimiter with \0 character to fix sorting |
| | | // issue where 'Abc Abc' would be placed before 'Abc/def' |
| | | var replace_from = RegExp(RegExp.escape(this.env.delimiter), 'g'), |
| | | replace_to = String.fromCharCode(0); |
| | | |
| | | $.each(this.env.subscriptionrows, function(k,v) { |
| | | var n = v[0]; |
| | | n = n.replace(replace_from, replace_to); |
| | | v.push(n); |
| | | if (v.length < 4) { |
| | | var n = v[0]; |
| | | n = n.replace(replace_from, replace_to); |
| | | v.push(n); |
| | | } |
| | | folders.push(v); |
| | | }); |
| | | |
| | | folders.sort(function(a, b) { |
| | | var len = a.length - 1; n1 = a[len], n2 = b[len]; |
| | | return n1 < n2 ? -1 : 1; |
| | |
| | | // replace an existing table row with a new folder line (with subfolders) |
| | | this.replace_folder_row = function(oldfolder, newfolder, display_name, is_protected, class_name) |
| | | { |
| | | if (!this.gui_objects.subscriptionlist) |
| | | if (!this.gui_objects.subscriptionlist) { |
| | | if (this.is_framed) |
| | | return parent.rcmail.replace_folder_row(oldfolder, newfolder, display_name, is_protected, class_name); |
| | | return false; |
| | | } |
| | | |
| | | var i, n, len, name, dispname, oldrow, tmprow, row, level, |
| | | tbody = this.gui_objects.subscriptionlist.tBodies[0], |
| | |
| | | subscribed = $('input[name="_subscribed[]"]', $('#'+id)).prop('checked'), |
| | | // find subfolders of renamed folder |
| | | list = this.get_subfolders(oldfolder); |
| | | |
| | | // no renaming, only update class_name |
| | | if (oldfolder == newfolder) { |
| | | $('#'+id).attr('class', class_name || ''); |
| | | this.subscription_list.focus(); |
| | | return; |
| | | } |
| | | |
| | | // replace an existing table row |
| | | this._remove_folder_row(id); |
| | |
| | | this.env.quota_content = content; |
| | | }; |
| | | |
| | | // update trash folder state |
| | | this.set_trash_count = function(count) |
| | | { |
| | | this[(count ? 'un' : '') + 'mark_folder'](this.env.trash_mailbox, 'empty', '', true); |
| | | }; |
| | | |
| | | // update the mailboxlist |
| | | this.set_unread_count = function(mbox, count, set_title, mark) |
| | | { |
| | |
| | | $(elem).removeClass('hide-headers').addClass('show-headers'); |
| | | $(this.gui_objects.all_headers_row).hide(); |
| | | elem.onclick = function() { rcmail.command('show-headers', '', elem); }; |
| | | }; |
| | | |
| | | // create folder selector popup, position and display it |
| | | this.folder_selector = function(obj, callback) |
| | | { |
| | | var container = this.folder_selector_element; |
| | | |
| | | if (!container) { |
| | | var rows = [], |
| | | delim = this.env.delimiter, |
| | | ul = $('<ul class="toolbarmenu iconized">'), |
| | | li = document.createElement('li'), |
| | | link = document.createElement('a'), |
| | | span = document.createElement('span'); |
| | | |
| | | container = $('<div id="folder-selector" class="popupmenu"></div>'); |
| | | link.href = '#'; |
| | | link.className = 'icon'; |
| | | |
| | | // loop over sorted folders list |
| | | $.each(this.env.mailboxes_list, function() { |
| | | var tmp, n = 0, s = 0, |
| | | folder = ref.env.mailboxes[this], |
| | | id = folder.id, |
| | | a = link.cloneNode(false), row = li.cloneNode(false); |
| | | |
| | | if (folder.virtual) |
| | | a.className += ' virtual'; |
| | | else { |
| | | a.className += ' active'; |
| | | a.onclick = function() { container.hide().data('callback')(folder.id); }; |
| | | } |
| | | |
| | | if (folder['class']) |
| | | a.className += ' ' + folder['class']; |
| | | |
| | | // calculate/set indentation level |
| | | while ((s = id.indexOf(delim, s)) >= 0) { |
| | | n++; s++; |
| | | } |
| | | a.style.paddingLeft = n ? (n * 16) + 'px' : 0; |
| | | |
| | | // add folder name element |
| | | tmp = span.cloneNode(false); |
| | | $(tmp).text(folder.name); |
| | | a.appendChild(tmp); |
| | | |
| | | row.appendChild(a); |
| | | rows.push(row); |
| | | }); |
| | | |
| | | ul.append(rows).appendTo(container); |
| | | |
| | | // temporarily show element to calculate its size |
| | | container.css({left: '-1000px', top: '-1000px'}) |
| | | .appendTo($('body')).show(); |
| | | |
| | | // set max-height if the list is long |
| | | if (rows.length > 10) |
| | | container.css('max-height', $('li', container)[0].offsetHeight * 10 + 9) |
| | | |
| | | // hide selector on click out of selector element |
| | | var fn = function(e) { if (e.target != container.get(0)) container.hide(); }; |
| | | $(document.body).on('mouseup', fn); |
| | | $('iframe').contents().on('mouseup', fn) |
| | | .load(function(e) { try { $(this).contents().on('mouseup', fn); } catch(e) {}; }); |
| | | |
| | | this.folder_selector_element = container; |
| | | } |
| | | |
| | | // position menu on the screen |
| | | this.element_position(container, obj); |
| | | |
| | | container.show().data('callback', callback); |
| | | }; |
| | | |
| | | // position a menu element on the screen in relation to other object |
| | | this.element_position = function(element, obj) |
| | | { |
| | | var obj = $(obj), win = $(window), |
| | | width = obj.width(), |
| | | height = obj.height(), |
| | | win_height = win.height(), |
| | | elem_height = $(element).height(), |
| | | elem_width = $(element).width(), |
| | | pos = obj.offset(), |
| | | top = pos.top, |
| | | left = pos.left + width; |
| | | |
| | | if (top + elem_height > win_height) { |
| | | top -= elem_height - height; |
| | | if (top < 0) |
| | | top = Math.max(0, (win_height - elem_height) / 2); |
| | | } |
| | | |
| | | if (left + elem_width > win.width()) |
| | | left -= elem_width + width; |
| | | |
| | | element.css({left: left + 'px', top: top + 'px'}); |
| | | }; |
| | | |
| | | |
| | |
| | | |
| | | case 'refresh': |
| | | case 'check-recent': |
| | | // update message flags |
| | | $.each(this.env.recent_flags || {}, function(uid, flags) { |
| | | ref.set_message(uid, 'deleted', flags.deleted); |
| | | ref.set_message(uid, 'replied', flags.answered); |
| | | ref.set_message(uid, 'unread', !flags.seen); |
| | | ref.set_message(uid, 'forwarded', flags.forwarded); |
| | | ref.set_message(uid, 'flagged', flags.flagged); |
| | | }); |
| | | delete this.env.recent_flags; |
| | | |
| | | case 'getunread': |
| | | case 'search': |
| | | this.env.qsearch = null; |
| | |
| | | |
| | | if ((response.action == 'list' || response.action == 'search') && this.message_list) { |
| | | this.msglist_select(this.message_list); |
| | | this.message_list.resize(); |
| | | this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:this.message_list.rowcount }); |
| | | } |
| | | } |
| | |
| | | this.enable_command('search-create', this.env.source == ''); |
| | | this.enable_command('search-delete', this.env.search_id); |
| | | this.update_group_commands(); |
| | | this.contact_list.resize(); |
| | | this.triggerEvent('listupdate', { folder:this.env.source, rowcount:this.contact_list.rowcount }); |
| | | } |
| | | } |
| | |
| | | |
| | | if (this.submit_timer) |
| | | clearTimeout(this.submit_timer); |
| | | }; |
| | | |
| | | /** |
| | | Send multi-threaded parallel HTTP requests to the server for a list if items. |
| | | The string '%' in either a GET query or POST parameters will be replaced with the respective item value. |
| | | This is the argument object expected: { |
| | | items: ['foo','bar','gna'], // list of items to send requests for |
| | | action: 'task/some-action', // Roudncube action to call |
| | | query: { q:'%s' }, // GET query parameters |
| | | postdata: { source:'%s' }, // POST data (sends a POST request if present) |
| | | threads: 3, // max. number of concurrent requests |
| | | onresponse: function(data){ }, // Callback function called for every response received from server |
| | | whendone: function(alldata){ } // Callback function called when all requests have been sent |
| | | } |
| | | */ |
| | | this.multi_thread_http_request = function(prop) |
| | | { |
| | | var reqid = new Date().getTime(); |
| | | |
| | | prop.reqid = reqid; |
| | | prop.running = 0; |
| | | prop.requests = []; |
| | | prop.result = []; |
| | | prop._items = $.extend([], prop.items); // copy items |
| | | |
| | | if (!prop.lock) |
| | | prop.lock = this.display_message(this.get_label('loading'), 'loading'); |
| | | |
| | | // add the request arguments to the jobs pool |
| | | this.http_request_jobs[reqid] = prop; |
| | | |
| | | // start n threads |
| | | var item, threads = prop.threads || 1; |
| | | for (var i=0; i < threads; i++) { |
| | | item = prop._items.shift(); |
| | | if (item === undefined) |
| | | break; |
| | | |
| | | prop.running++; |
| | | prop.requests.push(this.multi_thread_send_request(prop, item)); |
| | | } |
| | | |
| | | return reqid; |
| | | }; |
| | | |
| | | // helper method to send an HTTP request with the given iterator value |
| | | this.multi_thread_send_request = function(prop, item) |
| | | { |
| | | var postdata, query; |
| | | |
| | | // replace %s in post data |
| | | if (prop.postdata) { |
| | | postdata = {}; |
| | | for (var k in prop.postdata) { |
| | | postdata[k] = String(prop.postdata[k]).replace('%s', item); |
| | | } |
| | | postdata._reqid = prop.reqid; |
| | | } |
| | | // replace %s in query |
| | | else if (typeof prop.query == 'string') { |
| | | query = prop.query.replace('%s', item); |
| | | query += '&_reqid=' + prop.reqid; |
| | | } |
| | | else if (typeof prop.query == 'object' && prop.query) { |
| | | query = {}; |
| | | for (var k in prop.query) { |
| | | query[k] = String(prop.query[k]).replace('%s', item); |
| | | } |
| | | query._reqid = prop.reqid; |
| | | } |
| | | |
| | | // send HTTP GET or POST request |
| | | return postdata ? this.http_post(prop.action, postdata) : this.http_request(prop.action, query); |
| | | }; |
| | | |
| | | // callback function for multi-threaded http responses |
| | | this.multi_thread_http_response = function(data, reqid) |
| | | { |
| | | var prop = this.http_request_jobs[reqid]; |
| | | if (!prop || prop.running <= 0 || prop.cancelled) |
| | | return; |
| | | |
| | | prop.running--; |
| | | |
| | | // trigger response callback |
| | | if (prop.onresponse && typeof prop.onresponse == 'function') { |
| | | prop.onresponse(data); |
| | | } |
| | | |
| | | prop.result = $.extend(prop.result, data); |
| | | |
| | | // send next request if prop.items is not yet empty |
| | | var item = prop._items.shift(); |
| | | if (item !== undefined) { |
| | | prop.running++; |
| | | prop.requests.push(this.multi_thread_send_request(prop, item)); |
| | | } |
| | | // trigger whendone callback and mark this request as done |
| | | else if (prop.running == 0) { |
| | | if (prop.whendone && typeof prop.whendone == 'function') { |
| | | prop.whendone(prop.result); |
| | | } |
| | | |
| | | this.set_busy(false, '', prop.lock); |
| | | |
| | | // remove from this.http_request_jobs pool |
| | | delete this.http_request_jobs[reqid]; |
| | | } |
| | | }; |
| | | |
| | | // abort a running multi-thread request with the given identifier |
| | | this.multi_thread_request_abort = function(reqid) |
| | | { |
| | | var prop = this.http_request_jobs[reqid]; |
| | | if (prop) { |
| | | for (var i=0; prop.running > 0 && i < prop.requests.length; i++) { |
| | | if (prop.requests[i].abort) |
| | | prop.requests[i].abort(); |
| | | } |
| | | |
| | | prop.running = 0; |
| | | prop.cancelled = true; |
| | | this.set_busy(false, '', prop.lock); |
| | | } |
| | | }; |
| | | |
| | | // post the given form to a hidden iframe |
| | |
| | | |
| | | if (this.gui_objects.mailboxlist) |
| | | params._folderlist = 1; |
| | | if (this.gui_objects.messagelist) |
| | | params._list = 1; |
| | | if (this.gui_objects.quotadisplay) |
| | | params._quota = 1; |
| | | if (this.env.search_request) |
| | | params._search = this.env.search_request; |
| | | |
| | | if (this.gui_objects.messagelist) { |
| | | params._list = 1; |
| | | |
| | | // message uids for flag updates check |
| | | params._uids = $.map(this.message_list.rows, function(row, uid) { return uid; }).join(','); |
| | | } |
| | | |
| | | return params; |
| | | }; |
| | | |