-
-
Notifications
You must be signed in to change notification settings - Fork 255
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #258 from rwjblue/dom-helpers
Bring over DOM helper implementation.
- Loading branch information
Showing
31 changed files
with
1,921 additions
and
231 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Promise } from 'rsvp'; | ||
|
||
export const nextTick = setTimeout; | ||
|
||
export function nextTickPromise() { | ||
return new Promise(resolve => { | ||
nextTick(resolve); | ||
}); | ||
} |
21 changes: 21 additions & 0 deletions
21
addon-test-support/@ember/test-helpers/dom/-get-element.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { getContext } from '../setup-context'; | ||
|
||
export default function getElement(selectorOrElement) { | ||
if ( | ||
selectorOrElement instanceof Window || | ||
selectorOrElement instanceof Document || | ||
selectorOrElement instanceof Element | ||
) { | ||
return selectorOrElement; | ||
} else if (typeof selectorOrElement === 'string') { | ||
let context = getContext(); | ||
let rootElement = context && context.element; | ||
if (!rootElement) { | ||
throw new Error(`Must setup rendering context before attempting to interact with elements.`); | ||
} | ||
|
||
return rootElement.querySelector(selectorOrElement); | ||
} else { | ||
throw new Error('Must use an element or a selector string'); | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
addon-test-support/@ember/test-helpers/dom/-is-focusable.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import isFormControl from './-is-form-control'; | ||
|
||
const FOCUSABLE_TAGS = ['A']; | ||
export default function isFocusable(element) { | ||
if ( | ||
isFormControl(element) || | ||
element.isContentEditable || | ||
FOCUSABLE_TAGS.indexOf(element.tagName) > -1 | ||
) { | ||
return true; | ||
} | ||
|
||
return element.hasAttribute('tabindex'); | ||
} |
11 changes: 11 additions & 0 deletions
11
addon-test-support/@ember/test-helpers/dom/-is-form-control.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const FORM_CONTROL_TAGS = ['INPUT', 'BUTTON', 'SELECT', 'TEXTAREA']; | ||
|
||
export default function isFormControl(el) { | ||
let { tagName, type } = el; | ||
|
||
if (type === 'hidden') { | ||
return false; | ||
} | ||
|
||
return FORM_CONTROL_TAGS.indexOf(tagName) > -1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import getElement from './-get-element'; | ||
import fireEvent from './fire-event'; | ||
import settled from '../settled'; | ||
import isFocusable from './-is-focusable'; | ||
import { nextTickPromise } from '../-utils'; | ||
|
||
/** | ||
@private | ||
@method __blur__ | ||
@param {Element} element | ||
*/ | ||
export function __blur__(element) { | ||
let browserIsNotFocused = document.hasFocus && !document.hasFocus(); | ||
|
||
// makes `document.activeElement` be `body`. | ||
// If the browser is focused, it also fires a blur event | ||
element.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(element, 'blur', { bubbles: false }); | ||
fireEvent(element, 'focusout'); | ||
} | ||
} | ||
|
||
/** | ||
@method blur | ||
@param {String|Element} [target=document.activeElement] the element to blur | ||
@return {Promise<void>} | ||
@public | ||
*/ | ||
export default function blur(target = document.activeElement) { | ||
return nextTickPromise().then(() => { | ||
let element = getElement(target); | ||
if (!element) { | ||
throw new Error(`Element not found when calling \`blur('${target}')\`.`); | ||
} | ||
|
||
if (!isFocusable(element)) { | ||
throw new Error(`${target} is not focusable`); | ||
} | ||
|
||
__blur__(element); | ||
|
||
return settled(); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import getElement from './-get-element'; | ||
import fireEvent from './fire-event'; | ||
import { __focus__ } from './focus'; | ||
import settled from '../settled'; | ||
import isFocusable from './-is-focusable'; | ||
import { nextTickPromise } from '../-utils'; | ||
|
||
/** | ||
@private | ||
@method __click__ | ||
@param {Element} element | ||
*/ | ||
export function __click__(element) { | ||
fireEvent(element, 'mousedown'); | ||
|
||
if (isFocusable(element)) { | ||
__focus__(element); | ||
} | ||
|
||
fireEvent(element, 'mouseup'); | ||
fireEvent(element, 'click'); | ||
} | ||
|
||
/** | ||
@method click | ||
@param {String|Element} target | ||
@return {Promise<void>} | ||
@public | ||
*/ | ||
export default function click(target) { | ||
return nextTickPromise().then(() => { | ||
if (!target) { | ||
throw new Error('Must pass an element or selector to `click`.'); | ||
} | ||
|
||
let element = getElement(target); | ||
if (!element) { | ||
throw new Error(`Element not found when calling \`click('${target}')\`.`); | ||
} | ||
|
||
__click__(element); | ||
return settled(); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import getElement from './-get-element'; | ||
import isFormControl from './-is-form-control'; | ||
import { __focus__ } from './focus'; | ||
import settled from '../settled'; | ||
import fireEvent from './fire-event'; | ||
import { nextTickPromise } from '../-utils'; | ||
|
||
/* | ||
@method fillIn | ||
@param {String|Element} target | ||
@param {String} text | ||
@return {Promise<void>} | ||
@public | ||
*/ | ||
export default function fillIn(target, text) { | ||
return nextTickPromise().then(() => { | ||
if (!target) { | ||
throw new Error('Must pass an element or selector to `fillIn`.'); | ||
} | ||
|
||
let element = getElement(target); | ||
if (!element) { | ||
throw new Error(`Element not found when calling \`fillIn('${target}')\`.`); | ||
} | ||
|
||
if (!isFormControl(element) && !element.isContentEditable) { | ||
throw new Error('`fillIn` is only usable on form controls or contenteditable elements.'); | ||
} | ||
|
||
if (!text) { | ||
throw new Error('Must provide `text` when calling `fillIn`.'); | ||
} | ||
|
||
__focus__(element); | ||
|
||
if (element.isContentEditable) { | ||
element.innerHTML = text; | ||
} else { | ||
element.value = text; | ||
} | ||
|
||
fireEvent(element, 'input'); | ||
fireEvent(element, 'change'); | ||
|
||
return settled(); | ||
}); | ||
} |
Oops, something went wrong.