Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blur the previous active element on focus #918

Merged
merged 1 commit into from
Oct 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions addon-test-support/@ember/test-helpers/dom/focus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { nextTickPromise } from '../-utils';
import Target from './-target';
import { log } from '@ember/test-helpers/dom/-logging';
import { runHooks, registerHook } from '../-internal/helper-hooks';
import { __blur__ } from './blur';

registerHook('focus', 'start', (target: Target) => {
log('focus', target);
Expand All @@ -22,6 +23,14 @@ export function __focus__(element: HTMLElement | Element | Document | SVGElement

let browserIsNotFocused = document.hasFocus && !document.hasFocus();

if (
document.activeElement &&
document.activeElement !== element &&
isFocusable(document.activeElement)
) {
__blur__(document.activeElement);
}

// makes `document.activeElement` be `element`. If the browser is focused, it also fires a focus event
element.focus();

Expand Down
53 changes: 47 additions & 6 deletions tests/unit/dom/focus-test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { module, test } from 'qunit';
import { focus, setupContext, teardownContext, _registerHook } from '@ember/test-helpers';
import { buildInstrumentedElement, insertElement } from '../../helpers/events';
import { isIE11 } from '../../helpers/browser-detect';
import { buildInstrumentedElement, insertElement, instrumentElement } from '../../helpers/events';
import { isIE11, isEdge } from '../../helpers/browser-detect';
import hasEmberVersion from '@ember/test-helpers/has-ember-version';

let focusSteps = ['focus', 'focusin'];
let blurSteps = ['blur', 'focusout'];

if (isIE11) {
focusSteps = ['focusin', 'focus'];
blurSteps = ['focusout', 'blur'];
} else if (isEdge) {
blurSteps = ['focusout', 'blur'];
}

module('DOM Helper: focus', function (hooks) {
Expand Down Expand Up @@ -95,6 +99,43 @@ module('DOM Helper: focus', function (hooks) {
assert.verifySteps(focusSteps);
});

test('blurs the previous active element', async function (assert) {
element = buildInstrumentedElement('input', ['target']);

const focusedElement = document.createElement('textarea');
insertElement(focusedElement);
focusedElement.focus();
instrumentElement(focusedElement, ['target']);

await focus(element);

assert.verifySteps([
...blurSteps.map(s => {
return `${s} [object HTMLTextAreaElement]`;
}),
...focusSteps.map(s => {
return `${s} [object HTMLInputElement]`;
}),
]);
});

test('does not attempt to blur the previous element if it is not focusable', async function (assert) {
element = buildInstrumentedElement('input', ['target']);

const focusedElement = document.createElement('div');
insertElement(focusedElement);
focusedElement.focus();
instrumentElement(focusedElement, ['target']);

await focus(element);

assert.verifySteps([
...focusSteps.map(s => {
return `${s} [object HTMLInputElement]`;
}),
]);
});

test('rejects if selector is not found', async function (assert) {
element = buildInstrumentedElement('div');

Expand All @@ -106,7 +147,7 @@ module('DOM Helper: focus', function (hooks) {
);
});

test('focusing a input via selector with context set', async function (assert) {
test('focusing an input via selector with context set', async function (assert) {
element = buildInstrumentedElement('input');

await setupContext(context);
Expand All @@ -116,7 +157,7 @@ module('DOM Helper: focus', function (hooks) {
assert.strictEqual(document.activeElement, element, 'activeElement updated');
});

test('focusing a input via element with context set', async function (assert) {
test('focusing an input via element with context set', async function (assert) {
element = buildInstrumentedElement('input');

await setupContext(context);
Expand All @@ -126,7 +167,7 @@ module('DOM Helper: focus', function (hooks) {
assert.strictEqual(document.activeElement, element, 'activeElement updated');
});

test('focusing a input via element without context set', async function (assert) {
test('focusing an input via element without context set', async function (assert) {
element = buildInstrumentedElement('input');

await focus(element);
Expand All @@ -135,7 +176,7 @@ module('DOM Helper: focus', function (hooks) {
assert.strictEqual(document.activeElement, element, 'activeElement updated');
});

test('focusing a input via selector without context set', async function (assert) {
test('focusing an input via selector without context set', async function (assert) {
element = buildInstrumentedElement('input');

assert.rejects(
Expand Down