mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 14:41:29 +01:00
aaefb6ce68
It Et2Dialog.template is an attribute, and has to return the template name. Use Et2Dialog.eTemplate to access the loaded etemplate2 object.
576 lines
16 KiB
TypeScript
576 lines
16 KiB
TypeScript
/**
|
|
* EGroupware eTemplate2 - JS Placeholder widgets
|
|
*
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
* @package etemplate
|
|
* @subpackage api
|
|
* @link https://www.egroupware.org
|
|
* @author Nathan Gray
|
|
* @copyright Nathan Gray 2021
|
|
*/
|
|
|
|
/*egw:uses
|
|
et2_core_inputWidget;
|
|
et2_core_valueWidget;
|
|
et2_widget_description;
|
|
*/
|
|
|
|
import {et2_register_widget, WidgetConfig} from "./et2_core_widget";
|
|
import {ClassWithAttributes} from "./et2_core_inheritance";
|
|
import {et2_inputWidget} from "./et2_core_inputWidget";
|
|
import {Et2Dialog} from "./Et2Dialog/Et2Dialog";
|
|
import {Et2LinkEntry} from "./Et2Link/Et2LinkEntry";
|
|
import {Et2Select} from "./Et2Select/Et2Select";
|
|
import {Et2Description} from "./Et2Description/Et2Description";
|
|
import {Et2Button} from "./Et2Button/Et2Button";
|
|
|
|
|
|
/**
|
|
* Display a dialog to choose a placeholder
|
|
*/
|
|
export class et2_placeholder_select extends et2_inputWidget
|
|
{
|
|
static readonly _attributes : any = {
|
|
insert_callback: {
|
|
"name": "Insert callback",
|
|
"description": "Method called with the selected placeholder text",
|
|
"type": "js"
|
|
},
|
|
dialog_title: {
|
|
"name": "Dialog title",
|
|
"type": "string",
|
|
"default": "Insert Placeholder"
|
|
}
|
|
};
|
|
|
|
static placeholders : Object | null = null;
|
|
|
|
button : JQuery;
|
|
submit_callback : any;
|
|
dialog : Et2Dialog;
|
|
protected value : any;
|
|
|
|
protected LIST_URL = 'EGroupware\\Api\\Etemplate\\Widget\\Placeholder::ajax_get_placeholders';
|
|
protected TEMPLATE = '/api/templates/default/insert_merge_placeholder.xet?1';
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param _parent
|
|
* @param _attrs
|
|
* @memberOf et2_vfsSelect
|
|
*/
|
|
constructor(_parent, _attrs? : WidgetConfig, _child? : object)
|
|
{
|
|
// Call the inherited constructor
|
|
super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_placeholder_select._attributes, _child || {}));
|
|
|
|
// Allow no child widgets
|
|
this.supportedWidgetClasses = [];
|
|
}
|
|
|
|
_content(_content, _callback)
|
|
{
|
|
let self = this;
|
|
if(this.dialog)
|
|
{
|
|
this.dialog.close();
|
|
}
|
|
|
|
var callback = _callback || this._buildDialog;
|
|
if(et2_placeholder_select.placeholders === null)
|
|
{
|
|
this.egw().loading_prompt('placeholder_select', true, '', 'body');
|
|
this.egw().json(
|
|
this.LIST_URL,
|
|
[],
|
|
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);
|
|
}.bind(this)
|
|
).sendRequest(true);
|
|
}
|
|
else
|
|
{
|
|
this._buildDialog(et2_placeholder_select.placeholders);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Builds placeholder selection dialog
|
|
*
|
|
* @param {object} _data content
|
|
*/
|
|
protected _buildDialog(_data)
|
|
{
|
|
let buttons = [
|
|
{
|
|
label: this.egw().lang("Insert"),
|
|
id: "submit",
|
|
image: "export"
|
|
}
|
|
];
|
|
let extra_buttons_action = {};
|
|
|
|
if(this.options.extra_buttons && this.options.method)
|
|
{
|
|
for(let i = 0; i < this.options.extra_buttons.length; i++)
|
|
{
|
|
delete (this.options.extra_buttons[i]['click']);
|
|
buttons.push(this.options.extra_buttons[i]);
|
|
extra_buttons_action[this.options.extra_buttons[i]['id']] = this.options.extra_buttons[i]['id'];
|
|
}
|
|
|
|
}
|
|
buttons.push({label: this.egw().lang("Cancel"), id: "cancel", image: "cancel"});
|
|
|
|
let data = {
|
|
content: {app: '', group: '', entry: {}},
|
|
sel_options: {app: [], group: []},
|
|
modifications: {
|
|
entry: {
|
|
application_list: []
|
|
}
|
|
|
|
}
|
|
};
|
|
|
|
Object.keys(_data).map((key) =>
|
|
{
|
|
data.sel_options.app.push(
|
|
{
|
|
value: key,
|
|
label: this.egw().lang(key)
|
|
});
|
|
});
|
|
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 = {app: data.content.app};
|
|
data.modifications.entry.application_list = Object.keys(_data);
|
|
// Remove non-app placeholders (user & general)
|
|
let non_apps = ['user', 'general'];
|
|
for(let i = 0; i < non_apps.length; i++)
|
|
{
|
|
let index = data.modifications.entry.application_list.indexOf(non_apps[i]);
|
|
data.modifications.entry.application_list.splice(index, 1);
|
|
}
|
|
|
|
// callback for dialog
|
|
this.submit_callback = function(submit_button_id, submit_value)
|
|
{
|
|
if((submit_button_id == 'submit' || (extra_buttons_action && extra_buttons_action[submit_button_id])) && submit_value)
|
|
{
|
|
this._do_insert_callback(submit_value);
|
|
return true;
|
|
}
|
|
else if(submit_button_id == 'cancel')
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// Keep dialog open
|
|
return false;
|
|
}
|
|
}.bind(this);
|
|
|
|
this.dialog = new Et2Dialog(this.egw());
|
|
this.dialog.transformAttributes({
|
|
callback: this.submit_callback,
|
|
title: this.options.dialog_title || "Insert Placeholder",
|
|
buttons: buttons,
|
|
value: data,
|
|
template: this.egw().webserverUrl + this.TEMPLATE,
|
|
resizable: true,
|
|
width: ''
|
|
});
|
|
document.body.appendChild(<HTMLElement><unknown>this.dialog);
|
|
this.dialog.addEventListener('open', this._on_template_load.bind(this));
|
|
}
|
|
|
|
doLoadingFinished()
|
|
{
|
|
this._content.call(this, null);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Post-load of the dialog
|
|
* Bind internal events, set some things that are difficult to do in the template
|
|
*/
|
|
_on_template_load()
|
|
{
|
|
let app = <Et2Select><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("app");
|
|
let group = <Et2Select><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("group");
|
|
let placeholder_list = <Et2Select><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("placeholder_list");
|
|
let preview = <Et2Description><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("preview_placeholder");
|
|
let entry = <Et2LinkEntry><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("entry");
|
|
|
|
placeholder_list.set_select_options(this._get_placeholders(app.get_value(), group.get_value()));
|
|
|
|
// Bind some handlers
|
|
app.onchange = (node, widget) =>
|
|
{
|
|
preview.set_value("");
|
|
if(['user', 'filemanager'].indexOf(widget.get_value()) >= 0)
|
|
{
|
|
// These ones don't let you select an entry for preview (they don't work)
|
|
entry.set_disabled(true);
|
|
entry.set_value({app: 'user', id: '', query: ''});
|
|
}
|
|
else if(widget.get_value() == 'general')
|
|
{
|
|
// Don't change entry app, leave it
|
|
entry.set_disabled(false);
|
|
}
|
|
else
|
|
{
|
|
// Load app translations
|
|
this.egw().langRequireApp(this.egw().window, widget.get_value());
|
|
entry.set_disabled(false);
|
|
entry.set_value({app: widget.get_value(), id: '', query: ''});
|
|
}
|
|
let groups = this._get_group_options(widget.get_value());
|
|
group.set_select_options(groups);
|
|
group.set_value(groups[0].value);
|
|
group.onchange();
|
|
}
|
|
group.onchange = (select_node, select_widget) =>
|
|
{
|
|
let options = this._get_placeholders(app.get_value(), group.get_value())
|
|
placeholder_list.set_select_options(options);
|
|
preview.set_value("");
|
|
placeholder_list.updateComplete.then(() => placeholder_list.set_value(options[0].value));
|
|
}
|
|
placeholder_list.onchange = this._on_placeholder_select.bind(this);
|
|
entry.onchange = this._on_placeholder_select.bind(this);
|
|
(<Et2Button><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("insert_placeholder")).onclick = () =>
|
|
{
|
|
this.options.insert_callback(this.dialog.eTemplate.widgetContainer.getDOMWidgetById("preview_placeholder").getDOMNode().textContent);
|
|
};
|
|
(<Et2Button><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("insert_content")).onclick = () =>
|
|
{
|
|
this.options.insert_callback(this.dialog.eTemplate.widgetContainer.getDOMWidgetById("preview_content").getDOMNode().textContent);
|
|
};
|
|
|
|
app.set_value(app.get_value());
|
|
}
|
|
|
|
/**
|
|
* 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 = <Et2LinkEntry><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("app");
|
|
let entry = <Et2LinkEntry><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("entry");
|
|
let placeholder_list = <Et2Select><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("placeholder_list");
|
|
let preview = <Et2Description><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("preview_placeholder");
|
|
let preview_content = <Et2Description><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("preview_content");
|
|
|
|
// Show the selected placeholder
|
|
this.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';
|
|
|
|
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',
|
|
[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)
|
|
).sendRequest(true);
|
|
}
|
|
else
|
|
{
|
|
// No value, hide the row
|
|
preview_content.getDOMNode().parentNode.style.visibility = 'hidden';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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) =>
|
|
{
|
|
// @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.push({label:key, value: et2_placeholder_select.placeholders[appname][key]});
|
|
}
|
|
else
|
|
{
|
|
let a = {label: key, value:[]};
|
|
for(let sub of Object.keys(et2_placeholder_select.placeholders[appname][key]))
|
|
{
|
|
if(!et2_placeholder_select.placeholders[appname][key][sub])
|
|
{
|
|
continue;
|
|
}
|
|
a.value.push({
|
|
value: key + '-' + sub,
|
|
label: this.egw().lang(sub)
|
|
});
|
|
}
|
|
options.push(a);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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 _group = group.split('-', 2);
|
|
let ph = et2_placeholder_select.placeholders[appname];
|
|
for(let i = 0; typeof ph !== "undefined" && i < _group.length; i++)
|
|
{
|
|
ph = ph[_group[i]];
|
|
}
|
|
return ph || [];
|
|
}
|
|
|
|
/**
|
|
* 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_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": {
|
|
"{{org_name}}\n{{n_fn}}\n{{adr_one_street}}{{NELF adr_one_street2}}\n{{adr_one_formatted}}": "Business address",
|
|
"{{n_fn}}\n{{adr_two_street}}{{NELF adr_two_street2}}\n{{adr_two_formatted}}": "Home address",
|
|
"{{n_fn}}\n{{email}}\n{{tel_work}}": "Name, email, phone"
|
|
}
|
|
}
|
|
};
|
|
|
|
button : JQuery;
|
|
submit_callback : any;
|
|
dialog : Et2Dialog;
|
|
protected value : any;
|
|
|
|
protected LIST_URL = 'EGroupware\\Api\\Etemplate\\Widget\\Placeholder::ajax_get_placeholders';
|
|
protected TEMPLATE = '/api/templates/default/placeholder_snippet.xet?1';
|
|
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param _parent
|
|
* @param _attrs
|
|
* @memberOf et2_vfsSelect
|
|
*/
|
|
constructor(_parent, _attrs? : WidgetConfig, _child? : object)
|
|
{
|
|
// Call the inherited constructor
|
|
super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_placeholder_select._attributes, _child || {}));
|
|
|
|
// Load app translations
|
|
this.egw().langRequireApp(this.egw().window, "addressbook");
|
|
}
|
|
|
|
/**
|
|
* Post-load of the dialog
|
|
* Bind internal events, set some things that are difficult to do in the template
|
|
*/
|
|
_on_template_load()
|
|
{
|
|
let app = <Et2Select><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("app");
|
|
let placeholder_list = <Et2Select><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("placeholder_list");
|
|
let preview = <Et2Description><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("preview_content");
|
|
let entry = <Et2LinkEntry><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("entry");
|
|
|
|
|
|
placeholder_list.set_select_options(this._get_placeholders("addressbook", "addresses"));
|
|
|
|
// Further setup / styling that can't be done in etemplate
|
|
app.setAttribute("readonly", true);
|
|
|
|
// Bind some handlers
|
|
app.onchange = (node, widget) =>
|
|
{
|
|
entry.set_value({app: widget.get_value()});
|
|
placeholder_list.set_select_options(this._get_placeholders(app.value, "addresses"));
|
|
}
|
|
placeholder_list.onchange = this._on_placeholder_select.bind(this);
|
|
entry.onchange = this._on_placeholder_select.bind(this);
|
|
|
|
app.set_value(app.value);
|
|
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 = <Et2Select><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("app");
|
|
let entry = <Et2LinkEntry><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("entry");
|
|
let placeholder_list = <Et2Select><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("placeholder_list");
|
|
let preview_content = <Et2Description><unknown>this.dialog.eTemplate.widgetContainer.getDOMWidgetById("preview_content");
|
|
let placeholder = "";
|
|
if(app && app.value)
|
|
{
|
|
placeholder = Object.keys(et2_placeholder_snippet_select.placeholders[<string>app.value]["addresses"])[<string>placeholder_list.value];
|
|
}
|
|
|
|
if(placeholder && 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',
|
|
[placeholder, {app: "addressbook", id: 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';
|
|
}.bind(this)
|
|
).sendRequest(true);
|
|
}
|
|
else
|
|
{
|
|
// No value, hide the row
|
|
preview_content.getDOMNode().parentNode.style.visibility = 'hidden';
|
|
}
|
|
if(!entry.get_value())
|
|
{
|
|
entry._searchNode.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, index) =>
|
|
{
|
|
options.push(
|
|
{
|
|
value: index,
|
|
label: this.egw().lang(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"]);
|