diff --git a/api/js/etemplate/et2_widget_placeholder.ts b/api/js/etemplate/et2_widget_placeholder.ts index c99e273cb0..bdbef7b34a 100644 --- a/api/js/etemplate/et2_widget_placeholder.ts +++ b/api/js/etemplate/et2_widget_placeholder.ts @@ -138,7 +138,13 @@ export class et2_placeholder_select extends et2_inputWidget let data = { content: {app: '', group: '', entry: {}}, sel_options: {app: [], group: []}, - modifications: {outer_box: {entry: {}}} + modifications: { + outer_box: { + entry: { + application_list: [] + } + } + } }; Object.keys(_data).map((key) => @@ -151,7 +157,7 @@ export class et2_placeholder_select extends et2_inputWidget }); data.sel_options.group = this._get_group_options(Object.keys(_data)[0]); data.content.app = data.sel_options.app[0].value; - data.content.group = data.sel_options.group[0].value; + data.content.group = data.sel_options.group[0]?.value; data.content.entry = {app: data.content.app}; data.modifications.outer_box.entry.application_list = Object.keys(_data); // Remove non-app placeholders (user & general) @@ -315,11 +321,37 @@ export class et2_placeholder_select extends et2_inputWidget let options = []; Object.keys(et2_placeholder_select.placeholders[appname]).map((key) => { - options.push( + // @ts-ignore + if(Object.keys(et2_placeholder_select.placeholders[appname][key]).filter((key) => isNaN(key)).length > 0) + { + // Handle groups of groups + if(typeof et2_placeholder_select.placeholders[appname][key].label !== "undefined") { + options[key] = et2_placeholder_select.placeholders[appname][key]; + } + else + { + options[this.egw().lang(key)] = []; + for(let sub of Object.keys(et2_placeholder_select.placeholders[appname][key])) + { + if(!et2_placeholder_select.placeholders[appname][key][sub]) + { + continue; + } + options[key].push({ + value: key + '-' + sub, + label: this.egw().lang(sub) + }); + } + } + } + else + { + options.push({ value: key, label: this.egw().lang(key) }); + } }); return options; } @@ -333,16 +365,13 @@ export class et2_placeholder_select extends et2_inputWidget */ _get_placeholders(appname : string, group : string) { - let options = []; - Object.keys(et2_placeholder_select.placeholders[appname][group]).map((key) => + let _group = group.split('-', 2); + let ph = et2_placeholder_select.placeholders[appname]; + for(let i = 0; typeof ph !== "undefined" && i < _group.length; i++) { - options.push( - { - value: key, - label: et2_placeholder_select.placeholders[appname][group][key] - }); - }); - return options; + ph = ph[_group[i]]; + } + return ph || []; } /** diff --git a/api/src/Contacts/Merge.php b/api/src/Contacts/Merge.php index e699886ed0..4dc6d5a47c 100644 --- a/api/src/Contacts/Merge.php +++ b/api/src/Contacts/Merge.php @@ -279,12 +279,20 @@ class Merge extends Api\Storage\Merge $placeholders = [ 'contact' => [], 'details' => [ - $this->prefix($prefix, 'categories', '{') => lang('Category path'), - $this->prefix($prefix, 'note', '{') => $this->contacts->contact_fields['note'], - $this->prefix($prefix, 'id', '{') => $this->contacts->contact_fields['id'], - $this->prefix($prefix, 'owner', '{') => $this->contacts->contact_fields['owner'], - $this->prefix($prefix, 'private', '{') => $this->contacts->contact_fields['private'], - $this->prefix($prefix, 'cat_id', '{') => $this->contacts->contact_fields['cat_id'], + [ + 'value' => $this->prefix($prefix, 'categories', '{'), + 'label' => lang('Category path') + ], + ['value' => $this->prefix($prefix, 'note', '{'), + 'label' => $this->contacts->contact_fields['note']], + ['value' => $this->prefix($prefix, 'id', '{'), + 'label' => $this->contacts->contact_fields['id']], + ['value' => $this->prefix($prefix, 'owner', '{'), + 'label' => $this->contacts->contact_fields['owner']], + ['value' => $this->prefix($prefix, 'private', '{'), + 'label' => $this->contacts->contact_fields['private']], + ['value' => $this->prefix($prefix, 'cat_id', '{'), + 'label' => $this->contacts->contact_fields['cat_id']], ], ]; @@ -320,22 +328,31 @@ class Merge extends Api\Storage\Merge $marker = $this->prefix($prefix, $name, '{'); if(!array_filter($placeholders, function ($a) use ($marker) { - return array_key_exists($marker, $a); + count(array_filter($a, function ($b) use ($marker) + { + return $b['value'] == $marker; + }) + ) > 0; })) { - $placeholders[$group][$marker] = $label; + $placeholders[$group][] = [ + 'value' => $marker, + 'label' => $label + ]; } } // Correctly formatted address by country / preference - $placeholders['business'][$this->prefix($prefix, 'adr_one_formatted', '{')] = "Formatted business address"; - $placeholders['private'][$this->prefix($prefix, 'adr_two_formatted', '{')] = "Formatted private address"; + $placeholders['business'][] = [ + 'value' => $this->prefix($prefix, 'adr_one_formatted', '{'), + 'label' => "Formatted business address" + ]; + $placeholders['private'][] = [ + 'value' => $this->prefix($prefix, 'adr_two_formatted', '{'), + 'label' => "Formatted private address" + ]; - $group = 'customfields'; - foreach($this->contacts->customfields as $name => $field) - { - $placeholders[$group][$this->prefix($prefix, '#' . $name, '{')] = $field['label']; - } + $this->add_customfield_placeholders($placeholders, $prefix); return $placeholders; } diff --git a/api/src/Storage/Merge.php b/api/src/Storage/Merge.php index 55c3f34b5d..6d15c4962c 100644 --- a/api/src/Storage/Merge.php +++ b/api/src/Storage/Merge.php @@ -2738,7 +2738,10 @@ abstract class Merge return array_key_exists($marker, $a); })) { - $placeholders[$group][$marker] = $label; + $placeholders[$group][] = [ + 'value' => $marker, + 'label' => $label + ]; } } return $placeholders; @@ -2753,13 +2756,45 @@ abstract class Merge $replacements = $contacts->get_placeholder_list($this->prefix($prefix, 'user')); unset($replacements['details'][$this->prefix($prefix, 'user/account_id', '{')]); $replacements['account'] = [ - $this->prefix($prefix, 'user/account_id', '{') => 'Account ID', - $this->prefix($prefix, 'user/account_lid', '{') => 'Login ID' + [ + 'value' => $this->prefix($prefix, 'user/account_id', '{'), + 'label' => 'Account ID' + ], + [ + 'value' => $this->prefix($prefix, 'user/account_lid', '{'), + 'label' => 'Login ID' + ] ]; return $replacements; } + /** + * Get the list of placeholders for an application's customfields + * If the customfield is a link to another application, we expand and add those placeholders as well + */ + protected function add_customfield_placeholders(&$placeholders, $prefix = '') + { + foreach(Customfields::get($this->get_app()) as $name => $field) + { + if(array_key_exists($field['type'], Api\Link::app_list())) + { + $app = self::get_app_class($field['type']); + if($app) + { + $this->add_linked_placeholders($placeholders, $name, $app->get_placeholder_list('#' . $name)); + } + } + else + { + $placeholders['customfields'][] = [ + 'value' => $this->prefix($prefix, '#' . $name, '{'), + 'label' => $field['label'] . ($field['type'] == 'select-account' ? '*' : '') + ]; + } + } + } + /** * Get a list of placeholders provided. * @@ -2771,11 +2806,34 @@ abstract class Merge $placeholders = [ 'placeholders' => [] ]; - foreach(Customfields::get($this->get_app()) as $name => $field) - { - $placeholders['customfields'][$this->prefix($prefix, '#' . $name, '{')] = $field['label'] . ($field['type'] == 'select-account' ? '*' : ''); - } + + $this->add_customfield_placeholders($placeholders, $prefix); return $placeholders; } + + /** + * Add placeholders from another application into the given list of placeholders + * + * This is used for linked entries (like info_contact) and custom fields where the type is another application. + * Here we adjust the group name, and add the group to the end of the placeholder list + * @param array $placeholder_list Our placeholder list + * @param string $base_name Name of the entry (eg: Contact, custom field name) + * @param array $add_placeholder_groups Placeholder list from the other app + */ + protected function add_linked_placeholders(&$placeholder_list, $base_name, $add_placeholder_groups) : void + { + if(!$add_placeholder_groups) + { + // Skip empties + return; + } + /* + foreach($add_placeholder_groups as $group => $add_placeholders) + { + $placeholder_list[$base_name . ': ' . lang($group)] = $add_placeholders; + } + */ + $placeholder_list[$base_name] = $add_placeholder_groups; + } } diff --git a/infolog/inc/class.infolog_merge.inc.php b/infolog/inc/class.infolog_merge.inc.php index 74bbcd0887..def1692722 100644 --- a/infolog/inc/class.infolog_merge.inc.php +++ b/infolog/inc/class.infolog_merge.inc.php @@ -284,10 +284,22 @@ class infolog_merge extends Api\Storage\Merge return array_key_exists($marker, $a); })) { - $placeholders[$group][$marker] = $label; + $placeholders[$group][] = [ + 'value' => $marker, + 'label' => $label + ]; } } + // Add contact placeholders + $insert_index = 1; + $placeholders = array_slice($placeholders, 0, $insert_index, true) + + [lang($tracking->field2label['info_from']) => []] + + array_slice($placeholders, $insert_index, count($placeholders) - $insert_index, true); + $contact_merge = new Api\Contacts\Merge(); + $contact = $contact_merge->get_placeholder_list('info_contact'); + $this->add_linked_placeholders($placeholders, lang($tracking->field2label['info_from']), $contact); + return $placeholders; } }