Skip to content

Commit

Permalink
Merge pull request #918 from ro0gr/blur-previous-active
Browse files Browse the repository at this point in the history
Blur the previous active element on focus
  • Loading branch information
rwjblue committed Oct 12, 2020
2 parents e599e64 + 98926bc commit 38bdc9f
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 6 deletions.
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

0 comments on commit 38bdc9f

Please sign in to comment.