got LinkEntry mostly working

This commit is contained in:
ralf 2022-06-01 16:05:34 +02:00
parent 9b0e1b9206
commit 0aa813a0ff
6 changed files with 168 additions and 64 deletions

View File

@ -17,7 +17,7 @@ const ADD_ET2_PREFIX_REGEXP = '#<((/?)([vh]?box|date(-time[^\s]*|-duration|-sinc
const ADD_ET2_PREFIX_LAST_GROUP = 6;
// unconditional of legacy add et2- prefix to this widgets
const ADD_ET2_PREFIX_LEGACY_REGEXP = '#<(description|label|image|vfs-mime|vfs-uid|vfs-gid|link|link-string|link-list|favorites)\s([^>]+)/>#m';
const ADD_ET2_PREFIX_LEGACY_REGEXP = '#<(description|label|image|vfs-mime|vfs-uid|vfs-gid|link|link-string|link-list|link-search|link-entry|link-apps|favorites)\s([^>]+)/>#m';
// switch evtl. set output-compression off, as we can't calculate a Content-Length header with transparent compression
ini_set('zlib.output_compression', 0);
@ -67,6 +67,59 @@ function send_template()
// fix <menulist...><menupopup type="select-*"/></menulist> --> <select type="select-*" .../>
$str = preg_replace('#<menulist([^>]*)>[\r\n\s]*<menupopup([^>]+>)[\r\n\s]*</menulist>#', '<select$1$2', $str);
// fix legacy options, so new client-side has not to deal with them
$str = preg_replace_callback('#<([^- />]+)(-[^ ]+)?[^>]* (options="([^"]+)")[ />]#', static function ($matches) {
// take care of (static) type attribute, if used
if (preg_match('/ type="([a-z-]+)"/', $matches[0], $type))
{
str_replace('<' . $matches[1] . $matches[2], '<' . $type[1], $matches[0]);
str_replace($type[0], '', $matches[0]);
list($matches[1], $matches[2]) = explode('-', $type[1], 2);
}
static $legacy_options = array( // use "ignore" to ignore further comma-sep. values, otherwise they are all in last attribute
'select' => 'empty_label,ignore',
'select-account' => 'empty_label,account_type,ignore',
'box' => ',cellpadding,cellspacing,keep',
'hbox' => 'cellpadding,cellspacing,keep',
'vbox' => 'cellpadding,cellspacing,keep',
'groupbox' => 'cellpadding,cellspacing,keep',
'checkbox' => 'selected_value,unselected_value,ro_true,ro_false',
'radio' => 'set_value,ro_true,ro_false',
'customfields' => 'sub-type,use-private,field-names',
'date' => 'data_format,ignore', // Legacy option "mode" was never implemented in et2
'description' => 'bold-italic,link,activate_links,label_for,link_target,link_popup_size,link_title',
'button' => 'image,ro_image',
'buttononly' => 'image,ro_image',
'link-entry' => 'only_app,application_list',
);
// prefer more specific type-subtype over just type
$names = $legacy_options[$matches[1] . $matches[2]] ?? $legacy_options[$matches[1]] ?? null;
if (isset($names))
{
$names = explode(',', $names);
$values = Api\Etemplate\Widget::csv_split($matches[4], count($names));
if (count($values) < count($names))
{
$values = array_merge($values, array_fill(count($values), count($names) - count($values), ''));
}
$attrs = array_diff(array_combine($names, $values), ['', null]);
unset($attrs['ignore']);
// fix select options can be either multiple or empty_label
if ($matches[1] === 'select' && !empty($attrs['empty_label']) && (int)$attrs['empty_label'] > 0)
{
$attrs['multiple'] = (int)$attrs['empty_label'];
unset($matches['empty_label']);
}
$options = '';
foreach ($attrs as $attr => $value)
{
$options .= $attr . '="' . $value . '" ';
}
return str_replace($matches[3], $options, $matches[0]);
}
return $matches[0];
}, $str);
// Change splitter dockside -> primary + vertical
$str = preg_replace_callback('#<split([^>]*?)>(.*)</split>#su', static function ($matches) use ($name) {
$tag = 'et2-split';
@ -110,58 +163,6 @@ function send_template()
}
else
{
// fix legacy options, so new client-side has not to deal with them
$str = preg_replace_callback('#<([^- />]+)(-[^ ]+)?[^>]* (options="([^"]+)")[ />]#', static function ($matches) {
// take care of (static) type attribute, if used
if (preg_match('/ type="([a-z-]+)"/', $matches[0], $type))
{
str_replace('<' . $matches[1] . $matches[2], '<' . $type[1], $matches[0]);
str_replace($type[0], '', $matches[0]);
list($matches[1], $matches[2]) = explode('-', $type[1], 2);
}
static $legacy_options = array( // use "ignore" to ignore further comma-sep. values, otherwise they are all in last attribute
'select' => 'empty_label,ignore',
'select-account' => 'empty_label,account_type,ignore',
'box' => ',cellpadding,cellspacing,keep',
'hbox' => 'cellpadding,cellspacing,keep',
'vbox' => 'cellpadding,cellspacing,keep',
'groupbox' => 'cellpadding,cellspacing,keep',
'checkbox' => 'selected_value,unselected_value,ro_true,ro_false',
'radio' => 'set_value,ro_true,ro_false',
'customfields' => 'sub-type,use-private,field-names',
'date' => 'data_format,ignore', // Legacy option "mode" was never implemented in et2
'description' => 'bold-italic,link,activate_links,label_for,link_target,link_popup_size,link_title',
'button' => 'image,ro_image',
'buttononly' => 'image,ro_image',
);
// prefer more specific type-subtype over just type
$names = $legacy_options[$matches[1] . $matches[2]] ?? $legacy_options[$matches[1]] ?? null;
if (isset($names))
{
$names = explode(',', $names);
$values = Api\Etemplate\Widget::csv_split($matches[4], count($names));
if (count($values) < count($names))
{
$values = array_merge($values, array_fill(count($values), count($names) - count($values), ''));
}
$attrs = array_diff(array_combine($names, $values), ['', null]);
unset($attrs['ignore']);
// fix select options can be either multiple or empty_label
if ($matches[1] === 'select' && !empty($attrs['empty_label']) && (int)$attrs['empty_label'] > 0)
{
$attrs['multiple'] = (int)$attrs['empty_label'];
unset($matches['empty_label']);
}
$options = '';
foreach ($attrs as $attr => $value)
{
$options .= $attr . '="' . $value . '" ';
}
return str_replace($matches[3], $options, $matches[0]);
}
return $matches[0];
}, $str);
// fix deprecated attributes: needed, blur, ...
static $deprecated = [
'needed' => 'required',

View File

@ -71,8 +71,8 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
}
}
protected __app_icons : boolean;
protected __application_list : string[];
protected __only_app : string;
/**
* Constructor
@ -91,6 +91,17 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
this._handleChange = this._handleChange.bind(this);
}
set only_app(app : string)
{
this.__only_app = app;
this.style.display = app ? 'inline' : 'none';
}
get only_app() : string
{
return this.__only_app;
}
connectedCallback()
{
super.connectedCallback();
@ -108,6 +119,8 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
// Register to
this.addEventListener("change", this._handleChange);
if (this.__only_app) this.style.display = 'none';
}
disconnectedCallback()

View File

@ -4,6 +4,12 @@ import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {FormControlMixin, ValidateMixin} from "@lion/form-core";
import {Et2LinkSearch} from "./Et2LinkSearch";
export interface LinkEntry {
app: string;
id: string|number;
title?: string;
}
/**
* EGroupware eTemplate2 - Search & select link entry WebComponent
*
@ -62,12 +68,24 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
...super.slots,
app: () =>
{
const app = document.createElement("et2-link-apps")
const app = <Et2LinkAppSelect>document.createElement("et2-link-apps")
app.only_app = this.__only_app;
return app;
},
select: () =>
{
const select = <Et2LinkSearch><unknown>document.createElement("et2-link-search");
select.app = this.__only_app || this.__app;
if (this.__value && typeof this.__value === 'object')
{
select.app = this.__value.app;
select.select_options = [{value: this.__value.id, label: this.__value.title}];
select.value = this.__value.id;
}
else
{
select.value = this.__value;
}
return select;
}
}
@ -85,15 +103,31 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
this._handleAppChange = this._handleAppChange.bind(this);
}
protected __only_app : string;
protected __app : string;
set only_app(app)
{
this._appNode.only_app = app;
this._searchNode.app = app;
this.__only_app = app;
if (this._appNode) this._appNode.only_app = app;
if (this._searchNode) this._searchNode.app = app;
}
get only_app()
{
return this._appNode.only_app;
return this.__only_app;
}
set app(app)
{
this.__app = app;
if (this._appNode) this._appNode.value = app;
if (this._searchNode) this._searchNode.app = app;
}
get app()
{
return this._appNode?.value || this.__app;
}
get _appNode() : Et2LinkAppSelect
@ -122,6 +156,49 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
this._searchNode.app = this._appNode.value;
}
protected __value : LinkEntry|string|number;
get value() : LinkEntry|string|number
{
if (this.only_app)
{
return this._searchNode?.value || this.__value;
}
return this._searchNode ? {
id: this._searchNode?.value || this.__value,
app: this._appNode?.value || this.__onlyApp || this.__app,
//search: this._searchNode... // content of search field
} : this.__value;
}
set value(val: LinkEntry|string|number)
{
if (!val)
{
if (this._searchNode) this._searchNode.value = '';
}
else if (typeof val === 'string')
{
if (val.indexOf(',') > 0) val = val.replace(",", ":");
const vals = val.split(':');
this.app = vals[0];
if (this._searchNode)
{
this._searchNode.value = vals[1];
}
}
else // object with attributes: app, id, title
{
this.app = val.app;
if (this._searchNode)
{
this._searchNode.value = val.id;
this._searchNode.select_options = [{value: val.id, label: val.title}];
}
}
this.__value = val;
}
/**
* @return {TemplateResult}
* @protected

View File

@ -61,9 +61,16 @@ export class Et2LinkSearch extends Et2Select
return;
}
}
// ToDo use egw.request(), not old egw.json()
request.sendRequest().then((result) =>
{
this.processRemoteResults(result);
result.response.forEach((response) =>
{
if (typeof response.data !== 'undefined')
{
this.processRemoteResults(response.data);
}
});
});
}
}

View File

@ -152,7 +152,13 @@ export const Et2widgetWithSelectMixin = dedupeMixin((superclass) =>
let fixed_options = [];
for(let key in <any>new_options)
{
fixed_options.push({value: key, label: new_options[key]});
let option : any = new_options[key];
if (typeof option === 'string')
{
option = { label: option };
}
option.value = key.trim(); // link_search prefixes keys with one space
fixed_options.push(option);
}
this.__select_options = fixed_options;
}

View File

@ -295,7 +295,7 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) =>
if(this.getItems().length === 1)
{
this.getItems()[0].click();
this.hide();
// not jQuery this.hide();
return;
}
event.preventDefault();
@ -379,7 +379,7 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) =>
protected remoteQuery(search : string, options : object)
{
return this.egw().json(this.searchUrl, [search]).sendRequest().then((result) =>
return this.egw().request(this.searchUrl, [search]).sendRequest().then((result) =>
{
this.processRemoteResults(result);
});
@ -392,7 +392,7 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) =>
*/
protected processRemoteResults(results)
{
// TODO: Add the results in
this.select_options = results;
}
/**