| | |
| | | // select first input field in an edit form |
| | | if (this.gui_objects.editform) |
| | | $("input,select,textarea", this.gui_objects.editform) |
| | | .not(':hidden').not(':disabled').first().select(); |
| | | .not(':hidden').not(':disabled').first().select().focus(); |
| | | |
| | | // unset contentframe variable if preview_pane is enabled |
| | | if (this.env.contentframe && !$('#' + this.env.contentframe).is(':visible')) |
| | |
| | | |
| | | // remove copy from local storage if compose screen is left intentionally |
| | | this.remove_compose_data(this.env.compose_id); |
| | | this.compose_skip_unsavedcheck = true; |
| | | } |
| | | |
| | | this.last_command = command; |
| | | |
| | | // process external commands |
| | | if (typeof this.command_handlers[command] === 'function') { |
| | | ret = this.command_handlers[command](props, obj); |
| | | ret = this.command_handlers[command](props, obj, event); |
| | | return ret !== undefined ? ret : (obj ? false : true); |
| | | } |
| | | else if (typeof this.command_handlers[command] === 'string') { |
| | | ret = window[this.command_handlers[command]](props, obj); |
| | | ret = window[this.command_handlers[command]](props, obj, event); |
| | | return ret !== undefined ? ret : (obj ? false : true); |
| | | } |
| | | |
| | |
| | | |
| | | if (win) { |
| | | this.save_compose_form_local(); |
| | | this.compose_skip_unsavedcheck = true; |
| | | $("input[name='_action']", form).val('compose'); |
| | | form.action = this.url('mail/compose', { _id: this.env.compose_id, _extwin: 1 }); |
| | | form.target = win.name; |
| | |
| | | |
| | | if (task == 'mail') |
| | | url += '&_mbox=INBOX'; |
| | | else if (task == 'logout') |
| | | else if (task == 'logout' && !this.env.server_error) |
| | | this.clear_compose_data(); |
| | | |
| | | this.redirect(url); |
| | |
| | | return (this.env.mailboxes[id] |
| | | && !this.env.mailboxes[id].virtual |
| | | && (this.env.mailboxes[id].id != this.env.mailbox || this.is_multifolder_listing())) ? 1 : 0; |
| | | |
| | | case 'settings': |
| | | return id != this.env.mailbox ? 1 : 0; |
| | | |
| | | case 'addressbook': |
| | | var target; |
| | |
| | | } |
| | | |
| | | // check for locally stored compose data |
| | | if (window.localStorage) { |
| | | var key, formdata, index = this.local_storage_get_item('compose.index', []); |
| | | |
| | | for (i = 0; i < index.length; i++) { |
| | | key = index[i]; |
| | | formdata = this.local_storage_get_item('compose.' + key, null, true); |
| | | if (!formdata) { |
| | | continue; |
| | | } |
| | | // restore saved copy of current compose_id |
| | | if (formdata.changed && key == this.env.compose_id) { |
| | | this.restore_compose_form(key, html_mode); |
| | | break; |
| | | } |
| | | // skip records from 'other' drafts |
| | | if (this.env.draft_id && formdata.draft_id && formdata.draft_id != this.env.draft_id) { |
| | | continue; |
| | | } |
| | | // skip records on reply |
| | | if (this.env.reply_msgid && formdata.reply_msgid != this.env.reply_msgid) { |
| | | continue; |
| | | } |
| | | // show dialog asking to restore the message |
| | | if (formdata.changed && formdata.session != this.env.session_id) { |
| | | this.show_popup_dialog( |
| | | this.get_label('restoresavedcomposedata') |
| | | .replace('$date', new Date(formdata.changed).toLocaleString()) |
| | | .replace('$subject', formdata._subject) |
| | | .replace(/\n/g, '<br/>'), |
| | | this.get_label('restoremessage'), |
| | | [{ |
| | | text: this.get_label('restore'), |
| | | click: function(){ |
| | | ref.restore_compose_form(key, html_mode); |
| | | ref.remove_compose_data(key); // remove old copy |
| | | ref.save_compose_form_local(); // save under current compose_id |
| | | $(this).dialog('close'); |
| | | } |
| | | }, |
| | | { |
| | | text: this.get_label('delete'), |
| | | click: function(){ |
| | | ref.remove_compose_data(key); |
| | | $(this).dialog('close'); |
| | | } |
| | | }, |
| | | { |
| | | text: this.get_label('ignore'), |
| | | click: function(){ |
| | | $(this).dialog('close'); |
| | | } |
| | | }] |
| | | ); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | this.compose_restore_dialog(0, html_mode) |
| | | |
| | | if (input_to.val() == '') |
| | | input_to.focus(); |
| | |
| | | // start the auto-save timer |
| | | this.auto_save_start(); |
| | | }; |
| | | |
| | | this.compose_restore_dialog = function(j, html_mode) |
| | | { |
| | | var i, key, formdata, index = this.local_storage_get_item('compose.index', []); |
| | | |
| | | var show_next = function(i) { |
| | | if (++i < index.length) |
| | | ref.compose_restore_dialog(i, html_mode) |
| | | } |
| | | |
| | | for (i = j || 0; i < index.length; i++) { |
| | | key = index[i]; |
| | | formdata = this.local_storage_get_item('compose.' + key, null, true); |
| | | if (!formdata) { |
| | | continue; |
| | | } |
| | | // restore saved copy of current compose_id |
| | | if (formdata.changed && key == this.env.compose_id) { |
| | | this.restore_compose_form(key, html_mode); |
| | | break; |
| | | } |
| | | // skip records from 'other' drafts |
| | | if (this.env.draft_id && formdata.draft_id && formdata.draft_id != this.env.draft_id) { |
| | | continue; |
| | | } |
| | | // skip records on reply |
| | | if (this.env.reply_msgid && formdata.reply_msgid != this.env.reply_msgid) { |
| | | continue; |
| | | } |
| | | // show dialog asking to restore the message |
| | | if (formdata.changed && formdata.session != this.env.session_id) { |
| | | this.show_popup_dialog( |
| | | this.get_label('restoresavedcomposedata') |
| | | .replace('$date', new Date(formdata.changed).toLocaleString()) |
| | | .replace('$subject', formdata._subject) |
| | | .replace(/\n/g, '<br/>'), |
| | | this.get_label('restoremessage'), |
| | | [{ |
| | | text: this.get_label('restore'), |
| | | click: function(){ |
| | | ref.restore_compose_form(key, html_mode); |
| | | ref.remove_compose_data(key); // remove old copy |
| | | ref.save_compose_form_local(); // save under current compose_id |
| | | $(this).dialog('close'); |
| | | } |
| | | }, |
| | | { |
| | | text: this.get_label('delete'), |
| | | click: function(){ |
| | | ref.remove_compose_data(key); |
| | | $(this).dialog('close'); |
| | | show_next(i); |
| | | } |
| | | }, |
| | | { |
| | | text: this.get_label('ignore'), |
| | | click: function(){ |
| | | $(this).dialog('close'); |
| | | show_next(i); |
| | | } |
| | | }] |
| | | ); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | this.init_address_input_events = function(obj, props) |
| | | { |
| | |
| | | form._draft.value = draft ? '1' : ''; |
| | | 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); |
| | | |
| | | // register timer to notify about connection timeout |
| | | this.submit_timer = setTimeout(function(){ |
| | |
| | | // submit delete request |
| | | if (key && confirm(this.get_label('deleteresponseconfirm'))) { |
| | | this.http_post('settings/delete-response', { _key: key }, false); |
| | | return true; |
| | | } |
| | | |
| | | return false; |
| | | }; |
| | | |
| | | // updates spellchecker buttons on state change |
| | |
| | | |
| | | // always remove local copy upon saving as draft |
| | | this.remove_compose_data(this.env.compose_id); |
| | | this.compose_skip_unsavedcheck = false; |
| | | }; |
| | | |
| | | this.auto_save_start = function() |
| | |
| | | ref.compose_type_activity_last = ref.compose_type_activity; |
| | | } |
| | | }, 5000); |
| | | |
| | | $(window).unload(function() { |
| | | // remove copy from local storage if compose screen is left after warning |
| | | if (!ref.env.server_error) |
| | | ref.remove_compose_data(ref.env.compose_id); |
| | | }); |
| | | } |
| | | |
| | | // check for unsaved changes before leaving the compose page |
| | | if (!window.onbeforeunload) { |
| | | window.onbeforeunload = function() { |
| | | if (!ref.compose_skip_unsavedcheck && ref.cmp_hash != ref.compose_field_hash()) { |
| | | return ref.get_label('notsentwarning'); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | // Unlock interface now that saving is complete |
| | |
| | | } |
| | | }); |
| | | |
| | | if (window.localStorage && !empty) { |
| | | if (!empty) { |
| | | var index = this.local_storage_get_item('compose.index', []), |
| | | key = this.env.compose_id; |
| | | |
| | | if ($.inArray(key, index) < 0) { |
| | | index.push(key); |
| | | } |
| | | this.local_storage_set_item('compose.' + key, formdata, true); |
| | | this.local_storage_set_item('compose.index', index); |
| | | if ($.inArray(key, index) < 0) { |
| | | index.push(key); |
| | | } |
| | | |
| | | this.local_storage_set_item('compose.' + key, formdata, true); |
| | | this.local_storage_set_item('compose.index', index); |
| | | } |
| | | }; |
| | | |
| | |
| | | // remove stored compose data from localStorage |
| | | this.remove_compose_data = function(key) |
| | | { |
| | | if (window.localStorage) { |
| | | var index = this.local_storage_get_item('compose.index', []); |
| | | var index = this.local_storage_get_item('compose.index', []); |
| | | |
| | | if ($.inArray(key, index) >= 0) { |
| | | this.local_storage_remove_item('compose.' + key); |
| | | this.local_storage_set_item('compose.index', $.grep(index, function(val,i) { return val != key; })); |
| | | } |
| | | if ($.inArray(key, index) >= 0) { |
| | | this.local_storage_remove_item('compose.' + key); |
| | | this.local_storage_set_item('compose.index', $.grep(index, function(val,i) { return val != key; })); |
| | | } |
| | | }; |
| | | |
| | | // clear all stored compose data of this user |
| | | this.clear_compose_data = function() |
| | | { |
| | | if (window.localStorage) { |
| | | var i, index = this.local_storage_get_item('compose.index', []); |
| | | var i, index = this.local_storage_get_item('compose.index', []); |
| | | |
| | | for (i=0; i < index.length; i++) { |
| | | this.local_storage_remove_item('compose.' + index[i]); |
| | | } |
| | | this.local_storage_remove_item('compose.index'); |
| | | for (i=0; i < index.length; i++) { |
| | | this.local_storage_remove_item('compose.' + index[i]); |
| | | } |
| | | |
| | | this.local_storage_remove_item('compose.index'); |
| | | }; |
| | | |
| | | |
| | |
| | | return; |
| | | } |
| | | |
| | | var i, rx, |
| | | id = obj.options[obj.selectedIndex].value, |
| | | var id = obj.options[obj.selectedIndex].value, |
| | | sig = this.env.identity, |
| | | delim = this.env.recipients_separator, |
| | | rx_delim = RegExp.escape(delim), |
| | | headers = ['replyto', 'bcc']; |
| | | rx_delim = RegExp.escape(delim); |
| | | |
| | | // update reply-to/bcc fields with addresses defined in identities |
| | | for (i in headers) { |
| | | var key = headers[i], |
| | | old_val = sig && this.env.identities[sig] ? this.env.identities[sig][key] : '', |
| | | new_val = id && this.env.identities[id] ? this.env.identities[id][key] : '', |
| | | $.each(['replyto', 'bcc'], function() { |
| | | var rx, key = this, |
| | | old_val = sig && ref.env.identities[sig] ? ref.env.identities[sig][key] : '', |
| | | new_val = id && ref.env.identities[id] ? ref.env.identities[id][key] : '', |
| | | input = $('[name="_'+key+'"]'), input_val = input.val(); |
| | | |
| | | // remove old address(es) |
| | |
| | | |
| | | if (old_val || new_val) |
| | | input.val(input_val).change(); |
| | | } |
| | | }); |
| | | |
| | | // enable manual signature insert |
| | | if (this.env.signatures && this.env.signatures[id]) { |
| | |
| | | this.sent_successfully = function(type, msg, folders) |
| | | { |
| | | this.display_message(msg, type); |
| | | this.compose_skip_unsavedcheck = true; |
| | | |
| | | if (this.env.extwin) { |
| | | this.lock_form(this.gui_objects.messageform); |
| | |
| | | this.ksearch_pane = $('<div>').attr('id', 'rcmKSearchpane').attr('role', 'listbox') |
| | | .css({ position:'absolute', 'z-index':30000 }).append(ul).appendTo(document.body); |
| | | this.ksearch_pane.__ul = ul[0]; |
| | | |
| | | // register (delegate) event handlers |
| | | ul.on('mouseover', 'li', function(e){ ref.ksearch_select(e.target); }) |
| | | .on('mouseup', 'li', function(e){ ref.ksearch_click(e.target); }) |
| | | } |
| | | |
| | | ul = this.ksearch_pane.__ul; |
| | |
| | | // add each result line to list |
| | | if (results && (len = results.length)) { |
| | | for (i=0; i < len && maxlen > 0; i++) { |
| | | text = typeof results[i] === 'object' ? results[i].name : results[i]; |
| | | text = typeof results[i] === 'object' ? (results[i].display || results[i].name) : results[i]; |
| | | type = typeof results[i] === 'object' ? results[i].type : ''; |
| | | id = i + this.env.contacts.length; |
| | | $('<li>').attr('id', 'rcmkSearchItem' + id) |
| | |
| | | .html(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); }) |
| | | .mouseup(function() { ref.ksearch_click(this); }) |
| | | .get(0)._rcm_id = id; |
| | | maxlen -= 1; |
| | | } |
| | |
| | | id = this.env.iid ? this.env.iid : selection[0]; |
| | | |
| | | // submit request with appended token |
| | | if (confirm(this.get_label('deleteidentityconfirm'))) |
| | | this.goto_url('delete-identity', { _iid: id, _token: this.env.request_token }, true); |
| | | |
| | | return true; |
| | | if (id && confirm(this.get_label('deleteidentityconfirm'))) |
| | | this.http_post('settings/delete-identity', { _iid: id }, true); |
| | | }; |
| | | |
| | | this.update_identity_row = function(id, name, add) |
| | |
| | | frame.location.href = this.env.blankpage; |
| | | } |
| | | } |
| | | |
| | | this.enable_command('delete', false); |
| | | }; |
| | | |
| | | this.remove_identity = function(id) |
| | | { |
| | | var frame, list = this.identity_list, |
| | | rid = this.html_identifier(id); |
| | | |
| | | if (list && id) { |
| | | list.remove_row(rid); |
| | | if (this.env.contentframe && (frame = this.get_frame_window(this.env.contentframe))) { |
| | | frame.location.href = this.env.blankpage; |
| | | } |
| | | } |
| | | |
| | | this.enable_command('delete', false); |
| | | }; |
| | | |
| | | |
| | |
| | | |
| | | this.last_sub_rx = RegExp('['+delim+']?[^'+delim+']+$'); |
| | | |
| | | this.subscription_list = new rcube_list_widget(this.gui_objects.subscriptionlist, |
| | | {multiselect:false, draggable:true, keyboard:true, toggleselect:true}); |
| | | this.subscription_list = new rcube_treelist_widget(this.gui_objects.subscriptionlist, { |
| | | selectable: true, |
| | | id_prefix: 'rcmli', |
| | | id_encode: this.html_identifier_encode, |
| | | id_decode: this.html_identifier_decode |
| | | }); |
| | | |
| | | this.subscription_list |
| | | .addEventListener('select', function(o){ ref.subscription_select(o); }) |
| | | .addEventListener('dragstart', function(o){ ref.drag_active = true; }) |
| | | .addEventListener('dragend', function(o){ ref.subscription_move_folder(o); }) |
| | | .addEventListener('initrow', function (row) { |
| | | row.obj.onmouseover = function() { ref.focus_subscription(row.id); }; |
| | | row.obj.onmouseout = function() { ref.unfocus_subscription(row.id); }; |
| | | }) |
| | | .init() |
| | | .focus(); |
| | | .addEventListener('select', function(node) { ref.subscription_select(node.id); }) |
| | | .addEventListener('collapse', function(node) { ref.folder_collapsed(node) }) |
| | | .addEventListener('expand', function(node) { ref.folder_collapsed(node) }) |
| | | .draggable({cancel: 'li.mailbox.root'}) |
| | | .droppable({ |
| | | // @todo: find better way, accept callback is executed for every folder |
| | | // 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) { |
| | | var source_folder = ref.folder_id2name($(node).attr('id')), |
| | | dest_folder = ref.folder_id2name(this.id), |
| | | source = ref.env.subscriptionrows[source_folder], |
| | | dest = ref.env.subscriptionrows[dest_folder]; |
| | | |
| | | $('#mailboxroot') |
| | | .mouseover(function(){ ref.focus_subscription(this.id); }) |
| | | .mouseout(function(){ ref.unfocus_subscription(this.id); }) |
| | | }; |
| | | return source && !source[2] |
| | | && dest_folder != source_folder.replace(ref.last_sub_rx, '') |
| | | && !dest_folder.startsWith(source_folder + ref.env.delimiter); |
| | | }, |
| | | drop: function(e, ui) { |
| | | var source = ref.folder_id2name(ui.draggable.attr('id')), |
| | | dest = ref.folder_id2name(this.id); |
| | | |
| | | this.focus_subscription = function(id) |
| | | { |
| | | var row, folder; |
| | | |
| | | if (this.drag_active && this.env.mailbox && (row = document.getElementById(id))) |
| | | if (this.env.subscriptionrows[id] && |
| | | (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(this.last_sub_rx, '') && |
| | | !folder.startsWith(this.env.mailbox + this.env.delimiter) |
| | | ) { |
| | | this.env.dstfolder = folder; |
| | | $(row).addClass('droptarget'); |
| | | ref.subscription_move_folder(source, dest); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | this.unfocus_subscription = function(id) |
| | | this.folder_id2name = function(id) |
| | | { |
| | | var row = $('#'+id); |
| | | |
| | | this.env.dstfolder = null; |
| | | |
| | | if (row.length && this.env.subscriptionrows[id]) |
| | | row.removeClass('droptarget'); |
| | | else |
| | | $(this.subscription_list.frame).removeClass('droptarget'); |
| | | return ref.html_identifier_decode(id.replace(/^rcmli/, '')); |
| | | }; |
| | | |
| | | this.subscription_select = function(list) |
| | | this.subscription_select = function(id) |
| | | { |
| | | var id, folder; |
| | | var folder; |
| | | |
| | | if (list && (id = list.get_single_selection()) && |
| | | (folder = this.env.subscriptionrows['rcmrow'+id]) |
| | | ) { |
| | | this.env.mailbox = folder[0]; |
| | | this.show_folder(folder[0]); |
| | | if (id && id != '*' && (folder = this.env.subscriptionrows[id])) { |
| | | this.env.mailbox = id; |
| | | this.show_folder(id); |
| | | this.enable_command('delete-folder', !folder[2]); |
| | | } |
| | | else { |
| | |
| | | } |
| | | }; |
| | | |
| | | this.subscription_move_folder = function(list) |
| | | this.subscription_move_folder = function(from, to) |
| | | { |
| | | if (this.env.mailbox && this.env.dstfolder !== null && |
| | | this.env.dstfolder != this.env.mailbox && |
| | | this.env.dstfolder != this.env.mailbox.replace(this.last_sub_rx, '') |
| | | ) { |
| | | var path = this.env.mailbox.split(this.env.delimiter), |
| | | if (from && to !== null && from != to && to != from.replace(this.last_sub_rx, '')) { |
| | | var path = from.split(this.env.delimiter), |
| | | basename = path.pop(), |
| | | newname = this.env.dstfolder === '' ? basename : this.env.dstfolder + this.env.delimiter + basename; |
| | | newname = to === '' || to === '*' ? basename : to + this.env.delimiter + basename; |
| | | |
| | | if (newname != this.env.mailbox) { |
| | | this.http_post('rename-folder', {_folder_oldname: this.env.mailbox, _folder_newname: newname}, this.set_busy(true, 'foldermoving')); |
| | | this.subscription_list.draglayer.hide(); |
| | | if (newname != from) { |
| | | this.http_post('rename-folder', {_folder_oldname: from, _folder_newname: newname}, |
| | | this.set_busy(true, 'foldermoving')); |
| | | } |
| | | } |
| | | |
| | | this.drag_active = false; |
| | | this.unfocus_subscription(this.get_folder_row_id(this.env.dstfolder)); |
| | | }; |
| | | |
| | | // tell server to create and subscribe a new mailbox |
| | |
| | | // delete a specific mailbox with all its messages |
| | | this.delete_folder = function(name) |
| | | { |
| | | var id = this.get_folder_row_id(name ? name : this.env.mailbox), |
| | | folder = this.env.subscriptionrows[id][0]; |
| | | if (!name) |
| | | name = this.env.mailbox; |
| | | |
| | | if (folder && confirm(this.get_label('deletefolderconfirm'))) { |
| | | var lock = this.set_busy(true, 'folderdeleting'); |
| | | this.http_post('delete-folder', {_mbox: folder}, lock); |
| | | if (name && confirm(this.get_label('deletefolderconfirm'))) { |
| | | this.http_post('delete-folder', {_mbox: name}, this.set_busy(true, 'folderdeleting')); |
| | | } |
| | | }; |
| | | |
| | | // Add folder row to the table and initialize it |
| | | this.add_folder_row = function (name, display_name, is_protected, subscribed, skip_init, class_name) |
| | | this.add_folder_row = function (id, name, display_name, is_protected, subscribed, class_name, refrow, subfolders) |
| | | { |
| | | if (!this.gui_objects.subscriptionlist) |
| | | return false; |
| | | |
| | | var row, n, tmp, tmp_name, rowid, collator, |
| | | folders = [], list = [], slist = [], |
| | | tbody = this.gui_objects.subscriptionlist.tBodies[0], |
| | | refrow = $('tr', tbody).get(1), |
| | | id = 'rcmrow'+((new Date).getTime()); |
| | | // disable drag-n-drop temporarily |
| | | this.subscription_list.draggable('destroy').droppable('destroy'); |
| | | |
| | | if (!refrow) { |
| | | var row, n, tmp, tmp_name, rowid, collator, pos, p, parent = '', |
| | | folders = [], list = [], slist = [], |
| | | list_element = $(this.gui_objects.subscriptionlist); |
| | | row = refrow ? refrow : $($('li', list_element).get(1)).clone(true); |
| | | |
| | | if (!row.length) { |
| | | // Refresh page if we don't have a table row to clone |
| | | this.goto_url('folders'); |
| | | return false; |
| | | } |
| | | |
| | | // clone a table row if there are existing rows |
| | | row = $(refrow).clone(true); |
| | | |
| | | // set ID, reset css class |
| | | row.attr({id: id, 'class': class_name}); |
| | | row.attr({id: 'rcmli' + this.html_identifier_encode(id), 'class': class_name}); |
| | | |
| | | if (!refrow || !refrow.length) { |
| | | // remove old subfolders and toggle |
| | | $('ul,div.treetoggle', row).remove(); |
| | | } |
| | | |
| | | // set folder name |
| | | row.find('td:first').html(display_name); |
| | | $('a:first', row).text(display_name); |
| | | |
| | | // update subscription checkbox |
| | | $('input[name="_subscribed[]"]', row).val(name) |
| | | $('input[name="_subscribed[]"]:first', row).val(id) |
| | | .prop({checked: subscribed ? true : false, disabled: is_protected ? true : false}); |
| | | |
| | | // add to folder/row-ID map |
| | | this.env.subscriptionrows[id] = [name, display_name, false]; |
| | | |
| | | // copy folders data to an array for sorting |
| | | $.each(this.env.subscriptionrows, function(k, v) { folders.push(v); }); |
| | | $.each(this.env.subscriptionrows, function(k, v) { v[3] = k; folders.push(v); }); |
| | | |
| | | try { |
| | | // use collator if supported (FF29, IE11, Opera15, Chrome24) |
| | |
| | | folders.sort(function(a, b) { |
| | | var i, f1, f2, |
| | | path1 = a[0].split(ref.env.delimiter), |
| | | path2 = b[0].split(ref.env.delimiter); |
| | | path2 = b[0].split(ref.env.delimiter), |
| | | len = path1.length; |
| | | |
| | | for (i=0; i<path1.length; i++) { |
| | | for (i=0; i<len; i++) { |
| | | f1 = path1[i]; |
| | | f2 = path2[i]; |
| | | |
| | | if (f1 !== f2) { |
| | | if (f2 === undefined) |
| | | return 1; |
| | | if (collator) |
| | | return collator.compare(f1, f2); |
| | | else |
| | | return f1 < f2 ? -1 : 1; |
| | | } |
| | | else if (i == len-1) { |
| | | return -1 |
| | | } |
| | | } |
| | | }); |
| | | |
| | | for (n in folders) { |
| | | p = folders[n][3]; |
| | | // protected folder |
| | | if (folders[n][2]) { |
| | | tmp_name = folders[n][0] + this.env.delimiter; |
| | | tmp_name = p + this.env.delimiter; |
| | | // prefix namespace cannot have subfolders (#1488349) |
| | | if (tmp_name == this.env.prefix_ns) |
| | | continue; |
| | | slist.push(folders[n][0]); |
| | | slist.push(p); |
| | | tmp = tmp_name; |
| | | } |
| | | // protected folder's child |
| | | else if (tmp && folders[n][0].startsWith(tmp)) |
| | | slist.push(folders[n][0]); |
| | | else if (tmp && p.startsWith(tmp)) |
| | | slist.push(p); |
| | | // other |
| | | else { |
| | | list.push(folders[n][0]); |
| | | list.push(p); |
| | | tmp = null; |
| | | } |
| | | } |
| | | |
| | | // check if subfolder of a protected folder |
| | | for (n=0; n<slist.length; n++) { |
| | | if (name.startsWith(slist[n] + this.env.delimiter)) |
| | | rowid = this.get_folder_row_id(slist[n]); |
| | | if (id.startsWith(slist[n] + this.env.delimiter)) |
| | | rowid = slist[n]; |
| | | } |
| | | |
| | | // find folder position after sorting |
| | | for (n=0; !rowid && n<list.length; n++) { |
| | | if (n && list[n] == name) |
| | | rowid = this.get_folder_row_id(list[n-1]); |
| | | if (n && list[n] == id) |
| | | rowid = list[n-1]; |
| | | } |
| | | |
| | | // add row to the table |
| | | if (rowid) |
| | | $('#'+rowid).after(row); |
| | | else |
| | | row.appendTo(tbody); |
| | | if (rowid && (n = this.subscription_list.get_item(rowid, true))) { |
| | | // find parent folder |
| | | if (pos = id.lastIndexOf(this.env.delimiter)) { |
| | | parent = id.substring(0, pos); |
| | | parent = this.subscription_list.get_item(parent, true); |
| | | |
| | | // add required tree elements to the parent if not already there |
| | | if (!$('div.treetoggle', parent).length) { |
| | | $('<div> </div>').addClass('treetoggle collapsed').appendTo(parent); |
| | | } |
| | | if (!$('ul', parent).length) { |
| | | $('<ul>').css('display', 'none').appendTo(parent); |
| | | } |
| | | } |
| | | |
| | | if (parent && n == parent) { |
| | | $('ul:first', parent).append(row); |
| | | } |
| | | else { |
| | | while (p = $(n).parent().parent().get(0)) { |
| | | if (parent && p == parent) |
| | | break; |
| | | if (!$(p).is('li.mailbox')) |
| | | break; |
| | | n = p; |
| | | } |
| | | |
| | | $(n).after(row); |
| | | } |
| | | } |
| | | else { |
| | | list_element.append(row); |
| | | } |
| | | |
| | | // add subfolders |
| | | $.extend(this.env.subscriptionrows, subfolders || {}); |
| | | |
| | | // update list widget |
| | | this.subscription_list.clear_selection(); |
| | | if (!skip_init) |
| | | this.init_subscription_list(); |
| | | this.subscription_list.reset(true); |
| | | this.subscription_select(); |
| | | |
| | | // expand parent |
| | | if (parent) { |
| | | this.subscription_list.expand(this.folder_id2name(parent.id)); |
| | | } |
| | | |
| | | row = row.get(0); |
| | | if (row.scrollIntoView) |
| | |
| | | }; |
| | | |
| | | // 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) |
| | | this.replace_folder_row = function(oldid, id, name, display_name, is_protected, class_name) |
| | | { |
| | | if (!this.gui_objects.subscriptionlist) { |
| | | if (this.is_framed) |
| | | return parent.rcmail.replace_folder_row(oldfolder, newfolder, display_name, is_protected, class_name); |
| | | return parent.rcmail.replace_folder_row(oldid, id, name, 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], |
| | | folders = this.env.subscriptionrows, |
| | | id = this.get_folder_row_id(oldfolder), |
| | | prefix_len = oldfolder.length, |
| | | subscribed = $('input[name="_subscribed[]"]', $('#'+id)).prop('checked'), |
| | | // find subfolders of renamed folder |
| | | list = this.get_subfolders(oldfolder); |
| | | var subfolders = {}, |
| | | row = this.subscription_list.get_item(oldid, true), |
| | | parent = $(row).parent(), |
| | | old_folder = this.env.subscriptionrows[oldid], |
| | | prefix_len_id = oldid.length, |
| | | prefix_len_name = old_folder[0].length, |
| | | subscribed = $('input[name="_subscribed[]"]:first', row).prop('checked'); |
| | | |
| | | // no renaming, only update class_name |
| | | if (oldfolder == newfolder) { |
| | | $('#'+id).attr('class', class_name || ''); |
| | | this.subscription_list.focus(); |
| | | if (oldid == id) { |
| | | $(row).attr('class', class_name || ''); |
| | | return; |
| | | } |
| | | |
| | | // replace an existing table row |
| | | this._remove_folder_row(id); |
| | | row = $(this.add_folder_row(newfolder, display_name, is_protected, subscribed, true, class_name)); |
| | | // update subfolders |
| | | $('li', row).each(function() { |
| | | var fname = ref.folder_id2name(this.id), |
| | | folder = ref.env.subscriptionrows[fname], |
| | | newid = id + fname.slice(prefix_len_id); |
| | | |
| | | // detect tree depth change |
| | | if (len = list.length) { |
| | | level = (oldfolder.split(this.env.delimiter)).length - (newfolder.split(this.env.delimiter)).length; |
| | | this.id = 'rcmli' + ref.html_identifier_encode(newid); |
| | | $('input[name="_subscribed[]"]:first', this).val(newid); |
| | | folder[0] = name + folder[0].slice(prefix_len_name); |
| | | |
| | | subfolders[newid] = folder; |
| | | delete ref.env.subscriptionrows[fname]; |
| | | }); |
| | | |
| | | // get row off the list |
| | | row = $(row).detach(); |
| | | |
| | | delete this.env.subscriptionrows[oldid]; |
| | | |
| | | // remove parent list/toggle elements if not needed |
| | | if (parent.get(0) != this.gui_objects.subscriptionlist && !$('li', parent).length) { |
| | | $('ul,div.treetoggle', parent.parent()).remove(); |
| | | } |
| | | |
| | | // move subfolders to the new branch |
| | | for (n=0; n<len; n++) { |
| | | id = list[n]; |
| | | name = this.env.subscriptionrows[id][0]; |
| | | dispname = this.env.subscriptionrows[id][1]; |
| | | oldrow = $('#'+id); |
| | | tmprow = oldrow.clone(true); |
| | | oldrow.remove(); |
| | | row.after(tmprow); |
| | | row = tmprow; |
| | | // update folder index |
| | | name = newfolder + name.slice(prefix_len); |
| | | $('input[name="_subscribed[]"]', row).val(name); |
| | | this.env.subscriptionrows[id][0] = name; |
| | | // update the name if level is changed |
| | | if (level != 0) { |
| | | if (level > 0) { |
| | | for (i=level; i>0; i--) |
| | | dispname = dispname.replace(/^ /, ''); |
| | | } |
| | | else { |
| | | for (i=level; i<0; i++) |
| | | dispname = ' ' + dispname; |
| | | } |
| | | row.find('td:first').html(dispname); |
| | | this.env.subscriptionrows[id][1] = dispname; |
| | | } |
| | | } |
| | | |
| | | // update list widget |
| | | this.init_subscription_list(); |
| | | // move the existing table row |
| | | this.add_folder_row(id, name, display_name, is_protected, subscribed, class_name, row, subfolders); |
| | | }; |
| | | |
| | | // remove the table row of a specific mailbox from the table |
| | | this.remove_folder_row = function(folder, subs) |
| | | this.remove_folder_row = function(folder) |
| | | { |
| | | var n, len, list = [], id = this.get_folder_row_id(folder); |
| | | var list = [], row = this.subscription_list.get_item(folder, true); |
| | | |
| | | // get subfolders if any |
| | | if (subs) |
| | | list = this.get_subfolders(folder); |
| | | $('li', row).each(function() { list.push(ref.folder_id2name(this.id)); }); |
| | | |
| | | // remove old row |
| | | this._remove_folder_row(id); |
| | | // remove folder row (and subfolders) |
| | | this.subscription_list.remove(folder); |
| | | |
| | | // remove subfolders |
| | | for (n=0, len=list.length; n<len; n++) |
| | | this._remove_folder_row(list[n]); |
| | | }; |
| | | |
| | | this._remove_folder_row = function(id) |
| | | { |
| | | this.subscription_list.remove_row(id.replace(/^rcmrow/, '')); |
| | | $('#'+id).remove(); |
| | | delete this.env.subscriptionrows[id]; |
| | | }; |
| | | |
| | | this.get_subfolders = function(folder) |
| | | { |
| | | var name, list = [], |
| | | prefix = folder + this.env.delimiter, |
| | | row = $('#'+this.get_folder_row_id(folder)).get(0); |
| | | |
| | | while (row = row.nextSibling) { |
| | | if (row.id) { |
| | | name = this.env.subscriptionrows[row.id][0]; |
| | | if (name && name.startsWith(prefix)) { |
| | | list.push(row.id); |
| | | } |
| | | else |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return list; |
| | | // update local list variable |
| | | list.push(folder); |
| | | $.each(list, function(i, v) { delete ref.env.subscriptionrows[v]; }); |
| | | }; |
| | | |
| | | this.subscribe = function(folder) |
| | |
| | | var lock = this.display_message(this.get_label('folderunsubscribing'), 'loading'); |
| | | this.http_post('unsubscribe', {_mbox: folder}, lock); |
| | | } |
| | | }; |
| | | |
| | | // helper method to find a specific mailbox row ID |
| | | this.get_folder_row_id = function(folder) |
| | | { |
| | | var id, folders = this.env.subscriptionrows; |
| | | for (id in folders) |
| | | if (folders[id] && folders[id][0] == folder) |
| | | return id; |
| | | }; |
| | | |
| | | // when user select a folder in manager |
| | |
| | | // disables subscription checkbox (for protected folder) |
| | | this.disable_subscription = function(folder) |
| | | { |
| | | var id = this.get_folder_row_id(folder); |
| | | if (id) |
| | | $('input[name="_subscribed[]"]', $('#'+id)).prop('disabled', true); |
| | | var row = this.subscription_list.get_item(folder, true); |
| | | if (row) |
| | | $('input[name="_subscribed[]"]:first', row).prop('disabled', true); |
| | | }; |
| | | |
| | | this.folder_size = function(folder) |
| | |
| | | // save message in local storage and do not redirect |
| | | if (this.env.action == 'compose') { |
| | | this.save_compose_form_local(); |
| | | this.compose_skip_unsavedcheck = true; |
| | | } |
| | | else if (redirect_url) { |
| | | setTimeout(function(){ ref.redirect(redirect_url, true); }, 2000); |
| | |
| | | // wrapper for localStorage.getItem(key) |
| | | this.local_storage_get_item = function(key, deflt, encrypted) |
| | | { |
| | | var item; |
| | | |
| | | // TODO: add encryption |
| | | var item = localStorage.getItem(this.get_local_storage_prefix() + key); |
| | | try { |
| | | item = localStorage.getItem(this.get_local_storage_prefix() + key); |
| | | } |
| | | catch (e) { } |
| | | |
| | | return item !== null ? JSON.parse(item) : (deflt || null); |
| | | }; |
| | | |
| | | // wrapper for localStorage.setItem(key, data) |
| | | this.local_storage_set_item = function(key, data, encrypted) |
| | | { |
| | | // TODO: add encryption |
| | | return localStorage.setItem(this.get_local_storage_prefix() + key, JSON.stringify(data)); |
| | | // try/catch to handle no localStorage support, but also error |
| | | // in Safari-in-private-browsing-mode where localStorage exists |
| | | // but can't be used (#1489996) |
| | | try { |
| | | // TODO: add encryption |
| | | localStorage.setItem(this.get_local_storage_prefix() + key, JSON.stringify(data)); |
| | | return true; |
| | | } |
| | | catch (e) { |
| | | return false; |
| | | } |
| | | }; |
| | | |
| | | // wrapper for localStorage.removeItem(key) |
| | | this.local_storage_remove_item = function(key) |
| | | { |
| | | return localStorage.removeItem(this.get_local_storage_prefix() + key); |
| | | try { |
| | | localStorage.removeItem(this.get_local_storage_prefix() + key); |
| | | return true; |
| | | } |
| | | catch (e) { |
| | | return false; |
| | | } |
| | | }; |
| | | } // end object rcube_webmail |
| | | |