* Collabora: Add address insert dialog

This commit is contained in:
nathan 2021-09-21 14:06:24 -06:00
parent 15a2e546ea
commit d512238dc0
4 changed files with 277 additions and 7 deletions

View File

@ -36,6 +36,11 @@ export class et2_placeholder_select extends et2_inputWidget
"name": "Insert callback", "name": "Insert callback",
"description": "Method called with the selected placeholder text", "description": "Method called with the selected placeholder text",
"type": "js" "type": "js"
},
dialog_title: {
"name": "Dialog title",
"type": "string",
"default": "Insert Placeholder"
} }
}; };
@ -99,7 +104,7 @@ export class et2_placeholder_select extends et2_inputWidget
* *
* @param {object} _data content * @param {object} _data content
*/ */
private _buildDialog(_data) protected _buildDialog(_data)
{ {
let self = this; let self = this;
@ -149,7 +154,7 @@ export class et2_placeholder_select extends et2_inputWidget
{ {
if((submit_button_id == 'submit' || (extra_buttons_action && extra_buttons_action[submit_button_id])) && submit_value) if((submit_button_id == 'submit' || (extra_buttons_action && extra_buttons_action[submit_button_id])) && submit_value)
{ {
this.options.insert_callback(submit_value.placeholder_list); this._do_insert_callback(submit_value);
return true; return true;
} }
}.bind(this); }.bind(this);
@ -238,6 +243,7 @@ export class et2_placeholder_select extends et2_inputWidget
let preview_content = <et2_description>this.dialog.template.widgetContainer.getDOMWidgetById("preview_content"); let preview_content = <et2_description>this.dialog.template.widgetContainer.getDOMWidgetById("preview_content");
// Show the selected placeholder // Show the selected placeholder
this.set_value(placeholder_list.get_value());
preview.set_value(placeholder_list.get_value()); preview.set_value(placeholder_list.get_value());
preview.getDOMNode().parentNode.style.visibility = placeholder_list.get_value().trim() ? null : 'hidden'; preview.getDOMNode().parentNode.style.visibility = placeholder_list.get_value().trim() ? null : 'hidden';
@ -301,6 +307,16 @@ export class et2_placeholder_select extends et2_inputWidget
return options; return options;
} }
/**
* Get the correct insert text call the insert callback with it
*
* @param dialog_values
*/
_do_insert_callback(dialog_values : Object)
{
this.options.insert_callback(this.get_value());
}
set_value(value) set_value(value)
{ {
this.value = value; this.value = value;
@ -313,3 +329,160 @@ export class et2_placeholder_select extends et2_inputWidget
}; };
et2_register_widget(et2_placeholder_select, ["placeholder-select"]); et2_register_widget(et2_placeholder_select, ["placeholder-select"]);
/**
* Display a dialog to choose from a set list of placeholder snippets
*/
export class et2_placeholder_snippet_select extends et2_placeholder_select
{
static readonly _attributes : any = {
dialog_title: {
"default": "Insert address"
}
};
static placeholders = {
"addressbook": {
"addresses": {
"{{n_fn}}\n{{adr_one_street}}{{NELF adr_one_street2}}\n{{adr_one_formatted}}": "Work address",
"{{n_fn}}\n{{adr_two_street}}{{NELF adr_two_street2}}\n{{adr_two_formatted}}": "Home address",
}
}
};
button : JQuery;
submit_callback : any;
dialog : et2_dialog;
protected value : any;
protected LIST_URL = 'EGroupware\\Api\\Etemplate\\Widget\\Placeholder::ajax_get_placeholders';
protected TEMPLATE = '/api/templates/default/placeholder_snippet.xet?1';
/**
* Post-load of the dialog
* Bind internal events, set some things that are difficult to do in the template
*/
_on_template_load()
{
let app = <et2_selectbox>this.dialog.template.widgetContainer.getDOMWidgetById("app");
let placeholder_list = <et2_selectbox>this.dialog.template.widgetContainer.getDOMWidgetById("placeholder_list");
let preview = <et2_description>this.dialog.template.widgetContainer.getDOMWidgetById("preview_content");
let entry = <et2_link_entry>this.dialog.template.widgetContainer.getDOMWidgetById("entry");
placeholder_list.set_select_options(this._get_placeholders("addressbook", "addresses"));
// Further setup / styling that can't be done in etemplate
app.getInputNode().setAttribute("readonly", true);
this.dialog.template.DOMContainer.style.display = "flex";
this.dialog.template.DOMContainer.firstChild.style.display = "flex";
placeholder_list.getDOMNode().size = 5;
// Bind some handlers
app.onchange = (node, widget) =>
{
entry.set_value({app: widget.get_value()});
placeholder_list.set_select_options(this._get_placeholders(app.get_value(), "addresses"));
}
placeholder_list.onchange = this._on_placeholder_select.bind(this);
entry.onchange = this._on_placeholder_select.bind(this);
this._on_placeholder_select();
}
/**
* User has selected a placeholder
* Update the UI, and if they have an entry selected do the replacement and show that.
*/
_on_placeholder_select()
{
let app = <et2_link_entry>this.dialog.template.widgetContainer.getDOMWidgetById("app");
let entry = <et2_link_entry>this.dialog.template.widgetContainer.getDOMWidgetById("entry");
let placeholder_list = <et2_selectbox>this.dialog.template.widgetContainer.getDOMWidgetById("placeholder_list");
let preview = <et2_description>this.dialog.template.widgetContainer.getDOMWidgetById("preview_placeholder");
let preview_content = <et2_description>this.dialog.template.widgetContainer.getDOMWidgetById("preview_content");
if(placeholder_list.get_value() && entry.get_value())
{
// 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()],
function(_content)
{
this.set_value(_content);
preview_content.set_value(_content);
preview_content.getDOMNode().parentNode.style.visibility = _content.trim() ? null : 'hidden';
}.bind(this)
).sendRequest(true);
}
else
{
// No value, hide the row
preview_content.getDOMNode().parentNode.style.visibility = 'hidden';
}
if(!entry.get_value())
{
entry.search.get(0).focus();
}
}
/**
* Get the list of placeholder groups under the selected application
* @param appname
* @returns {value:string, label:string}[]
*/
_get_group_options(appname : string)
{
let options = [];
Object.keys(et2_placeholder_select.placeholders[appname]).map((key) =>
{
options.push(
{
value: key,
label: this.egw().lang(key)
});
});
return options;
}
/**
* Get a list of placeholders under the given application + group
*
* @param appname
* @param group
* @returns {value:string, label:string}[]
*/
_get_placeholders(appname : string, group : string)
{
let options = [];
Object.keys(et2_placeholder_snippet_select.placeholders[appname][group]).map((key) =>
{
options.push(
{
value: key,
label: et2_placeholder_snippet_select.placeholders[appname][group][key]
});
});
return options;
}
/**
* Get the correct insert text call the insert callback with it
*
* @param dialog_values
*/
_do_insert_callback(dialog_values : Object)
{
this.options.insert_callback(this.get_value());
}
set_value(value)
{
this.value = value;
}
getValue()
{
return this.value;
}
};
et2_register_widget(et2_placeholder_snippet_select, ["placeholder-snippet"]);

View File

@ -309,6 +309,10 @@ class Merge extends Api\Storage\Merge
} }
} }
// Correctly formatted address by country / preference
$placeholders['business']["{{adr_one_formatted}}"] = "Formatted business address";
$placeholders['private']["{{adr_two_formatted}}"] = "Formatted private address";
$group = 'customfields'; $group = 'customfields';
foreach($this->contacts->customfields as $name => $field) foreach($this->contacts->customfields as $name => $field)
{ {

View File

@ -283,22 +283,43 @@ abstract class Merge
} }
break; break;
case 'account_id': case 'account_id':
if ($value) if($value)
{ {
$replacements['$$'.($prefix ? $prefix.'/':'').'account_lid$$'] = $GLOBALS['egw']->accounts->id2name($value); $replacements['$$' . ($prefix ? $prefix . '/' : '') . 'account_lid$$'] = $GLOBALS['egw']->accounts->id2name($value);
} }
break; break;
} }
if ($name != 'photo') $replacements['$$'.($prefix ? $prefix.'/':'').$name.'$$'] = $value; if($name != 'photo')
{
$replacements['$$' . ($prefix ? $prefix . '/' : '') . $name . '$$'] = $value;
}
} }
// Formatted address, according to preference or country
foreach(['one', 'two'] as $adr)
{
switch($this->contacts->addr_format_by_country($contact["adr_{$adr}_countryname"]))
{
case 'city_state_postcode':
$formatted_placeholder = $contact["adr_{$adr}_locality"] . " " .
$contact["adr_{$adr}_region"] . " " . $contact["adr_{$adr}_postalcode"];
break;
case 'postcode_city':
default:
$formatted_placeholder = $contact["adr_{$adr}_postalcode"] . ' ' . $contact["adr_{$adr}_locality"];
break;
}
$replacements['$$adr_' . $adr . '_formatted$$'] = $formatted_placeholder;
}
// set custom fields, should probably go to a general method all apps can use // set custom fields, should probably go to a general method all apps can use
// need to load all cfs for $ignore_acl=true // need to load all cfs for $ignore_acl=true
foreach($ignore_acl ? Customfields::get('addressbook', true) : $this->contacts->customfields as $name => $field) foreach($ignore_acl ? Customfields::get('addressbook', true) : $this->contacts->customfields as $name => $field)
{ {
$name = '#'.$name; $name = '#' . $name;
if(!array_key_exists($name, $contact) || !$contact[$name]) if(!array_key_exists($name, $contact) || !$contact[$name])
{ {
$replacements['$$'.($prefix ? $prefix.'/':'').$name.'$$'] = ''; $replacements['$$' . ($prefix ? $prefix . '/' : '') . $name . '$$'] = '';
continue; continue;
} }
// Format date cfs per user Api\Preferences // Format date cfs per user Api\Preferences

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
<!-- $Id$ -->
<overlay>
<template id="etemplate.placeholder_snippet" template="" lang="" group="0" version="21.1.001">
<vbox id="outer_box">
<vbox id="selects">
<select id="app"/>
<select id="placeholder_list"/>
</vbox>
<hrule/>
<link-entry id="entry" label="Select entry"/>
<hbox class="preview">
<description id="preview_content"/>
</hbox>
</vbox>
<styles>
#api\.insert_merge_placeholder_outer_box > #api\.insert_merge_placeholder_selects {
flex: 1 1 50%;
}
#api\.insert_merge_placeholder_outer_box > label.et2_label {
flex: 0 1 auto;
}
#api\.insert_merge_placeholder_outer_box .preview {
flex: 1 1 50%;
font-size: larger;
}
select#api\.insert_merge_placeholder_app {
flex-grow: 0;
}
.ui-dialog-content, div.et2_box_widget, div.et2_box_widget > div.et2_box_widget {
display: flex;
flex: 1 1 auto;
}
div.et2_hbox {
flex-direction: row;
flex-grow: 1;
}
div.et2_vbox {
flex-direction: column;
gap: 5px;
}
div.et2_box_widget > * {
flex: 1 1 auto;
width: 100%;
}
div.et2_link_entry {
flex-grow: 0;
}
div.et2_link_entry input.ui-autocomplete-input {
width: 75%
}
div.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button, button#cancel, .et2_button {
border: none;
border-radius: 0px;
background-color: transparent;
}
div.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover, button#cancel:hover {
box-shadow: none;
-webkit-box-shadow: none;
}
.preview .et2_button {
flex: 0 1 24px;
height: 24px;
border: none;
border-radius: 0px;
background-color: transparent;
}
</styles>
</template>
</overlay>