forked from extern/egroupware
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:
parent
2e5cc0de10
commit
a3d2674757
@ -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(','));
|
||||||
|
@ -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;
|
||||||
|
@ -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))
|
||||||
|
Loading…
Reference in New Issue
Block a user