diff --git a/api/js/etemplate/Et2Vfs/Et2VfsPath.ts b/api/js/etemplate/Et2Vfs/Et2VfsPath.ts index 8c2db958ca..f28713d4b4 100644 --- a/api/js/etemplate/Et2Vfs/Et2VfsPath.ts +++ b/api/js/etemplate/Et2Vfs/Et2VfsPath.ts @@ -118,9 +118,14 @@ export class Et2VfsPath extends Et2InputWidget(LitElement) public blur() { + const oldEditing = this.editing; this.editing = false; + this.requestUpdate("editing", oldEditing); + if(!this._edit) + { + return; + } - this.requestUpdate("editing"); let oldValue = this.value; this.value = this._edit.value; @@ -149,7 +154,7 @@ export class Et2VfsPath extends Et2InputWidget(LitElement) { const wrapper = this.shadowRoot.querySelector(".vfs-path__scroll"); const path = wrapper?.querySelector("sl-breadcrumb"); - const scroll = path?.shadowRoot.querySelector("nav"); + const scroll = path?.shadowRoot?.querySelector("nav"); if(!wrapper || !scroll) { return; @@ -183,14 +188,21 @@ export class Et2VfsPath extends Et2InputWidget(LitElement) switch(event.key) { case "Enter": - event.stopPropagation(); - event.preventDefault(); - this.editing = !this.editing; - this.requestUpdate("editing"); - break; + const oldValue = this.value; + this.value = this._edit.value; + this.requestUpdate("value", oldValue); + if(oldValue != this.value) + { + this.updateComplete.then(() => + { + this.dispatchEvent(new Event("change")); + }); + } + // Fall through case "Escape": event.stopPropagation(); event.preventDefault(); + this._edit.value = this.value; this.blur(); break; } @@ -372,7 +384,6 @@ export class Et2VfsPath extends Et2InputWidget(LitElement) ?required=${this.required} .value=${this.value} tabindex="-1" - aria-hidden="true" @blur=${() => this.blur()} @keydown=${this.handleKeyDown} /> diff --git a/api/js/etemplate/Et2Vfs/test/Et2VfsPath.test.ts b/api/js/etemplate/Et2Vfs/test/Et2VfsPath.test.ts index cb6dd68f37..c3f3264ef3 100644 --- a/api/js/etemplate/Et2Vfs/test/Et2VfsPath.test.ts +++ b/api/js/etemplate/Et2Vfs/test/Et2VfsPath.test.ts @@ -1,7 +1,8 @@ -import {assert, elementUpdated, fixture, html} from '@open-wc/testing'; +import {assert, elementUpdated, expect, fixture, html, oneEvent} from '@open-wc/testing'; import * as sinon from 'sinon'; import {inputBasicTests} from "../../Et2InputWidget/test/InputBasicTests"; import {Et2VfsPath} from "../Et2VfsPath"; +import {sendKeys} from "@web/test-runner-commands"; /** * Test file for Etemplate webComponent VfsPath @@ -64,18 +65,80 @@ describe("Path widget basics", () => await elementUpdated(element); assert.equal(element.shadowRoot.activeElement, element._edit, "Editable path did not get focus when widget got focus"); }); +}); +describe("User interactions", () => +{ + // Setup run before each test + beforeEach(before); it("blurring widget accepts current text", async() => { + const changeListener = oneEvent(element, "change"); const value = "/home/test/directory"; + + // Enter new value element.focus(); await elementUpdated(element); element._edit.value = value; + + // Lose focus element.blur(); await elementUpdated(element); assert.equal(element.value, value, "Path was not accepted on blur"); + + // Make sure change event is fired + return changeListener; }); + it("[Enter] accepts current path", async() => + { + const originalValue = "/home/different/directory"; + const changedValue = "/home/test/directory"; + element.value = originalValue; + element.focus(); + await elementUpdated(element); + const changeListener = oneEvent(element, "change"); + + // Enter field, "type" a new value + element._edit.focus(); + element._edit.value = changedValue; + + // Press Enter to accept new value + await sendKeys({down: "Enter"}); + + // Wait for change event + const event = await changeListener; + expect(event).to.exist; + + // Check value + assert.equal(element.value, changedValue, "Value did not change on [Enter]"); + }); + + it("[Esc] rejects current path", async() => + { + const originalValue = "/home/different/directory"; + const changedValue = "/home/changed/directory"; + element.value = originalValue; + element.focus(); + await elementUpdated(element); + + // Set up spy for change event + const handler = sinon.spy(); + element.addEventListener("change", handler); + + // Change the value + element._edit.focus(); + element._edit.value = changedValue; + + // Press Escape, cancel edit + await sendKeys({down: "Escape"}); + + // Check value + assert.equal(element.value, originalValue, "Value was changed when [Esc] was pressed"); + + // No change event + sinon.assert.notCalled(handler); + }) }); inputBasicTests(async() =>