Work on LinkEntry

- fix missing app select
- add clear button
- use request() instead of json() to query server
- add optional class property to SelectOption
- move cleaning select options to its own function so we can use it anywhere
- Use separate render to keep local / remote options separate.  Local options stay in select_options.
This commit is contained in:
nathan 2022-06-01 09:23:07 -06:00
parent cbe097b2e3
commit 2b68b6cbbe
6 changed files with 72 additions and 40 deletions

View File

@ -69,7 +69,10 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
app: () =>
{
const app = <Et2LinkAppSelect>document.createElement("et2-link-apps")
app.only_app = this.__only_app;
if(this.__only_app)
{
app.only_app = this.__only_app;
}
return app;
},
select: () =>
@ -105,6 +108,7 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
protected __only_app : string;
protected __app : string;
protected __value : LinkEntry | string | number;
set only_app(app)
{
@ -121,8 +125,14 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
set app(app)
{
this.__app = app;
if (this._appNode) this._appNode.value = app;
if (this._searchNode) this._searchNode.app = app;
if(this._appNode)
{
this._appNode.value = app;
}
if(this._searchNode)
{
this._searchNode.app = app;
}
}
get app()
@ -156,8 +166,6 @@ 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)
@ -203,7 +211,6 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
* @return {TemplateResult}
* @protected
*/
// eslint-disable-next-line class-methods-use-this
_inputGroupInputTemplate()
{
return html`

View File

@ -44,6 +44,7 @@ export class Et2LinkSearch extends Et2Select
super();
this.search = true;
this.searchUrl = "EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link_search";
this.clearable = true;
}
get _appNode() : Et2LinkAppSelect
@ -53,7 +54,7 @@ export class Et2LinkSearch extends Et2Select
protected remoteQuery(search : string, options : object)
{
let request = this.egw().json(this.searchUrl, [this._appNode.value, '', search, options]);
let request = this.egw().request(this.searchUrl, [this._appNode.value, '', search, options]);
if(this.query && typeof this.query == "function")
{
if(!this.query(request, this))
@ -61,16 +62,9 @@ export class Et2LinkSearch extends Et2Select
return;
}
}
// ToDo use egw.request(), not old egw.json()
request.sendRequest().then((result) =>
request.then((result) =>
{
result.response.forEach((response) =>
{
if (typeof response.data !== 'undefined')
{
this.processRemoteResults(response.data);
}
});
this.processRemoteResults(result);
});
}
}

View File

@ -281,7 +281,7 @@ export class Et2Select extends Et2WithSearchMixin(Et2InvokerMixin(Et2WidgetWithS
<et2-image slot="prefix" src="${option.icon}"></et2-image>` : "";
return html`
<sl-menu-item value="${option.value}" title="${option.title}">
<sl-menu-item value="${option.value}" title="${option.title}" class="${option.class}">
${icon}
${option.label}
</sl-menu-item>`;

View File

@ -11,7 +11,7 @@ import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {StaticOptions} from "./StaticOptions";
import {dedupeMixin, html, PropertyValues, render, repeat, TemplateResult} from "@lion/core";
import {et2_readAttrWithDefault} from "../et2_core_xml";
import {find_select_options, SelectOption} from "./FindSelectOptions";
import {cleanSelectOptions, find_select_options, SelectOption} from "./FindSelectOptions";
/**
* Base class for things that do selectbox type behaviour, to avoid putting too much or copying into read-only
@ -147,25 +147,9 @@ export const Et2widgetWithSelectMixin = dedupeMixin((superclass) =>
set select_options(new_options : SelectOption[])
{
const old_options = this.__select_options;
if(!Array.isArray(new_options))
{
let fixed_options = [];
for(let key in <any>new_options)
{
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;
}
else
{
this.__select_options = new_options;
}
this.__select_options = cleanSelectOptions(new_options);
this.requestUpdate("select_options", old_options);
}

View File

@ -15,6 +15,8 @@ export interface SelectOption
title? : string;
// Related image or icon
icon? : string;
// Class applied to node
class? : string;
}
/**
@ -210,3 +212,36 @@ export function find_select_options(widget, attr_options?, options : SelectOptio
}
return content_options;
}
/**
* Clean up things that might be select options and get them to what we need to make
* them consistent for widget use.
*
* Options might be just a list of labels, or an object of value => label pairs, etc.
*
* @param {SelectOption[] | string[] | object} options
*/
export function cleanSelectOptions(options : SelectOption[] | string[] | object) : SelectOption[]
{
let fixed_options = [];
if(!Array.isArray(options))
{
for(let key in <any>options)
{
let option : any = options[key];
if(typeof option === 'string')
{
option = {label: option};
}
option.value = key.trim(); // link_search prefixes keys with one space
fixed_options.push(option);
}
}
else
{
fixed_options = options;
}
return fixed_options;
}

View File

@ -8,7 +8,8 @@
*/
import {css, dedupeMixin, html, LitElement, render, SlotMixin} from "@lion/core";
import {css, dedupeMixin, html, LitElement, render, repeat, SlotMixin} from "@lion/core";
import {cleanSelectOptions, SelectOption} from "./FindSelectOptions";
// Export the Interface for TypeScript
@ -295,7 +296,7 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) =>
if(this.getItems().length === 1)
{
this.getItems()[0].click();
// not jQuery this.hide();
this.dropdown.hide();
return;
}
event.preventDefault();
@ -392,7 +393,18 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) =>
*/
protected processRemoteResults(results)
{
this.select_options = results;
let entries = cleanSelectOptions(results);
// Add a "remote" class so we can tell these apart from any local results
entries.forEach((entry) => entry.class = entry.class += "remote");
let target = this._optionTargetNode || this;
if(target)
{
render(html`${repeat(<SelectOption[]>entries, (option : SelectOption) => option.value, this._optionTemplate.bind(this))}`,
target
);
}
}
/**