| | |
| | | }; |
| | | |
| | | // add a localized label to the client environment |
| | | this.add_label = function(key, value) |
| | | this.add_label = function(p, value) |
| | | { |
| | | this.labels[key] = value; |
| | | if (typeof p == 'string') |
| | | this.labels[p] = value; |
| | | else if (typeof p == 'object') |
| | | $.extend(this.labels, p); |
| | | }; |
| | | |
| | | // add a button to the button list |
| | |
| | | |
| | | break; |
| | | |
| | | |
| | | case 'addressbook': |
| | | if (this.gui_objects.folderlist) |
| | | this.env.contactfolders = $.extend($.extend({}, this.env.address_sources), this.env.contactgroups); |
| | |
| | | if (this.gui_objects.qsearchbox) { |
| | | $(this.gui_objects.qsearchbox).focusin(function() { rcmail.contact_list.blur(); }); |
| | | } |
| | | |
| | | this.enable_command('group-create', this.env.address_sources[this.env.source].groups); |
| | | } |
| | | |
| | | this.set_page_buttons(); |
| | | |
| | | if (this.env.address_sources && this.env.address_sources[this.env.source] && !this.env.address_sources[this.env.source].readonly) { |
| | | this.enable_command('add', 'import', true); |
| | | this.enable_command('group-create', this.env.address_sources[this.env.source].groups); |
| | | } |
| | | |
| | | if (this.env.cid) { |
| | | this.enable_command('show', 'edit', true); |
| | |
| | | } |
| | | } |
| | | |
| | | if ((this.env.action == 'add' || this.env.action == 'edit') && this.gui_objects.editform) { |
| | | if (this.gui_objects.editform) { |
| | | this.enable_command('save', true); |
| | | this.init_contact_form(); |
| | | if (this.env.action == 'add' || this.env.action == 'edit') |
| | | this.init_contact_form(); |
| | | } |
| | | else if (this.gui_objects.qsearchbox) { |
| | | if (this.gui_objects.qsearchbox) { |
| | | this.enable_command('search', 'reset-search', 'moveto', true); |
| | | $(this.gui_objects.qsearchbox).select(); |
| | | } |
| | |
| | | if (this.contact_list && this.contact_list.rowcount > 0) |
| | | this.enable_command('export', true); |
| | | |
| | | this.enable_command('list', 'listgroup', true); |
| | | this.enable_command('add', 'import', this.env.writable_source); |
| | | this.enable_command('list', 'listgroup', 'advanced-search', true); |
| | | break; |
| | | |
| | | |
| | |
| | | if (this.env.trash_mailbox) |
| | | this.set_alttext('delete', this.env.mailbox != this.env.trash_mailbox ? 'movemessagetotrash' : 'deletemessage'); |
| | | } |
| | | else if (this.task=='addressbook') { |
| | | else if (this.task == 'addressbook') { |
| | | if (!this.env.search_request || (props != this.env.source)) |
| | | this.reset_qsearch(); |
| | | |
| | | this.list_contacts(props); |
| | | this.enable_command('add', 'import', (this.env.address_sources && !this.env.address_sources[this.env.source].readonly)); |
| | | this.enable_command('add', 'import', this.env.writable_source); |
| | | } |
| | | break; |
| | | |
| | |
| | | |
| | | // common commands used in multiple tasks |
| | | case 'show': |
| | | if (this.task=='mail') { |
| | | if (this.task == 'mail') { |
| | | var uid = this.get_single_uid(); |
| | | if (uid && (!this.env.uid || uid != this.env.uid)) { |
| | | if (this.env.mailbox == this.env.drafts_mailbox) |
| | |
| | | this.show_message(uid); |
| | | } |
| | | } |
| | | else if (this.task=='addressbook') { |
| | | else if (this.task == 'addressbook') { |
| | | var cid = props ? props : this.get_single_cid(); |
| | | if (cid && !(this.env.action=='show' && cid==this.env.cid)) |
| | | if (cid && !(this.env.action == 'show' && cid == this.env.cid)) |
| | | this.load_contact(cid, 'show'); |
| | | } |
| | | break; |
| | | |
| | | case 'add': |
| | | if (this.task=='addressbook') |
| | | if (this.task == 'addressbook') |
| | | this.load_contact(0, 'add'); |
| | | else if (this.task=='settings') { |
| | | else if (this.task == 'settings') { |
| | | this.identity_list.clear_selection(); |
| | | this.load_identity(0, 'add-identity'); |
| | | } |
| | |
| | | break; |
| | | |
| | | case 'save': |
| | | if (this.gui_objects.editform) { |
| | | var input_pagesize = $("input[name='_pagesize']"); |
| | | var input_name = $("input[name='_name']"); |
| | | var input_email = $("input[name='_email']"); |
| | | |
| | | var input, form = this.gui_objects.editform; |
| | | if (form) { |
| | | // adv. search |
| | | if (this.env.action == 'search') { |
| | | } |
| | | // user prefs |
| | | if (input_pagesize.length && isNaN(parseInt(input_pagesize.val()))) { |
| | | else if ((input = $("input[name='_pagesize']", form)) && input.length && isNaN(parseInt(input.val()))) { |
| | | alert(this.get_label('nopagesizewarning')); |
| | | input_pagesize.focus(); |
| | | input.focus(); |
| | | break; |
| | | } |
| | | // contacts/identities |
| | | else { |
| | | if (input_name.length && input_name.val() == '') { |
| | | if ((input = $("input[name='_name']", form)) &&input.length && input.val() == '') { |
| | | alert(this.get_label('nonamewarning')); |
| | | input_name.focus(); |
| | | input.focus(); |
| | | break; |
| | | } |
| | | else if (this.task == 'settings' && input_email.length && (this.env.identities_level % 2) == 0 && !rcube_check_email(input_email.val())) { |
| | | else if (this.task == 'settings' && (this.env.identities_level % 2) == 0 && |
| | | (input = $("input[name='_email']", form)) && input.length&& !rcube_check_email(input.val()) |
| | | ) { |
| | | alert(this.get_label('noemailwarning')); |
| | | input_email.focus(); |
| | | input.focus(); |
| | | break; |
| | | } |
| | | |
| | |
| | | $('input.placeholder').each(function(){ if (this.value == this._placeholder) this.value = ''; }); |
| | | } |
| | | |
| | | this.gui_objects.editform.submit(); |
| | | form.submit(); |
| | | } |
| | | break; |
| | | |
| | |
| | | |
| | | if (s && this.env.mailbox) |
| | | this.list_mailbox(this.env.mailbox); |
| | | else if (s && this.task == 'addressbook') |
| | | else if (s && this.task == 'addressbook') { |
| | | if (this.env.source == '') { |
| | | for (var n in this.env.address_sources) break; |
| | | this.env.source = n; |
| | | this.env.group = ''; |
| | | } |
| | | this.list_contacts(this.env.source, this.env.group); |
| | | } |
| | | break; |
| | | |
| | | case 'listgroup': |
| | |
| | | |
| | | this.save_pref = function(prop) |
| | | { |
| | | var request = {'_name': prop.name, '_value': urlencode(prop.value)}; |
| | | var request = {'_name': prop.name, '_value': prop.value}; |
| | | |
| | | if (prop.session) |
| | | request['_session'] = urlencode(prop.session); |
| | | request['_session'] = prop.session; |
| | | if (prop.env) |
| | | this.env[prop.env] = prop.value; |
| | | |
| | |
| | | // set class to read/unread |
| | | this.toggle_read_status = function(flag, a_uids) |
| | | { |
| | | // mark all message rows as read/unread |
| | | for (var i=0; i<a_uids.length; i++) |
| | | this.set_message(a_uids[i], 'unread', (flag=='unread' ? true : false)); |
| | | |
| | | var url = '_uid='+this.uids_to_list(a_uids)+'&_flag='+flag, |
| | | var i, len = a_uids.length, |
| | | url = '_uid='+this.uids_to_list(a_uids)+'&_flag='+flag, |
| | | lock = this.display_message(this.get_label('markingmessage'), 'loading'); |
| | | |
| | | // mark all message rows as read/unread |
| | | for (i=0; i<len; i++) |
| | | this.set_message(a_uids[i], 'unread', (flag=='unread' ? true : false)); |
| | | |
| | | // also send search request to get the right messages |
| | | if (this.env.search_request) |
| | |
| | | |
| | | this.http_post('mark', url, lock); |
| | | |
| | | for (var i=0; i<a_uids.length; i++) |
| | | for (i=0; i<len; i++) |
| | | this.update_thread_root(a_uids[i], flag); |
| | | }; |
| | | |
| | | // set image to flagged or unflagged |
| | | this.toggle_flagged_status = function(flag, a_uids) |
| | | { |
| | | // mark all message rows as flagged/unflagged |
| | | for (var i=0; i<a_uids.length; i++) |
| | | this.set_message(a_uids[i], 'flagged', (flag=='flagged' ? true : false)); |
| | | |
| | | var url = '_uid='+this.uids_to_list(a_uids)+'&_flag='+flag, |
| | | var i, len = a_uids.length, |
| | | url = '_uid='+this.uids_to_list(a_uids)+'&_flag='+flag, |
| | | lock = this.display_message(this.get_label('markingmessage'), 'loading'); |
| | | |
| | | // mark all message rows as flagged/unflagged |
| | | for (i=0; i<len; i++) |
| | | this.set_message(a_uids[i], 'flagged', (flag=='flagged' ? true : false)); |
| | | |
| | | // also send search request to get the right messages |
| | | if (this.env.search_request) |
| | |
| | | // mark all message rows as deleted/undeleted |
| | | this.toggle_delete_status = function(a_uids) |
| | | { |
| | | var rows = this.message_list ? this.message_list.rows : []; |
| | | var len = a_uids.length, |
| | | i, uid, all_deleted = true, |
| | | rows = this.message_list ? this.message_list.rows : []; |
| | | |
| | | if (a_uids.length==1) { |
| | | if (len == 1) { |
| | | if (!rows.length || (rows[a_uids[0]] && !rows[a_uids[0]].deleted)) |
| | | this.flag_as_deleted(a_uids); |
| | | else |
| | |
| | | return true; |
| | | } |
| | | |
| | | var uid, all_deleted = true; |
| | | for (var i=0, len=a_uids.length; i<len; i++) { |
| | | for (i=0; i<len; i++) { |
| | | uid = a_uids[i]; |
| | | if (rows[uid] && !rows[uid].deleted) { |
| | | all_deleted = false; |
| | |
| | | |
| | | this.flag_as_undeleted = function(a_uids) |
| | | { |
| | | for (var i=0, len=a_uids.length; i<len; i++) |
| | | this.set_message(a_uids[i], 'deleted', false); |
| | | |
| | | var url = '_uid='+this.uids_to_list(a_uids)+'&_flag=undelete', |
| | | var i, len=a_uids.length, |
| | | url = '_uid='+this.uids_to_list(a_uids)+'&_flag=undelete', |
| | | lock = this.display_message(this.get_label('markingmessage'), 'loading'); |
| | | |
| | | for (i=0; i<len; i++) |
| | | this.set_message(a_uids[i], 'deleted', false); |
| | | |
| | | // also send search request to get the right messages |
| | | if (this.env.search_request) |
| | |
| | | // argument should be a coma-separated list of uids |
| | | this.flag_deleted_as_read = function(uids) |
| | | { |
| | | var icn_src, uid, |
| | | rows = this.message_list ? this.message_list.rows : [], |
| | | str = String(uids), |
| | | a_uids = str.split(','); |
| | | var icn_src, uid, i, len, |
| | | rows = this.message_list ? this.message_list.rows : []; |
| | | |
| | | for (var i=0; i<a_uids.length; i++) { |
| | | uid = a_uids[i]; |
| | | uids = String(uids).split(','); |
| | | |
| | | for (i=0, len=uids.length; i<len; i++) { |
| | | uid = uids[i]; |
| | | if (rows[uid]) |
| | | this.set_message(uid, 'unread', false); |
| | | } |
| | |
| | | if (mods) |
| | | mods = mods[mbox] ? mods[mbox] : mods['*']; |
| | | } else if (this.contact_list) { |
| | | this.contact_list.clear(true); |
| | | this.show_contentframe(false); |
| | | this.list_contacts_clear(); |
| | | } |
| | | |
| | | if (mods) { |
| | |
| | | if (this.preview_timer) |
| | | clearTimeout(this.preview_timer); |
| | | |
| | | var id, frame, ref = this; |
| | | var n, id, sid, ref = this, writable = false, |
| | | source = this.env.source ? this.env.address_sources[this.env.source] : null; |
| | | |
| | | if (id = list.get_single_selection()) |
| | | this.preview_timer = window.setTimeout(function(){ ref.load_contact(id, 'show'); }, 200); |
| | | else if (this.env.contentframe) |
| | | this.show_contentframe(false); |
| | | |
| | | // no source = search result, we'll need to detect if any of |
| | | // selected contacts are in writable addressbook to enable edit/delete |
| | | if (list.selection.length) { |
| | | if (!source) { |
| | | for (n in list.selection) { |
| | | sid = String(list.selection[n]).replace(/^[^-]+-/, ''); |
| | | if (sid && this.env.address_sources[sid] && !this.env.address_sources[sid].readonly) { |
| | | writable = true; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | else { |
| | | writable = !source.readonly; |
| | | } |
| | | } |
| | | |
| | | this.enable_command('compose', list.selection.length > 0); |
| | | this.enable_command('edit', (id && this.env.address_sources && !this.env.address_sources[this.env.source].readonly) ? true : false); |
| | | this.enable_command('delete', list.selection.length && this.env.address_sources && !this.env.address_sources[this.env.source].readonly); |
| | | this.enable_command('edit', id && writable); |
| | | this.enable_command('delete', list.selection.length && writable); |
| | | |
| | | return false; |
| | | }; |
| | |
| | | this.list_contacts_remote = function(src, group, page) |
| | | { |
| | | // clear message list first |
| | | this.contact_list.clear(true); |
| | | this.show_contentframe(false); |
| | | this.enable_command('delete', 'compose', false); |
| | | this.list_contacts_clear(); |
| | | |
| | | // send request to server |
| | | var url = (src ? '_source='+urlencode(src) : '') + (page ? (src?'&':'') + '_page='+page : ''), |
| | |
| | | url += '&_search='+this.env.search_request; |
| | | |
| | | this.http_request('list', url, lock); |
| | | }; |
| | | |
| | | this.list_contacts_clear = function() |
| | | { |
| | | this.contact_list.clear(true); |
| | | this.show_contentframe(false); |
| | | this.enable_command('delete', 'compose', false); |
| | | }; |
| | | |
| | | // load contact record |
| | |
| | | if (!(selection.length || this.env.cid) || !confirm(this.get_label('deletecontactconfirm'))) |
| | | return; |
| | | |
| | | var id, a_cids = [], qs = ''; |
| | | var id, n, a_cids = [], qs = ''; |
| | | |
| | | if (this.env.cid) |
| | | a_cids.push(this.env.cid); |
| | | else { |
| | | for (var n=0; n<selection.length; n++) { |
| | | for (n=0; n<selection.length; n++) { |
| | | id = selection[n]; |
| | | a_cids.push(id); |
| | | this.contact_list.remove_row(id, (n == selection.length-1)); |
| | |
| | | qs += '&_gid='+urlencode(this.env.group); |
| | | |
| | | // also send search request to get the right records from the next page |
| | | if (this.env.search_request) |
| | | if (this.env.search_request) |
| | | qs += '&_search='+this.env.search_request; |
| | | |
| | | // send request to server |
| | |
| | | else { |
| | | var lastelem = $('.ff_'+col), |
| | | appendcontainer = $('#contactsection'+section+' .contactcontroller'+col); |
| | | |
| | | |
| | | if (!appendcontainer.length) |
| | | appendcontainer = $('<fieldset>').addClass('contactfieldgroup contactcontroller'+col).insertAfter($('#contactsection'+section+' .contactfieldgroup').last()); |
| | | |
| | |
| | | row = $('<div>').addClass('row'), |
| | | cell = $('<div>').addClass('contactfieldcontent data'), |
| | | label = $('<div>').addClass('contactfieldlabel label'); |
| | | |
| | | |
| | | if (colprop.subtypes_select) |
| | | label.html(colprop.subtypes_select); |
| | | else |
| | |
| | | this.init_edit_field(col, input); |
| | | } |
| | | else if (colprop.type == 'composite') { |
| | | var childcol, cp, first; |
| | | for (childcol in colprop.childs) { |
| | | var childcol, cp, first, templ, cols = [], suffices = []; |
| | | // read template for composite field order |
| | | if ((templ = this.env[col+'_template'])) { |
| | | for (var j=0; j < templ.length; j++) { |
| | | cols.push(templ[j][1]); |
| | | suffices.push(templ[j][2]); |
| | | } |
| | | } |
| | | else { // list fields according to appearance in colprop |
| | | for (childcol in colprop.childs) |
| | | cols.push(childcol); |
| | | } |
| | | |
| | | for (var i=0; i < cols.length; i++) { |
| | | childcol = cols[i]; |
| | | cp = colprop.childs[childcol]; |
| | | input = $('<input>') |
| | | .addClass('ff_'+childcol) |
| | | .attr({type: 'text', name: '_'+childcol+name_suffix, size: cp.size}) |
| | | .attr({ type: 'text', name: '_'+childcol+name_suffix, size: cp.size }) |
| | | .appendTo(cell); |
| | | cell.append(" "); |
| | | cell.append(suffices[i] || " "); |
| | | this.init_edit_field(childcol, input); |
| | | if (!first) first = input; |
| | | } |
| | |
| | | .addClass('ff_'+col) |
| | | .attr('name', '_'+col+name_suffix) |
| | | .appendTo(cell); |
| | | |
| | | |
| | | var options = input.attr('options'); |
| | | options[options.length] = new Option('---', ''); |
| | | if (colprop.options) |
| | |
| | | .html(this.env.delbutton) |
| | | .click(function(){ ref.delete_edit_field(this); return false }) |
| | | .appendTo(cell); |
| | | |
| | | |
| | | row.append(label).append(cell).appendTo(appendcontainer.show()); |
| | | input.first().focus(); |
| | | |
| | | |
| | | // disable option if limit reached |
| | | if (!colprop.count) colprop.count = 0; |
| | | if (++colprop.count == colprop.limit && colprop.limit) |
| | |
| | | colprop = this.env.coltypes[col], |
| | | fieldset = $(elem).parents('fieldset.contactfieldgroup'), |
| | | addmenu = fieldset.parent().find('select.addfieldmenu'); |
| | | |
| | | |
| | | // just clear input but don't hide the last field |
| | | if (--colprop.count <= 0 && colprop.visible) |
| | | $(elem).parent().children('input').val('').blur(); |
| | |
| | | if (!fieldset.children('div.row').length) |
| | | fieldset.hide(); |
| | | } |
| | | |
| | | |
| | | // enable option in add-field selector or insert it if necessary |
| | | if (addmenu.length) { |
| | | var option = addmenu.children('option[value="'+col+'"]'); |
| | |
| | | $('#ff_photo').val(id); |
| | | this.enable_command('upload-photo', this.env.coltypes.photo ? true : false); |
| | | this.enable_command('delete-photo', this.env.coltypes.photo && id != '-del-'); |
| | | }; |
| | | |
| | | // load advanced search page |
| | | this.advanced_search = function() |
| | | { |
| | | var add_url = '&_form=1', target = window; |
| | | |
| | | if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) { |
| | | add_url += '&_framed=1'; |
| | | target = window.frames[this.env.contentframe]; |
| | | this.contact_list.clear_selection(); |
| | | } |
| | | |
| | | this.location_href(this.env.comm_path+'&_action=search'+add_url, target); |
| | | |
| | | return true; |
| | | }; |
| | | |
| | | // unselect directory/group |
| | | this.unselect_directory = function() |
| | | { |
| | | if (this.env.address_sources.length > 1 || this.env.group != '') { |
| | | this.select_folder('', (this.env.group ? 'G'+this.env.source+this.env.group : this.env.source)); |
| | | this.env.group = ''; |
| | | this.env.source = ''; |
| | | } |
| | | }; |
| | | |
| | | |
| | |
| | | }; |
| | | |
| | | // Add folder row to the table and initialize it |
| | | this.add_folder_row = function (name, display_name, protected, subscribed, skip_init) |
| | | this.add_folder_row = function (name, display_name, protected, subscribed, skip_init, class_name) |
| | | { |
| | | if (!this.gui_objects.subscriptionlist) |
| | | return false; |
| | |
| | | } |
| | | |
| | | // clone a table row if there are existing rows |
| | | row = $(refrow).clone(true); |
| | | row = $(refrow).clone(true); |
| | | |
| | | // set ID, reset css class |
| | | row.attr('id', id); |
| | | row.attr('class', class_name); |
| | | |
| | | // set folder name |
| | | row.find('td:first').html(display_name); |
| | |
| | | }; |
| | | |
| | | // replace an existing table row with a new folder line (with subfolders) |
| | | this.replace_folder_row = function(oldfolder, newfolder, display_name, protected) |
| | | this.replace_folder_row = function(oldfolder, newfolder, display_name, protected, class_name) |
| | | { |
| | | if (!this.gui_objects.subscriptionlist) |
| | | return false; |
| | |
| | | |
| | | // replace an existing table row |
| | | this._remove_folder_row(id); |
| | | row = $(this.add_folder_row(newfolder, display_name, protected, subscribed, true)); |
| | | row = $(this.add_folder_row(newfolder, display_name, protected, subscribed, true, class_name)); |
| | | |
| | | // detect tree depth change |
| | | if (len = list.length) { |
| | |
| | | switch (response.action) { |
| | | case 'delete': |
| | | if (this.task == 'addressbook') { |
| | | var uid = this.contact_list.get_selection(); |
| | | var sid, uid = this.contact_list.get_selection(), writable = false; |
| | | |
| | | if (uid && this.contact_list.rows[uid]) { |
| | | // search results, get source ID from record ID |
| | | if (this.env.source == '') { |
| | | sid = String(uid).replace(/^[^-]+-/, ''); |
| | | writable = sid && this.env.address_sources[sid] && !this.env.address_sources[sid].readonly; |
| | | } |
| | | else { |
| | | writable = !this.env.address_sources[this.env.source].readonly; |
| | | } |
| | | } |
| | | this.enable_command('compose', (uid && this.contact_list.rows[uid])); |
| | | this.enable_command('delete', 'edit', (uid && this.contact_list.rows[uid] && this.env.address_sources && !this.env.address_sources[this.env.source].readonly)); |
| | | this.enable_command('delete', 'edit', writable); |
| | | this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); |
| | | } |
| | | |
| | |
| | | this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); |
| | | |
| | | if (response.action == 'list' || response.action == 'search') { |
| | | this.enable_command('group-create', |
| | | (this.env.address_sources[this.env.source].groups && !this.env.address_sources[this.env.source].readonly)); |
| | | this.enable_command('group-rename', 'group-delete', |
| | | (this.env.address_sources[this.env.source].groups && this.env.group && !this.env.address_sources[this.env.source].readonly)); |
| | | var source = this.env.source != '' ? this.env.address_sources[this.env.source] : null; |
| | | this.enable_command('group-create', (source && source.groups && !source.readonly)); |
| | | this.enable_command('group-rename', 'group-delete', (source && source.groups && this.env.group && !source.readonly)); |
| | | this.triggerEvent('listupdate', { folder:this.env.source, rowcount:this.contact_list.rowcount }); |
| | | } |
| | | } |
| | |
| | | |
| | | form.target = frame_name; |
| | | form.action = this.url(action, { _id:this.env.compose_id||'', _uploadid:ts }); |
| | | form.setAttribute('method', 'POST'); |
| | | form.setAttribute('enctype', 'multipart/form-data'); |
| | | form.submit(); |
| | | |
| | | return frame_name; |
| | | }; |
| | | |
| | | |
| | | // starts interval for keep-alive/check-recent signal |
| | | this.start_keepalive = function() |
| | | { |