From 5f7b9bd5f4a80fa2ceca4720e594f665384d875c Mon Sep 17 00:00:00 2001 From: nathan Date: Thu, 2 Jun 2022 11:52:27 -0600 Subject: [PATCH] Work on LinkEntry - Show / hide app select depending on has current value - Hide current value when searching to get more space --- api/js/etemplate/Et2Link/Et2LinkEntry.ts | 121 +++++++++++++++++++--- api/js/etemplate/Et2Link/Et2LinkSearch.ts | 1 + api/js/etemplate/Et2Select/SearchMixin.ts | 26 +++-- 3 files changed, 126 insertions(+), 22 deletions(-) diff --git a/api/js/etemplate/Et2Link/Et2LinkEntry.ts b/api/js/etemplate/Et2Link/Et2LinkEntry.ts index 09489d8b34..f5da783ca3 100644 --- a/api/js/etemplate/Et2Link/Et2LinkEntry.ts +++ b/api/js/etemplate/Et2Link/Et2LinkEntry.ts @@ -1,16 +1,3 @@ -import {css, html, LitElement, SlotMixin} from "@lion/core"; -import {Et2LinkAppSelect} from "./Et2LinkAppSelect"; -import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; -import {FormControlMixin, ValidateMixin} from "@lion/form-core"; -import {Et2LinkSearch} from "./Et2LinkSearch"; -import {LinkInfo} from "./Et2Link"; - -export interface LinkEntry { - app: string; - id: string|number; - title?: string; -} - /** * EGroupware eTemplate2 - Search & select link entry WebComponent * @@ -19,6 +6,26 @@ export interface LinkEntry { * @link https://www.egroupware.org * @author Nathan Gray */ + +import {css, html, LitElement, SlotMixin} from "@lion/core"; +import {Et2LinkAppSelect} from "./Et2LinkAppSelect"; +import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; +import {FormControlMixin, ValidateMixin} from "@lion/form-core"; +import {Et2LinkSearch} from "./Et2LinkSearch"; +import {LinkInfo} from "./Et2Link"; + +export interface LinkEntry +{ + app : string; + id : string | number; + title? : string; +} + +/** + * Find and select a single entry using the link system. + * + * + */ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(SlotMixin(LitElement)))) { static get styles() @@ -29,6 +36,10 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin( :host { display: block; } + :host(.hideApp) ::slotted([slot="app"]) { + display: none; + } + ` ]; } @@ -108,6 +119,8 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin( */ private _value : LinkInfo; + protected __only_app : string; + constructor() { super(); @@ -118,12 +131,22 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin( super.connectedCallback(); this._handleAppChange = this._handleAppChange.bind(this); + this._handleEntrySelect = this._handleEntrySelect.bind(this); + this._handleEntryClear = this._handleEntryClear.bind(this); + this._handleShow = this._handleShow.bind(this); + this._handleHide = this._handleHide.bind(this); // Clear initial value this._value = undefined; + + this._bindListeners(); } - protected __only_app : string; + disconnectedCallback() + { + super.disconnectedCallback(); + this._unbindListeners(); + } set only_app(app) { @@ -164,19 +187,83 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin( protected _bindListeners() { this._appNode.addEventListener("change", this._handleAppChange); + this.addEventListener("sl-select", this._handleEntrySelect); + this.addEventListener("sl-clear", this._handleEntryClear); + this.addEventListener("sl-show", this._handleShow); + this.addEventListener("sl-hide", this._handleHide); } protected _unbindListeners() { this._appNode.removeEventListener("change", this._handleAppChange); + this.removeEventListener("sl-select", this._handleEntrySelect); + this.removeEventListener("sl-clear", this._handleEntryClear); + this.removeEventListener("sl-show", this._handleShow); + this.removeEventListener("sl-hide", this._handleHide); } + /** + * Update the search node's app & clear selected value when + * selected app changes. + * @param event + * @protected + */ protected _handleAppChange(event) { this._searchNode.app = this._appNode.value; + this._searchNode.value = ""; } - get value() : LinkEntry|string|number + /** + * Hide app selection when there's an entry + * @param event + * @protected + */ + protected _handleEntrySelect(event) + { + this.classList.add("hideApp"); + } + + + /** + * Show app selection when there's no entry + * @param event + * @protected + */ + protected _handleEntryClear(event) + { + this.classList.remove("hideApp") + } + + + /** + * Option select dropdown opened + * Show app selection (Et2LinkAppSelect controls own visibility according to only_app) + * @param event + * @protected + */ + protected _handleShow(event) + { + this.classList.remove("hideApp"); + } + + /** + * Option select dropdown closed + * Hide app selection (Et2LinkAppSelect controls own visibility according to only_app) + * only if there's a value selected + * + * @param event + * @protected + */ + protected _handleHide(event) + { + if(this._searchNode.value) + { + this.classList.add("hideApp"); + } + } + + get value() : LinkEntry | string | number { if(this.only_app) { @@ -223,6 +310,10 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin( this.app = value.app; this._searchNode.value = value.id; } + if(value.id) + { + this.classList.add("hideApp"); + } } /** diff --git a/api/js/etemplate/Et2Link/Et2LinkSearch.ts b/api/js/etemplate/Et2Link/Et2LinkSearch.ts index 4296d7f1f6..c89a3a37d5 100644 --- a/api/js/etemplate/Et2Link/Et2LinkSearch.ts +++ b/api/js/etemplate/Et2Link/Et2LinkSearch.ts @@ -46,6 +46,7 @@ export class Et2LinkSearch extends Et2Select this.search = true; this.searchUrl = "EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link_search"; this.clearable = true; + this.hoist = true; } get _appNode() : Et2LinkAppSelect diff --git a/api/js/etemplate/Et2Select/SearchMixin.ts b/api/js/etemplate/Et2Select/SearchMixin.ts index 7c2549c15e..acfdc3277a 100644 --- a/api/js/etemplate/Et2Select/SearchMixin.ts +++ b/api/js/etemplate/Et2Select/SearchMixin.ts @@ -260,6 +260,10 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) => this._activeControls?.classList.add("active"); this._searchInputNode.focus(); this._searchInputNode.select(); + + // Hide the label for the currently selected value - it shows as checked in list + // and we want the space + this.shadowRoot.querySelector("[part='display-label']").style.display = "none"; } } @@ -269,9 +273,21 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) => if(this.searchEnabled) { this._activeControls?.classList.remove("active"); + + // Restore selected value visibility + this.shadowRoot.querySelector("[part='display-label']").style.display = ""; } } + /** + * Value was cleared + */ + _handleClear() + { + // Restore label styling + this.shadowRoot.querySelector("[part='display-label']").style.display = ""; + } + /** * Handle keypresses inside the search input * @param {KeyboardEvent} event @@ -292,13 +308,6 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) => event.stopImmediatePropagation(); if(event.key === "Enter") { - // If there's only one option, select it - if(this.getItems().length === 1) - { - this.getItems()[0].click(); - this.dropdown.hide(); - return; - } event.preventDefault(); this.startSearch(); } @@ -401,6 +410,9 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) => let target = this._optionTargetNode || this; if(target) { + // Keep local options first, add in remote options + entries = this.select_options.concat(entries); + render(html`${repeat(entries, (option : SelectOption) => option.value, this._optionTemplate.bind(this))}`, target );