/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* import-globals-from ../../mochitest/text.js */
/* import-globals-from ../../mochitest/attributes.js */
loadScripts(
{ name: "text.js", dir: MOCHITESTS_DIR },
{ name: "attributes.js", dir: MOCHITESTS_DIR }
);
const boldAttrs = { "font-weight": "700" };
/*
* Given a text accessible and a list of ranges
* check if those ranges match the misspelled ranges in the accessible.
*/
function misspelledRangesMatch(acc, ranges) {
let offset = 0;
let expectedRanges = [...ranges];
let charCount = acc.characterCount;
while (offset < charCount) {
let start = {};
let end = {};
let attributes = acc.getTextAttributes(false, offset, start, end);
offset = end.value;
try {
if (attributes.getStringProperty("invalid") == "spelling") {
let expected = expectedRanges.shift();
if (
!expected ||
expected[0] != start.value ||
expected[1] != end.value
) {
return false;
}
}
} catch (err) {}
}
return !expectedRanges.length;
}
/*
* Returns a promise that resolves after a text attribute changed event
* brings us to a state where the misspelled ranges match.
*/
async function waitForMisspelledRanges(acc, ranges) {
await waitForEvent(EVENT_TEXT_ATTRIBUTE_CHANGED);
await untilCacheOk(
() => misspelledRangesMatch(acc, ranges),
`Misspelled ranges match: ${JSON.stringify(ranges)}`
);
}
/**
* Test spelling errors.
*/
addAccessibleTask(
`
plain tset bold
`,
async function(browser, docAcc) {
const textarea = findAccessibleChildByID(docAcc, "textarea", [
nsIAccessibleText,
]);
info("Focusing textarea");
let spellingChanged = waitForMisspelledRanges(textarea, [
[5, 9],
[10, 14],
]);
textarea.takeFocus();
await spellingChanged;
// Test removal of a spelling error.
info('textarea: Changing first "tset" to "test"');
// setTextRange fires multiple EVENT_TEXT_ATTRIBUTE_CHANGED, so replace by
// selecting and typing instead.
spellingChanged = waitForMisspelledRanges(textarea, [[10, 14]]);
await invokeContentTask(browser, [], () => {
content.document.getElementById("textarea").setSelectionRange(5, 9);
});
EventUtils.sendString("test");
// Move the cursor to trigger spell check.
EventUtils.synthesizeKey("KEY_ArrowRight");
await spellingChanged;
// Test addition of a spelling error.
info('textarea: Changing it back to "tset"');
spellingChanged = waitForMisspelledRanges(textarea, [
[5, 9],
[10, 14],
]);
await invokeContentTask(browser, [], () => {
content.document.getElementById("textarea").setSelectionRange(5, 9);
});
EventUtils.sendString("tset");
EventUtils.synthesizeKey("KEY_ArrowRight");
await spellingChanged;
// Ensure that changing the text without changing any spelling errors
// correctly updates offsets.
info('textarea: Changing first "test" to "the"');
// Spelling errors don't change, so we won't get
// EVENT_TEXT_ATTRIBUTE_CHANGED. We change the text, wait for the insertion
// and then select a character so we know when the change is done.
let inserted = waitForEvent(EVENT_TEXT_INSERTED, textarea);
await invokeContentTask(browser, [], () => {
content.document.getElementById("textarea").setSelectionRange(0, 4);
});
EventUtils.sendString("the");
await inserted;
let selected = waitForEvent(EVENT_TEXT_SELECTION_CHANGED, textarea);
EventUtils.synthesizeKey("KEY_ArrowRight", { shiftKey: true });
await selected;
const expectedRanges = [
[4, 8],
[9, 13],
];
await untilCacheOk(
() => misspelledRangesMatch(textarea, expectedRanges),
`Misspelled ranges match: ${JSON.stringify(expectedRanges)}`
);
const editable = findAccessibleChildByID(docAcc, "editable", [
nsIAccessibleText,
]);
info("Focusing editable");
spellingChanged = waitForMisspelledRanges(editable, [[6, 10]]);
editable.takeFocus();
await spellingChanged;
// Test normal text and spelling errors crossing text nodes.
testTextAttrs(editable, 0, {}, {}, 0, 6, true); // "plain "
// Ensure we detect the spelling error even though there is a style change
// after it.
testTextAttrs(editable, 6, { invalid: "spelling" }, {}, 6, 10, true); // "tset"
testTextAttrs(editable, 10, {}, {}, 10, 11, true); // " "
// Ensure a style change is still detected in the presence of a spelling
// error.
testTextAttrs(editable, 11, boldAttrs, {}, 11, 15, true); // "bold"
},
{
chrome: true,
topLevel: isCacheEnabled,
iframe: isCacheEnabled,
remoteIframe: isCacheEnabled,
}
);