Et2Select + search: Fix some bugs

- Select a searched value didn't validate due to different attribute name
- et2-searchbox inside et2-select threw an additional change event, needed to catch that
- fix_bad_value() needs different handling when you can search, otherwise it just gets cleared again
This commit is contained in:
nathan 2022-08-31 13:27:10 -06:00
parent 2e5cc0de10
commit a3d2674757
3 changed files with 74 additions and 7 deletions

View File

@ -192,9 +192,12 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
} }
_triggerChange(e) _triggerChange(e)
{
if(super._triggerChange(e))
{ {
this.dispatchEvent(new Event("change")); this.dispatchEvent(new Event("change"));
} }
}
/** /**
* Change the menu sizing to allow the menu to be wider than the field width, but no smaller * Change the menu sizing to allow the menu to be wider than the field width, but no smaller
@ -234,6 +237,11 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
// Nothing to do here // Nothing to do here
return; return;
} }
// See if parent (search / free entry) is OK with it
if(super.fix_bad_value())
{
return;
}
// If no value is set, choose the first option // If no value is set, choose the first option
// Only do this on once during initial setup, or it can be impossible to clear the value // Only do this on once during initial setup, or it can be impossible to clear the value
const valueArray = Array.isArray(this.value) ? this.value : (!this.value ? [] : this.value.toString().split(',')); const valueArray = Array.isArray(this.value) ? this.value : (!this.value ? [] : this.value.toString().split(','));

View File

@ -140,6 +140,10 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
flex: 1 1 auto; flex: 1 1 auto;
width: 100%; width: 100%;
} }
/* Full width search textbox covers loading spinner, lift it up */
::slotted(sl-spinner) {
z-index: 2;
}
/* Don't show the current value while searching for single, we want the space /* Don't show the current value while searching for single, we want the space
This lets the current value shrink to nothing so the input can expand This lets the current value shrink to nothing so the input can expand
*/ */
@ -265,6 +269,7 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
this._handleClear = this._handleClear.bind(this); this._handleClear = this._handleClear.bind(this);
this._handleDoubleClick = this._handleDoubleClick.bind(this); this._handleDoubleClick = this._handleDoubleClick.bind(this);
this._handleSearchAbort = this._handleSearchAbort.bind(this); this._handleSearchAbort = this._handleSearchAbort.bind(this);
this._handleSearchChange = this._handleSearchChange.bind(this);
this._handleSearchKeyDown = this._handleSearchKeyDown.bind(this); this._handleSearchKeyDown = this._handleSearchKeyDown.bind(this);
this._handleEditKeyDown = this._handleEditKeyDown.bind(this); this._handleEditKeyDown = this._handleEditKeyDown.bind(this);
} }
@ -393,12 +398,12 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
protected get _searchInputNode() : HTMLInputElement protected get _searchInputNode() : HTMLInputElement
{ {
return this._activeControls.querySelector("#search"); return this._activeControls?.querySelector("#search");
} }
protected get _editInputNode() : HTMLInputElement protected get _editInputNode() : HTMLInputElement
{ {
return this._activeControls.querySelector("input#edit"); return this._activeControls?.querySelector("input#edit");
} }
protected get _activeControls() protected get _activeControls()
@ -454,6 +459,25 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
} }
} }
protected fix_bad_value()
{
if(!this.allowFreeEntries && !this.searchEnabled)
{
// Let regular select deal with it
return false;
}
const valueArray = Array.isArray(this.value) ? this.value : (!this.value ? [] : this.value.toString().split(','));
// Check any already found options
if(Object.values(this.menuItems).filter((option) => valueArray.find(val => val == option.value)).length === 0)
{
return false;
}
return true;
// TODO? Should we check the server, or just be OK with it? Passing the "current" value in sel_options makes sure the value is there
}
protected _bindListeners() protected _bindListeners()
{ {
this.addEventListener("sl-select", this._handleSelect); this.addEventListener("sl-select", this._handleSelect);
@ -468,6 +492,9 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
// selecting an option fires 2 change events - 1 before the widget is finished adjusting, losing the value // selecting an option fires 2 change events - 1 before the widget is finished adjusting, losing the value
// We catch all change events, then call this._oldChange only when value changes // We catch all change events, then call this._oldChange only when value changes
this.removeEventListener("change", this._oldChange); this.removeEventListener("change", this._oldChange);
this._searchInputNode.removeEventListener("change", this._searchInputNode.handleChange);
this._searchInputNode.addEventListener("change", this._handleSearchChange);
}); });
} }
@ -476,6 +503,8 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
this.removeEventListener("sl-select", this._handleSelect); this.removeEventListener("sl-select", this._handleSelect);
this.removeEventListener("sl-clear", this._handleClear) this.removeEventListener("sl-clear", this._handleClear)
this.removeEventListener("change", this._handleChange); this.removeEventListener("change", this._handleChange);
this._searchInputNode?.removeEventListener("change", this._handleSearchChange);
} }
handleMenuShow() handleMenuShow()
@ -523,6 +552,18 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
} }
} }
_triggerChange(event)
{
// Don't want searchbox events to trigger change event
if(event.target == this._searchInputNode)
{
event.stopImmediatePropagation();
event.preventDefault();
return false;
}
return true;
}
_handleChange(event) _handleChange(event)
{ {
if(event.target == this._searchInputNode) if(event.target == this._searchInputNode)
@ -792,6 +833,7 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
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
); );
this.handleMenuSlotChange();
} }
} }
@ -951,6 +993,19 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
}) })
this.syncItemsFromValue(); this.syncItemsFromValue();
} }
/**
* et2-searchbox (SlInput) sends out an event on change.
* We don't care, and if we let it bubble it'll get in the way.
* @param e
* @protected
*/
protected _handleSearchChange(e)
{
e.stopImmediatePropagation();
e.preventDefault();
return false;
}
} }
return Et2WidgetWithSearch as unknown as Constructor<SearchMixinInterface> & T; return Et2WidgetWithSearch as unknown as Constructor<SearchMixinInterface> & T;

View File

@ -152,19 +152,23 @@ class Taglist extends Etemplate\Widget
$type == 2 && $account_type == 'users' || $type == 2 && $account_type == 'users' ||
in_array($account_type, array('owngroups', 'memberships')) && in_array($account_type, array('owngroups', 'memberships')) &&
!in_array($val, $GLOBALS['egw']->accounts->memberships( !in_array($val, $GLOBALS['egw']->accounts->memberships(
$GLOBALS['egw_info']['user']['account_id'], true)) $GLOBALS['egw_info']['user']['account_id'], true
)
)
) )
{ {
self::set_validation_error($form_name, lang("'%1' is NOT allowed ('%2')!", $val, self::set_validation_error($form_name, lang("'%1' is NOT allowed ('%2')!", $val,
!$type?'not found' : ($type == 1 ? 'user' : 'group')),''); !$type ? 'not found' : ($type == 1 ? 'user' : 'group')
), ''
);
$value = ''; $value = '';
break; break;
} }
continue; continue;
} }
if(count($allowed) && !$this->attrs['allowFreeEntries'] && empty($this->attrs['autocomplete_url']) && !array_key_exists($val,$allowed)) if(count($allowed) && !$this->attrs['allowFreeEntries'] && empty($this->attrs['searchUrl']) && !array_key_exists($val, $allowed))
{ {
self::set_validation_error($form_name,lang("'%1' is NOT allowed ('%2')!",$val,implode("','",array_keys($allowed))),''); self::set_validation_error($form_name, lang("'%1' is NOT allowed ('%2')!", $val, implode("','", array_keys($allowed))), '');
unset($value[$key]); unset($value[$key]);
} }
if(str_contains($this->type, 'email') && $this->attrs['include_lists'] && is_numeric($val)) if(str_contains($this->type, 'email') && $this->attrs['include_lists'] && is_numeric($val))