<!DOCTYPE html>
<meta name="author" title="Ryosuke Niwa" href="mailto:[email protected]">
<link rel="help" href="https://html.spec.whatwg.org/multipage/dom.html#the-directionality">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
test(() => {
const input = document.createElement('input');
input.type = 'tel';
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'foo');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'rtl');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'RTL');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'ltr');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'LTR');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'auto');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.value = '\u05EA';
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'AUTO');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.removeAttribute('dir');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
}, 'input element whose type attribute is in the telephone state');
test(() => {
const input = document.createElement('input');
input.type = 'tel';
const container = document.createElement('div');
container.setAttribute('dir', 'rtl');
container.appendChild(input);
// Insert the element into the document so that we can also check for
// 'direction' in computed style.
document.body.appendChild(container);
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
// Per https://html.spec.whatwg.org/multipage/rendering.html#bidi-rendering:
assert_equals(getComputedStyle(input).direction, 'ltr');
// Changing to a different type causes the special type=tel rule to no longer apply.
input.type = 'text';
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
assert_equals(getComputedStyle(input).direction, 'rtl');
// And restoring type=tel brings back that behavior.
input.type = 'tel';
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
assert_equals(getComputedStyle(input).direction, 'ltr');
document.body.removeChild(container);
}, 'input element whose type attribute is in the telephone state in a RTL block');
for (const type of ['password', 'text', 'search', 'url', 'email', 'submit', 'reset', 'button', 'hidden']) {
test(() => {
const input = document.createElement('input');
input.type = type;
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'foo');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'rtl');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'RTL');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'ltr');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'LTR');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'auto');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.value = '\u05EA';
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'AUTO');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'))
input.removeAttribute('dir');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
}, `input element whose type attribute is in the ${type} state`);
}
test(() => {
const input = document.createElement('input');
input.type = 'text';
// bidirectional character type R
input.value = '\u05EA';
input.setAttribute('dir', 'auto');
const container = document.createElement('div');
container.appendChild(input);
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
// Changing to a different type that does't use value causes the bidi rule to no longer apply.
input.type = 'radio';
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
// And restoring type=text brings back that behavior.
input.type = 'text';
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
}, 'dynamic changes to type of input elements affect whether value is used for dir=auto');
for (const type of ['date', 'time', 'number', 'range', 'color', 'checkbox', 'radio', 'image']) {
test(() => {
const input = document.createElement('input');
input.type = type;
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'foo');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'rtl');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'RTL');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'ltr');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'LTR');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'auto');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.value = '\u05EA';
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'AUTO');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'))
input.removeAttribute('dir');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
let rtlParent = document.createElement("div");
rtlParent.dir = "rtl";
input.dir = "auto";
rtlParent.appendChild(input);
document.body.appendChild(rtlParent); // Just for good measure.
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
rtlParent.remove();
}, `input element whose type attribute is in the ${type} state`);
}
</script>
</html>