diff --git a/api/js/etemplate/et2_widget_placeholder.ts b/api/js/etemplate/et2_widget_placeholder.ts index 06d42a3245..1ac6847123 100644 --- a/api/js/etemplate/et2_widget_placeholder.ts +++ b/api/js/etemplate/et2_widget_placeholder.ts @@ -87,6 +87,12 @@ export class et2_placeholder_select extends et2_inputWidget [], function(_content) { + if(typeof _content === 'object' && _content.message) + { + // Something went wrong + this.egw().message(_content.message, 'error'); + return; + } this.egw().loading_prompt('placeholder_select', false); et2_placeholder_select.placeholders = _content; callback.apply(self, arguments); @@ -146,7 +152,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.entry = data.modifications.outer_box.entry.only_app = data.content.app; + data.content.entry = {app: data.content.app}; data.modifications.outer_box.entry.application_list = Object.keys(_data); // callback for dialog @@ -207,14 +213,30 @@ export class et2_placeholder_select extends et2_inputWidget // Bind some handlers app.onchange = (node, widget) => { - group.set_select_options(this._get_group_options(widget.get_value())); - entry.set_value({app: widget.get_value()}); + let groups = this._get_group_options(widget.get_value()); + group.set_select_options(groups); + group.set_value(groups[0].value); + if(['user'].indexOf(widget.get_value()) >= 0) + { + entry.app_select.val('api-accounts'); + entry.set_value({app: 'api-accounts', id: '', query: ''}); + } + else if(widget.get_value() == 'general') + { + // Don't change entry app, leave it + } + else + { + entry.app_select.val(widget.get_value()); + entry.set_value({app: widget.get_value(), id: '', query: ''}); + } } group.onchange = (select_node, select_widget) => { - console.log(this, arguments); - placeholder_list.set_select_options(this._get_placeholders(app.get_value(), group.get_value())); + let options = this._get_placeholders(app.get_value(), group.get_value()) + placeholder_list.set_select_options(options); preview.set_value(""); + placeholder_list.set_value(options[0].value); } placeholder_list.onchange = this._on_placeholder_select.bind(this); entry.onchange = this._on_placeholder_select.bind(this); @@ -227,7 +249,7 @@ export class et2_placeholder_select extends et2_inputWidget this.options.insert_callback(this.dialog.template.widgetContainer.getDOMWidgetById("preview_content").getDOMNode().textContent); }; - this._on_placeholder_select(); + app.set_value(app.get_value()); } /** @@ -252,9 +274,13 @@ export class et2_placeholder_select extends et2_inputWidget // Show the selected placeholder replaced with value from the selected entry this.egw().json( 'EGroupware\\Api\\Etemplate\\Widget\\Placeholder::ajax_fill_placeholders', - [app.get_value(), placeholder_list.get_value(), entry.get_value()], + [placeholder_list.get_value(), entry.get_value()], function(_content) { + if(!_content) + { + _content = ''; + } preview_content.set_value(_content); preview_content.getDOMNode().parentNode.style.visibility = _content.trim() ? null : 'hidden'; }.bind(this) @@ -385,6 +411,7 @@ export class et2_placeholder_snippet_select extends et2_placeholder_select placeholder_list.onchange = this._on_placeholder_select.bind(this); entry.onchange = this._on_placeholder_select.bind(this); + app.set_value(app.get_value()); this._on_placeholder_select(); } @@ -405,9 +432,13 @@ export class et2_placeholder_snippet_select extends et2_placeholder_select // Show the selected placeholder replaced with value from the selected entry this.egw().json( 'EGroupware\\Api\\Etemplate\\Widget\\Placeholder::ajax_fill_placeholders', - [app.get_value(), placeholder_list.get_value(), entry.get_value()], + [placeholder_list.get_value(), entry.get_value()], function(_content) { + if(!_content) + { + _content = ''; + } this.set_value(_content); preview_content.set_value(_content); preview_content.getDOMNode().parentNode.style.visibility = _content.trim() ? null : 'hidden'; diff --git a/api/src/Contacts/Merge.php b/api/src/Contacts/Merge.php index 4c0dcf6681..e699886ed0 100644 --- a/api/src/Contacts/Merge.php +++ b/api/src/Contacts/Merge.php @@ -334,7 +334,7 @@ class Merge extends Api\Storage\Merge $group = 'customfields'; foreach($this->contacts->customfields as $name => $field) { - $placeholders[$group][$this->prefix($prefix, $name, '{')] = $field['label']; + $placeholders[$group][$this->prefix($prefix, '#' . $name, '{')] = $field['label']; } return $placeholders; } diff --git a/api/src/Etemplate/Widget/Placeholder.php b/api/src/Etemplate/Widget/Placeholder.php index 8eca0b211a..253aa7f93e 100644 --- a/api/src/Etemplate/Widget/Placeholder.php +++ b/api/src/Etemplate/Widget/Placeholder.php @@ -64,7 +64,9 @@ class Placeholder extends Etemplate\Widget if(is_null($apps)) { - $apps = ['addressbook', 'user', 'general']; + $apps = ['addressbook', 'user', 'general'] + + // We use linking for preview, so limit to apps that support links + array_keys(Api\Link::app_list('query')); } foreach($apps as $appname) @@ -79,30 +81,38 @@ class Placeholder extends Etemplate\Widget $list = $merge->get_common_placeholder_list(); break; default: - $list = $merge->get_placeholder_list(); + if(get_class($merge) === 'EGroupware\Api\Contacts\Merge' && $appname !== 'addressbook' || $placeholders[$appname]) + { + // Looks like app doesn't support merging + continue 2; + } + $list = method_exists($merge, 'get_placeholder_list') ? $merge->get_placeholder_list() : []; break; } - if(!is_null($group)) + if(!is_null($group) && is_array($list)) { $list = array_intersect_key($list, $group); } - $placeholders[$appname] = $list; + if($list) + { + $placeholders[$appname] = $list; + } } $response = Api\Json\Response::get(); $response->data($placeholders); } - public function ajax_fill_placeholders($app, $content, $entry) + public function ajax_fill_placeholders($content, $entry) { - $merge = Api\Storage\Merge::get_app_class($app); + $merge = Api\Storage\Merge::get_app_class($entry['app']); $err = ""; - switch($app) + switch($entry['app']) { case 'addressbook': default: - $merged = $merge->merge_string($content, [$entry], $err, 'text/plain'); + $merged = $merge->merge_string($content, [$entry['id']], $err, 'text/plain'); } $response = Api\Json\Response::get(); $response->data($merged); diff --git a/api/src/Storage/Merge.php b/api/src/Storage/Merge.php index 220d54a154..feb196491e 100644 --- a/api/src/Storage/Merge.php +++ b/api/src/Storage/Merge.php @@ -1600,9 +1600,9 @@ abstract class Merge */ public static function get_app_class($appname) { - if(class_exists($appname) && is_subclass_of($appname, 'EGroupware\\Api\\Storage\\Merge')) + $classname = "{$appname}_merge"; + if(class_exists($classname) && is_subclass_of($classname, 'EGroupware\\Api\\Storage\\Merge')) { - $classname = "{$appname}_merge"; $document_merge = new $classname(); } else @@ -2709,4 +2709,23 @@ abstract class Merge return $replacements; } + + /** + * Get a list of placeholders provided. + * + * Placeholders are grouped logically. Group key should have a user-friendly translation. + * Override this method and specify the placeholders, as well as groups or a specific order + */ + public function get_placeholder_list($prefix = '') + { + $placeholders = [ + 'placeholders' => [] + ]; + foreach(Customfields::get($this->get_app()) as $name => $field) + { + $placeholders['customfields'][$this->prefix($prefix, '#' . $name, '{')] = $field['label'] . ($field['type'] == 'select-account' ? '*' : ''); + } + + return $placeholders; + } } diff --git a/infolog/inc/class.infolog_merge.inc.php b/infolog/inc/class.infolog_merge.inc.php index 75ff5120ea..74bbcd0887 100644 --- a/infolog/inc/class.infolog_merge.inc.php +++ b/infolog/inc/class.infolog_merge.inc.php @@ -250,14 +250,44 @@ class infolog_merge extends Api\Storage\Merge echo '