Work on LinkEntry

- Show / hide app select depending on has current value
- Hide current value when searching to get more space
This commit is contained in:
nathan 2022-06-02 11:52:27 -06:00
parent d5055b9b95
commit 5f7b9bd5f4
3 changed files with 126 additions and 22 deletions

View File

@ -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 * EGroupware eTemplate2 - Search & select link entry WebComponent
* *
@ -19,6 +6,26 @@ export interface LinkEntry {
* @link https://www.egroupware.org * @link https://www.egroupware.org
* @author Nathan Gray * @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)))) export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(SlotMixin(LitElement))))
{ {
static get styles() static get styles()
@ -29,6 +36,10 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
:host { :host {
display: block; display: block;
} }
:host(.hideApp) ::slotted([slot="app"]) {
display: none;
}
` `
]; ];
} }
@ -108,6 +119,8 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
*/ */
private _value : LinkInfo; private _value : LinkInfo;
protected __only_app : string;
constructor() constructor()
{ {
super(); super();
@ -118,12 +131,22 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
super.connectedCallback(); super.connectedCallback();
this._handleAppChange = this._handleAppChange.bind(this); 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 // Clear initial value
this._value = undefined; this._value = undefined;
this._bindListeners();
} }
protected __only_app : string; disconnectedCallback()
{
super.disconnectedCallback();
this._unbindListeners();
}
set only_app(app) set only_app(app)
{ {
@ -164,19 +187,83 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
protected _bindListeners() protected _bindListeners()
{ {
this._appNode.addEventListener("change", this._handleAppChange); 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() protected _unbindListeners()
{ {
this._appNode.removeEventListener("change", this._handleAppChange); 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) protected _handleAppChange(event)
{ {
this._searchNode.app = this._appNode.value; 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) if(this.only_app)
{ {
@ -223,6 +310,10 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
this.app = value.app; this.app = value.app;
this._searchNode.value = value.id; this._searchNode.value = value.id;
} }
if(value.id)
{
this.classList.add("hideApp");
}
} }
/** /**

View File

@ -46,6 +46,7 @@ export class Et2LinkSearch extends Et2Select
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; this.clearable = true;
this.hoist = true;
} }
get _appNode() : Et2LinkAppSelect get _appNode() : Et2LinkAppSelect

View File

@ -260,6 +260,10 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) =>
this._activeControls?.classList.add("active"); this._activeControls?.classList.add("active");
this._searchInputNode.focus(); this._searchInputNode.focus();
this._searchInputNode.select(); 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) if(this.searchEnabled)
{ {
this._activeControls?.classList.remove("active"); 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 * Handle keypresses inside the search input
* @param {KeyboardEvent} event * @param {KeyboardEvent} event
@ -292,13 +308,6 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) =>
event.stopImmediatePropagation(); event.stopImmediatePropagation();
if(event.key === "Enter") 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(); event.preventDefault();
this.startSearch(); this.startSearch();
} }
@ -401,6 +410,9 @@ export const Et2WithSearchMixin = dedupeMixin((superclass) =>
let target = this._optionTargetNode || this; let target = this._optionTargetNode || this;
if(target) if(target)
{ {
// Keep local options first, add in remote options
entries = this.select_options.concat(entries);
render(html`${repeat(<SelectOption[]>entries, (option : SelectOption) => option.value, this._optionTemplate.bind(this))}`, render(html`${repeat(<SelectOption[]>entries, (option : SelectOption) => option.value, this._optionTemplate.bind(this))}`,
target target
); );