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

View File

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

View File

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

View File

@ -11,7 +11,7 @@ import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {StaticOptions} from "./StaticOptions"; import {StaticOptions} from "./StaticOptions";
import {dedupeMixin, html, PropertyValues, render, repeat, TemplateResult} from "@lion/core"; import {dedupeMixin, html, PropertyValues, render, repeat, TemplateResult} from "@lion/core";
import {et2_readAttrWithDefault} from "../et2_core_xml"; 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 * 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[]) set select_options(new_options : SelectOption[])
{ {
const old_options = this.__select_options; const old_options = this.__select_options;
if(!Array.isArray(new_options))
{ this.__select_options = cleanSelectOptions(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.requestUpdate("select_options", old_options); this.requestUpdate("select_options", old_options);
} }

View File

@ -15,6 +15,8 @@ export interface SelectOption
title? : string; title? : string;
// Related image or icon // Related image or icon
icon? : string; 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; 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 // Export the Interface for TypeScript
@ -295,7 +296,7 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) =>
if(this.getItems().length === 1) if(this.getItems().length === 1)
{ {
this.getItems()[0].click(); this.getItems()[0].click();
// not jQuery this.hide(); this.dropdown.hide();
return; return;
} }
event.preventDefault(); event.preventDefault();
@ -392,7 +393,18 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) =>
*/ */
protected processRemoteResults(results) 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
);
}
} }
/** /**