From 2b68b6cbbebb73ea160b29d8ffe178b7ede86faa Mon Sep 17 00:00:00 2001 From: nathan Date: Wed, 1 Jun 2022 09:23:07 -0600 Subject: [PATCH] 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. --- api/js/etemplate/Et2Link/Et2LinkEntry.ts | 19 ++++++---- api/js/etemplate/Et2Link/Et2LinkSearch.ts | 14 +++----- api/js/etemplate/Et2Select/Et2Select.ts | 2 +- .../Et2Select/Et2WidgetWithSelectMixin.ts | 24 +++---------- .../etemplate/Et2Select/FindSelectOptions.ts | 35 +++++++++++++++++++ api/js/etemplate/Et2Select/SearchMixin.ts | 18 ++++++++-- 6 files changed, 72 insertions(+), 40 deletions(-) diff --git a/api/js/etemplate/Et2Link/Et2LinkEntry.ts b/api/js/etemplate/Et2Link/Et2LinkEntry.ts index 58c5066056..7c5b15a605 100644 --- a/api/js/etemplate/Et2Link/Et2LinkEntry.ts +++ b/api/js/etemplate/Et2Link/Et2LinkEntry.ts @@ -69,7 +69,10 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin( app: () => { const app = 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` diff --git a/api/js/etemplate/Et2Link/Et2LinkSearch.ts b/api/js/etemplate/Et2Link/Et2LinkSearch.ts index 0a67f9017a..b5101f6edf 100644 --- a/api/js/etemplate/Et2Link/Et2LinkSearch.ts +++ b/api/js/etemplate/Et2Link/Et2LinkSearch.ts @@ -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); }); } } diff --git a/api/js/etemplate/Et2Select/Et2Select.ts b/api/js/etemplate/Et2Select/Et2Select.ts index 0e6337d80c..f710778944 100644 --- a/api/js/etemplate/Et2Select/Et2Select.ts +++ b/api/js/etemplate/Et2Select/Et2Select.ts @@ -281,7 +281,7 @@ export class Et2Select extends Et2WithSearchMixin(Et2InvokerMixin(Et2WidgetWithS ` : ""; return html` - + ${icon} ${option.label} `; diff --git a/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts b/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts index a9e98cc446..36c1c7ed50 100644 --- a/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts +++ b/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts @@ -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 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); } diff --git a/api/js/etemplate/Et2Select/FindSelectOptions.ts b/api/js/etemplate/Et2Select/FindSelectOptions.ts index 46fc8f7384..361aa3cc3a 100644 --- a/api/js/etemplate/Et2Select/FindSelectOptions.ts +++ b/api/js/etemplate/Et2Select/FindSelectOptions.ts @@ -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 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; +} \ No newline at end of file diff --git a/api/js/etemplate/Et2Select/SearchMixin.ts b/api/js/etemplate/Et2Select/SearchMixin.ts index c21658b34d..b7a609e6a2 100644 --- a/api/js/etemplate/Et2Select/SearchMixin.ts +++ b/api/js/etemplate/Et2Select/SearchMixin.ts @@ -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(entries, (option : SelectOption) => option.value, this._optionTemplate.bind(this))}`, + target + ); + } } /**