Et2Select: Fix some search weirdness

- Search didn't start until 1 character more than expected
- Search didn't happen on enter because the et2-searchbox inside stopped the key event from bubbling
This commit is contained in:
nathan 2023-02-07 16:24:06 -07:00
parent 9cde6a7171
commit 193dbfc339
2 changed files with 99 additions and 4 deletions

View File

@ -434,12 +434,12 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
}
// I can't figure out how to get this full width via CSS
return html`
<et2-searchbox id="search" type="text" part="input" clearable
placeholder="${this.egw().lang("search")}"
<et2-textbox id="search" type="text" part="input" clearable
placeholder="${this.egw().lang("search")}"
style="width:100%"
@keydown=${this._handleSearchKeyDown}
@blur=${this._handleSearchBlur}
></et2-searchbox>
></et2-textbox>
${edit}
`;
}
@ -882,6 +882,7 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
{
return this.handleKeyDown(event);
}
event.stopPropagation();
// Don't allow event to bubble or it will interact with select
event.stopImmediatePropagation();
@ -913,7 +914,8 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
}
// Start the search automatically if they have enough letters
if(this._searchInputNode.value.length >= Et2WidgetWithSearch.MIN_CHARS)
// -1 because we're in keyDown handler, and value is from _before_ this key was pressed
if(this._searchInputNode.value.length >= Et2WidgetWithSearch.MIN_CHARS - 1)
{
this._searchTimeout = window.setTimeout(() => {this.startSearch()}, Et2WidgetWithSearch.SEARCH_TIMEOUT);
}

View File

@ -7,6 +7,9 @@ import {assert, elementUpdated, fixture, html} from '@open-wc/testing';
import * as sinon from 'sinon';
import {Et2Box} from "../../Layout/Et2Box/Et2Box";
import {Et2Select} from "../Et2Select";
import {Et2Textbox} from "../../Et2Textbox/Et2Textbox";
let keep_import : Et2Textbox = new Et2Textbox();
// Stub global egw for cssImage to find
// @ts-ignore
@ -20,6 +23,7 @@ window.egw = {
let parser = new window.DOMParser();
let container : Et2Box;
const options = [
<SelectOption>{value: "1", label: "Option 1"},
<SelectOption>{value: "2", label: "Option 2"}
@ -75,4 +79,93 @@ describe("Search actions", () =>
// For some reason in the test change gets called twice, even though in normal operation it gets called once.
sinon.assert.called(change);
});
})
describe("Trigger search", () =>
{
let element : Et2Select;
let clock;
// Setup run before each test
beforeEach(async() =>
{
// Mess with time
clock = sinon.useFakeTimers()
// Create an element to test with, and wait until it's ready
// @ts-ignore
element = await fixture<Et2Select>(html`
<et2-select label="I'm a select" search=true>
<sl-menu-item value="one">One</sl-menu-item>
<sl-menu-item value="two">Two</sl-menu-item>
<sl-menu-item value="three">Three</sl-menu-item>
<sl-menu-item value="four">Four</sl-menu-item>
<sl-menu-item value="five">Five</sl-menu-item>
<sl-menu-item value="six">Six</sl-menu-item>
<sl-menu-item value="seven">Seven</sl-menu-item>
</et2-select>
`);
// Stub egw()
sinon.stub(element, "egw").returns(window.egw);
await element.updateComplete;
await element._searchInputNode.updateComplete;
});
afterEach(() =>
{
clock.restore();
})
it("Searches after 2 characters", () =>
{
// Set up spy
let searchSpy = sinon.spy(element, "startSearch");
// Send two keypresses, but we need to explicitly set the value
element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "o"}));
element._searchInputNode.value = "o";
assert(searchSpy.notCalled);
element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "n"}));
element._searchInputNode.value = "on";
assert(searchSpy.notCalled);
// Skip the timeout
clock.runAll();
assert(searchSpy.calledOnce, "startSearch() was not called");
});
it("Searches on enter", () =>
{
// Set up spy
let searchSpy = sinon.spy(element, "startSearch");
// Send two keypresses, but we need to explicitly set the value
element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "o"}));
element._searchInputNode.value = "t";
assert(searchSpy.notCalled);
element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "Enter"}));
// Search starts immediately
assert(searchSpy.calledOnce, "startSearch() was not called");
});
it("Aborts search when escape pressed", () =>
{
// Set up spy
let abortSpy = sinon.spy(element, "_handleSearchAbort");
let searchSpy = sinon.spy(element, "startSearch");
// Send two keypresses, but we need to explicitly set the value
element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "t"}));
element._searchInputNode.value = "t";
element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "Escape"}));
assert(searchSpy.notCalled, "startSearch() was called");
assert(abortSpy.calledOnce, "_handleSearchAbort() was not called");
})
});