Skip to content

Commit

Permalink
Fix jQuery focus/blur/focusin/focusout inconsistencies.
Browse files Browse the repository at this point in the history
  • Loading branch information
rwjblue committed Oct 9, 2017
1 parent 6336351 commit 6e2b27b
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 26 deletions.
64 changes: 51 additions & 13 deletions tests/helpers/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,61 @@ export function matches(el, selector) {
return elMatches.call(el, selector);
}

function isFocusable(el) {
let focusableTags = ['INPUT', 'BUTTON', 'LINK', 'SELECT', 'A', 'TEXTAREA'];
let { tagName, type } = el;

if (type === 'hidden') {
return false;
}

return focusableTags.indexOf(tagName) > -1 || el.contentEditable === 'true';
}

export function focus(el) {
if (!el) {
return;
}
if (matches(el, 'input, textarea, select, button, [contenteditable=true]')) {
let type = el.type;
if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') {
run(function() {
// Firefox does not trigger the `focusin` event if the window
// does not have focus. If the document doesn't have focus just
// use trigger('focusin') instead.

if (!document.hasFocus || document.hasFocus()) {
el.focus();
}
});
}
if (isFocusable(el)) {
run(null, function() {
let browserIsNotFocused = document.hasFocus && !document.hasFocus();

// Firefox does not trigger the `focusin` event if the window
// does not have focus. If the document doesn't have focus just
// use trigger('focusin') instead.
if (browserIsNotFocused) {
fireEvent(el, 'focusin');
}

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

// if the browser is not focused the previous `el.focus()` didn't fire an event, so we simulate it
if (browserIsNotFocused) {
fireEvent(el, 'focus');
}
});
}
}

export function blur(el) {
if (isFocusable(el)) {
run(null, function() {
let browserIsNotFocused = document.hasFocus && !document.hasFocus();

fireEvent(el, 'focusout');

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

// Chrome/Firefox does not trigger the `blur` event if the window
// does not have focus. If the document does not have focus then
// fire `blur` event via native event.
if (browserIsNotFocused) {
fireEvent(el, 'blur');
}
});
}
}

Expand Down
23 changes: 13 additions & 10 deletions tests/unit/test-module-for-component-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import wait from 'ember-test-helpers/wait';
import qunitModuleFor from '../helpers/qunit-module-for';
import hasjQuery from '../helpers/has-jquery';
import hbs from 'htmlbars-inline-precompile';
import { fireEvent } from '../helpers/events';
import { fireEvent, focus, blur } from '../helpers/events';

var Service = EmberService || EmberObject;

Expand Down Expand Up @@ -119,13 +119,6 @@ if (hasjQuery()) {
'this.append() is deprecated. Please use this.render() or this.$() instead.'
);
});

test('$', function(assert) {
this.subject({ name: 'green' });

assert.equal(this.$('.color-name').text(), 'green');
assert.equal(this.$().text(), 'Pretty Color: green');
});
}

test('yields', function(assert) {
Expand Down Expand Up @@ -202,6 +195,15 @@ test('it can access the element', function(assert) {
assert.equal(this._element.textContent, 'Pretty Color: green');
});

if (hasjQuery()) {
test('$', function(assert) {
this.subject({ name: 'green' });

assert.equal(this.$('.color-name').text(), 'green');
assert.equal(this.$().text(), 'Pretty Color: green');
});
}

moduleForComponent(
'pretty-color',
'component:pretty-color -- this.render in setup',
Expand Down Expand Up @@ -507,13 +509,14 @@ test('it supports dom triggered focus events', function(assert) {
}),
});
this.render(hbs`{{my-input}}`);

let input = this._element.querySelector('input');
assert.equal(input.value, 'init');

fireEvent(input, 'focusin');
focus(input);
assert.equal(input.value, 'focusin');

fireEvent(input, 'focusout');
blur(input);
assert.equal(input.value, 'focusout');
});

Expand Down
6 changes: 3 additions & 3 deletions tests/unit/test-module-for-integration-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { TestModuleForIntegration } from 'ember-test-helpers';
import { setResolverRegistry, createCustomResolver } from '../helpers/resolver';
import qunitModuleFor from '../helpers/qunit-module-for';
import hbs from 'htmlbars-inline-precompile';
import { fireEvent } from '../helpers/events';
import { fireEvent, focus, blur } from '../helpers/events';

const Service = EmberService || EmberObject;

Expand Down Expand Up @@ -117,10 +117,10 @@ test('it supports dom triggered focus events', function(assert) {
let input = this._element.querySelector('input');
assert.equal(input.value, 'init');

fireEvent(input, 'focusin');
focus(input);
assert.equal(input.value, 'focusin');

fireEvent(input, 'focusout');
blur(input);
assert.equal(input.value, 'focusout');
});

Expand Down

0 comments on commit 6e2b27b

Please sign in to comment.