diff --git a/app/assets/javascripts/discourse/tests/acceptance/category-edit-test.js b/app/assets/javascripts/discourse/tests/acceptance/category-edit-test.js index aaf2dda4dd6..a315b60e72d 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/category-edit-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/category-edit-test.js @@ -114,7 +114,6 @@ acceptance("Category Edit", function (needs) { await allowedTagChooser.expand(); await allowedTagChooser.selectRowByValue("monkey"); - await allowedTagChooser.collapse(); const allowedTagGroupChooser = selectKit("#category-allowed-tag-groups"); await allowedTagGroupChooser.expand(); await allowedTagGroupChooser.selectRowByValue("TagGroup1"); @@ -128,7 +127,6 @@ acceptance("Category Edit", function (needs) { assert.deepEqual(payload.allowed_tags, ["monkey"]); assert.deepEqual(payload.allowed_tag_groups, ["TagGroup1"]); - await allowedTagGroupChooser.collapse(); await allowedTagChooser.expand(); await allowedTagChooser.deselectItemByValue("monkey"); diff --git a/app/assets/javascripts/discourse/tests/acceptance/select-kit-accessibility-test.js b/app/assets/javascripts/discourse/tests/acceptance/select-kit-accessibility-test.js deleted file mode 100644 index d4940f45231..00000000000 --- a/app/assets/javascripts/discourse/tests/acceptance/select-kit-accessibility-test.js +++ /dev/null @@ -1,67 +0,0 @@ -import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers"; -import { click, tab, triggerKeyEvent, visit } from "@ember/test-helpers"; -import selectKit from "discourse/tests/helpers/select-kit-helper"; -import { test } from "qunit"; - -acceptance("Select-kit - Composer - Accessibility", function (needs) { - needs.user(); - needs.site({ can_tag_topics: true }); - needs.settings({ allow_uncategorized_topics: true }); - - test("tabbing works", async function (assert) { - await visit("/"); - await click("#create-topic"); - - const tagChooser = selectKit(".mini-tag-chooser"); - await tagChooser.expand(); - - assert - .dom(".mini-tag-chooser .filter-input") - .isFocused("it should focus the filter by default"); - - await tab(); - - assert - .dom(".mini-tag-chooser .select-kit-row:first-child") - .isFocused("it should focus the first row next"); - - await tab({ backwards: true }); - - assert - .dom(".mini-tag-chooser .filter-input") - .isFocused("it should focus the filter again when tabbing backwards"); - - await tab({ backwards: true }); - - assert - .dom(".mini-tag-chooser .select-kit-header") - .isFocused("it should focus the tag chooser header next"); - - await tab({ backwards: true }); - - assert - .dom(".category-chooser .select-kit-header") - .isFocused("it should focus the category chooser header next"); - - await tab(); - - assert - .dom(".mini-tag-chooser .select-kit-header") - .isFocused("it should focus the tag chooser again"); - - await tagChooser.expand(); - - await triggerKeyEvent( - ".mini-tag-chooser .select-kit-row:first-child", - "keydown", - "Escape" - ); - - assert.notOk( - exists(".mini-tag-chooser .select-kit-body .select-kit-row"), - "Hitting Escape dismisses the tag chooser" - ); - - assert.ok(exists(".composer-fields"), "Escape does not dismiss composer"); - }); -}); diff --git a/app/assets/javascripts/discourse/tests/integration/components/select-kit/single-select-test.js b/app/assets/javascripts/discourse/tests/integration/components/select-kit/single-select-test.js index 299e1038ad7..c06eeadf84f 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/select-kit/single-select-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/select-kit/single-select-test.js @@ -1,6 +1,6 @@ import { module, test } from "qunit"; import { setupRenderingTest } from "discourse/tests/helpers/component-test"; -import { render, tab } from "@ember/test-helpers"; +import { render } from "@ember/test-helpers"; import I18n from "I18n"; import { hbs } from "ember-cli-htmlbars"; import selectKit from "discourse/tests/helpers/select-kit-helper"; @@ -63,54 +63,6 @@ module("Integration | Component | select-kit/single-select", function (hooks) { ); }); - test("accessibility", async function (assert) { - setDefaultState(this); - - await render(hbs``); - - await this.subject.expand(); - - const content = this.subject.displayedContent(); - assert.strictEqual(content.length, 3, "it shows rows"); - - assert - .dom(".select-kit-header") - .isFocused("it should focus the header first"); - - await tab(); - - assert - .dom(".select-kit-row:first-child") - .isFocused("it should focus the first row next"); - - await tab(); - - assert - .dom(".select-kit-row:nth-child(2)") - .isFocused("tab moves focus to 2nd row"); - - await tab(); - - assert - .dom(".select-kit-row:nth-child(3)") - .isFocused("tab moves focus to 3rd row"); - - await tab(); - - assert.notOk( - this.subject.isExpanded(), - "when there are no more rows, Tab collapses the dropdown" - ); - - await this.subject.expand(); - - assert.ok(this.subject.isExpanded(), "dropdown is expanded again"); - - await tab({ backwards: true }); - - assert.notOk(this.subject.isExpanded(), "Shift+Tab collapses the dropdown"); - }); - test("value", async function (assert) { setDefaultState(this); diff --git a/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-body.js b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-body.js index 8cdac072c85..a6a8437fe6b 100644 --- a/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-body.js +++ b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-body.js @@ -1,6 +1,5 @@ import Component from "@ember/component"; -import { bind } from "discourse-common/utils/decorators"; -import { later } from "@ember/runloop"; +import { bind } from "@ember/runloop"; import { computed } from "@ember/object"; export default Component.extend({ @@ -11,53 +10,55 @@ export default Component.extend({ return false; }), + rootEventType: "click", + + init() { + this._super(...arguments); + + this.handleRootMouseDownHandler = bind(this, this.handleRootMouseDown); + }, + didInsertElement() { this._super(...arguments); this.element.style.position = "relative"; - document.addEventListener("click", this.handleClick, true); - this.selectKit - .mainElement() - .addEventListener("keydown", this._handleKeydown, true); + + document.addEventListener( + this.rootEventType, + this.handleRootMouseDownHandler, + true + ); }, willDestroyElement() { this._super(...arguments); - document.removeEventListener("click", this.handleClick, true); - this.selectKit - .mainElement() - .removeEventListener("keydown", this._handleKeydown, true); + + document.removeEventListener( + this.rootEventType, + this.handleRootMouseDownHandler, + true + ); }, - @bind - handleClick(event) { - if (!this.selectKit.isExpanded || !this.selectKit.mainElement()) { + handleRootMouseDown(event) { + if (!this.selectKit.isExpanded) { return; } - if (this.selectKit.mainElement().contains(event.target)) { + const headerElement = document.querySelector( + `#${this.selectKit.uniqueID}-header` + ); + + if (headerElement && headerElement.contains(event.target)) { return; } - this.selectKit.close(event); - }, - - @bind - _handleKeydown(event) { - if (!this.selectKit.isExpanded || event.key !== "Tab") { + if (this.element.contains(event.target)) { return; } - later(() => { - if ( - this.isDestroying || - this.isDestroyed || - this.selectKit.mainElement().contains(document.activeElement) - ) { - return; - } - + if (this.selectKit.mainElement()) { this.selectKit.close(event); - }, 50); + } }, }); diff --git a/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-filter.js b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-filter.js index 47c10fdec3b..56f1fceeac5 100644 --- a/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-filter.js +++ b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-filter.js @@ -94,8 +94,6 @@ export default Component.extend(UtilsMixin, { if (event.key === "Escape") { this.selectKit.close(event); this.selectKit.headerElement().focus(); - event.preventDefault(); - event.stopPropagation(); return false; } diff --git a/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-row.js b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-row.js index d8a33cfd99d..9f0df11e103 100644 --- a/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-row.js +++ b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-row.js @@ -41,6 +41,7 @@ export default Component.extend(UtilsMixin, { if (!this.site.mobileView) { this.element.addEventListener("mouseenter", this.handleMouseEnter); this.element.addEventListener("focus", this.handleMouseEnter); + this.element.addEventListener("blur", this.handleBlur); } }, @@ -48,8 +49,9 @@ export default Component.extend(UtilsMixin, { this._super(...arguments); if (!this.site.mobileView) { - this.element.removeEventListener("mouseenter", this.handleMouseEnter); + this.element.removeEventListener("mouseenter", this.handleBlur); this.element.removeEventListener("focus", this.handleMouseEnter); + this.element.removeEventListener("blur", this.handleMouseEnter); } }, @@ -132,6 +134,20 @@ export default Component.extend(UtilsMixin, { return false; }, + @action + handleBlur(event) { + if ( + (!this.isDestroying || !this.isDestroyed) && + event.target && + this.selectKit.mainElement() + ) { + if (!this.selectKit.mainElement().contains(event.target)) { + this.selectKit.close(event); + } + } + return false; + }, + click(event) { event.preventDefault(); event.stopPropagation(); @@ -177,8 +193,6 @@ export default Component.extend(UtilsMixin, { } else if (event.key === "Escape") { this.selectKit.close(event); this.selectKit.headerElement().focus(); - event.preventDefault(); - event.stopPropagation(); } else { if (this.isValidInput(event.key)) { this.selectKit.set("filter", event.key);