+ var source = this.env.source != '' ? this.env.address_sources[this.env.source] : null;
+ this.enable_command('group-create', (source && source.groups && !source.readonly));
+ this.enable_command('group-rename', 'group-delete', (source && source.groups && this.env.group && !source.readonly));
+ };
+
+ this.init_edit_field = function(col, elem)
+ {
+ if (!elem)
+ elem = $('.ff_' + col);
+
+ elem.focus(function(){ ref.focus_textfield(this); })
+ .blur(function(){ ref.blur_textfield(this); })
+ .each(function(){ this._placeholder = this.title = ref.env.coltypes[col].label; ref.blur_textfield(this); });
+ };
+
+ this.insert_edit_field = function(col, section, menu)
+ {
+ // just make pre-defined input field visible
+ var elem = $('#ff_'+col);
+ if (elem.length) {
+ elem.show().focus();
+ $(menu).children('option[value="'+col+'"]').prop('disabled', true);
+ }
+ else {
+ var lastelem = $('.ff_'+col),
+ appendcontainer = $('#contactsection'+section+' .contactcontroller'+col);
+
+ if (!appendcontainer.length)
+ appendcontainer = $('<fieldset>').addClass('contactfieldgroup contactcontroller'+col).insertAfter($('#contactsection'+section+' .contactfieldgroup').last());
+
+ if (appendcontainer.length && appendcontainer.get(0).nodeName == 'FIELDSET') {
+ var input, colprop = this.env.coltypes[col],
+ row = $('<div>').addClass('row'),
+ cell = $('<div>').addClass('contactfieldcontent data'),
+ label = $('<div>').addClass('contactfieldlabel label');
+
+ if (colprop.subtypes_select)
+ label.html(colprop.subtypes_select);
+ else
+ label.html(colprop.label);
+
+ var name_suffix = colprop.limit != 1 ? '[]' : '';
+ if (colprop.type == 'text' || colprop.type == 'date') {
+ input = $('<input>')
+ .addClass('ff_'+col)
+ .attr({type: 'text', name: '_'+col+name_suffix, size: colprop.size})
+ .appendTo(cell);
+
+ this.init_edit_field(col, input);
+ }
+ else if (colprop.type == 'composite') {
+ 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 })
+ .appendTo(cell);
+ cell.append(suffices[i] || " ");
+ this.init_edit_field(childcol, input);
+ if (!first) first = input;
+ }
+ input = first; // set focus to the first of this composite fields
+ }
+ else if (colprop.type == 'select') {
+ input = $('<select>')
+ .addClass('ff_'+col)
+ .attr('name', '_'+col+name_suffix)
+ .appendTo(cell);
+
+ var options = input.attr('options');
+ options[options.length] = new Option('---', '');
+ if (colprop.options)
+ $.each(colprop.options, function(i, val){ options[options.length] = new Option(val, i); });
+ }
+
+ if (input) {
+ var delbutton = $('<a href="#del"></a>')
+ .addClass('contactfieldbutton deletebutton')
+ .attr({title: this.get_label('delete'), rel: col})
+ .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)
+ $(menu).children('option[value="'+col+'"]').prop('disabled', true);
+ }
+ }
+ }
+ };
+
+ this.delete_edit_field = function(elem)
+ {
+ var col = $(elem).attr('rel'),
+ 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();
+ else {
+ $(elem).parents('div.row').remove();
+ // hide entire fieldset if no more rows
+ 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+'"]');
+ if (option.length)
+ option.prop('disabled', false);
+ else
+ option = $('<option>').attr('value', col).html(colprop.label).appendTo(addmenu);
+ addmenu.show();
+ }
+ };
+
+ this.upload_contact_photo = function(form)
+ {
+ if (form && form.elements._photo.value) {
+ this.async_upload_form(form, 'upload-photo', function(e) {
+ rcmail.set_busy(false, null, rcmail.photo_upload_id);
+ });
+
+ // display upload indicator
+ this.photo_upload_id = this.set_busy(true, 'uploading');
+ }
+ };
+
+ this.replace_contact_photo = function(id)
+ {
+ var img_src = id == '-del-' ? this.env.photo_placeholder :
+ this.env.comm_path + '&_action=photo&_source=' + this.env.source + '&_cid=' + this.env.cid + '&_photo=' + id;
+
+ this.set_photo_actions(id);
+ $(this.gui_objects.contactphoto).children('img').attr('src', img_src);
+ };
+
+ this.photo_upload_end = function()
+ {
+ this.set_busy(false, null, this.photo_upload_id);
+ delete this.photo_upload_id;
+ };
+
+ this.set_photo_actions = function(id)
+ {
+ var n, buttons = this.buttons['upload-photo'];
+ for (n=0; buttons && n < buttons.length; n++)
+ $('#'+buttons[n].id).html(this.get_label(id == '-del-' ? 'addphoto' : 'replacephoto'));
+
+ $('#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, true);
+
+ return true;