diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /accessible/tests/mochitest/text | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'accessible/tests/mochitest/text')
17 files changed, 2439 insertions, 0 deletions
diff --git a/accessible/tests/mochitest/text/a11y.toml b/accessible/tests/mochitest/text/a11y.toml new file mode 100644 index 0000000000..740073611b --- /dev/null +++ b/accessible/tests/mochitest/text/a11y.toml @@ -0,0 +1,33 @@ +[DEFAULT] +support-files = [ "doc.html", + "!/accessible/tests/mochitest/*.js"] + +["test_atcaretoffset.html"] + +["test_charboundary.html"] + +["test_doc.html"] + +["test_dynamic.html"] + +["test_general.xhtml"] + +["test_gettext.html"] + +["test_hypertext.html"] + +["test_lineboundary.html"] + +["test_paragraphboundary.html"] + +["test_passwords.html"] + +["test_selection.html"] + +["test_settext_input_event.html"] + +["test_textBounds.html"] + +["test_wordboundary.html"] + +["test_words.html"] diff --git a/accessible/tests/mochitest/text/doc.html b/accessible/tests/mochitest/text/doc.html new file mode 100644 index 0000000000..d57406c226 --- /dev/null +++ b/accessible/tests/mochitest/text/doc.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<head> + <script type="application/javascript"> + document.documentElement.appendChild(document.createTextNode("outbody")); + </script> +</head> +<body>inbody</body> +</html> diff --git a/accessible/tests/mochitest/text/test_atcaretoffset.html b/accessible/tests/mochitest/text/test_atcaretoffset.html new file mode 100644 index 0000000000..33fe7cd793 --- /dev/null +++ b/accessible/tests/mochitest/text/test_atcaretoffset.html @@ -0,0 +1,425 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test: nsIAccessibleText getText* functions at caret offset</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../role.js"></script> + <script type="application/javascript" + src="../states.js"></script> + <script type="application/javascript" + src="../events.js"></script> + <script type="application/javascript" + src="../text.js"></script> + + <script type="application/javascript"> + // gA11yEventDumpToConsole = true; // debugging + + function traverseTextByLines(aQueue, aID, aLines) { + var wholeText = ""; + for (var i = 0; i < aLines.length ; i++) + wholeText += aLines[i][0] + aLines[i][1]; + + var baseInvokerFunc = synthClick; + var charIter = new charIterator(wholeText, aLines); + // charIter.debugOffset = 10; // enable to run tests at given offset only + + while (charIter.next()) { + aQueue.push(new tmpl_moveTo(aID, baseInvokerFunc, wholeText, charIter)); + baseInvokerFunc = synthRightKey; + } + } + + /** + * Used to get test list for each traversed character. + */ + function charIterator(aWholeText, aLines) { + this.next = function charIterator_next() { + // Don't increment offset if we are at end of the wrapped line + // (offset is shared between end of this line and start of next line). + if (this.mAtWrappedLineEnd) { + this.mAtWrappedLineEnd = false; + this.mLine = this.mLine.nextLine; + return true; + } + + this.mOffset++; + if (this.mOffset > aWholeText.length) + return false; + + var nextLine = this.mLine.nextLine; + if (!nextLine.isFakeLine() && this.mOffset == nextLine.start) { + if (nextLine.start == this.mLine.end) + this.mAtWrappedLineEnd = true; + else + this.mLine = nextLine; + } + + return true; + }; + + Object.defineProperty(this, "offset", { get() { return this.mOffset; }, + }); + + Object.defineProperty(this, "offsetDescr", { get() { + return this.mOffset + " offset (" + this.mLine.number + " line, " + + (this.mOffset - this.mLine.start) + " offset on the line)"; + }, + }); + + Object.defineProperty(this, "tests", { get() { + // Line boundary tests. + var cLine = this.mLine; + var pLine = cLine.prevLine; + var ppLine = pLine.prevLine; + var nLine = cLine.nextLine; + var nnLine = nLine.nextLine; + + var lineTests = [ + [ testTextBeforeOffset, BOUNDARY_LINE_START, pLine.start, cLine.start], + [ testTextBeforeOffset, BOUNDARY_LINE_END, ppLine.end, pLine.end], + [ testTextAtOffset, BOUNDARY_LINE_START, cLine.start, nLine.start], + [ testTextAtOffset, BOUNDARY_LINE_END, pLine.end, cLine.end], + [ testTextAfterOffset, BOUNDARY_LINE_START, nLine.start, nnLine.start], + [ testTextAfterOffset, BOUNDARY_LINE_END, cLine.end, nLine.end], + ]; + + // Word boundary tests. + var cWord = this.mLine.firstWord; + var nWord = cWord.nextWord, pWord = cWord.prevWord; + + // The current word is a farthest word starting at or after the offset. + if (this.mOffset >= nWord.start) { + while (this.mOffset >= nWord.start && !this.mLine.isLastWord(cWord)) { + cWord = nWord; + nWord = nWord.nextWord; + } + pWord = cWord.prevWord; + } else if (this.mOffset < cWord.start) { + while (this.mOffset < cWord.start) { + cWord = pWord; + pWord = pWord.prevWord; + } + nWord = cWord.nextWord; + } + + var nnWord = nWord.nextWord, ppWord = pWord.prevWord; + + var isAfterWordEnd = + this.mOffset > cWord.end || cWord.line != this.mLine; + var isAtOrAfterWordEnd = (this.mOffset >= cWord.end); + var useNextWordForAtWordEnd = + isAtOrAfterWordEnd && this.mOffset != aWholeText.length; + + var wordTests = [ + [ testTextBeforeOffset, BOUNDARY_WORD_START, + pWord.start, cWord.start ], + [ testTextBeforeOffset, BOUNDARY_WORD_END, + (isAfterWordEnd ? pWord : ppWord).end, + (isAfterWordEnd ? cWord : pWord).end ], + [ testTextAtOffset, BOUNDARY_WORD_START, + cWord.start, nWord.start ], + [ testTextAtOffset, BOUNDARY_WORD_END, + (useNextWordForAtWordEnd ? cWord : pWord).end, + (useNextWordForAtWordEnd ? nWord : cWord).end ], + [ testTextAfterOffset, BOUNDARY_WORD_START, + nWord.start, nnWord.start ], + [ testTextAfterOffset, BOUNDARY_WORD_END, + (isAfterWordEnd ? nWord : cWord).end, + (isAfterWordEnd ? nnWord : nWord).end ], + ]; + + // Character boundary tests. + var prevOffset = this.offset > 1 ? this.offset - 1 : 0; + var nextOffset = this.offset >= aWholeText.length ? + this.offset : this.offset + 1; + var nextAfterNextOffset = nextOffset >= aWholeText.length ? + nextOffset : nextOffset + 1; + + var charTests = [ + [ testTextBeforeOffset, BOUNDARY_CHAR, + prevOffset, this.offset ], + [ testTextAtOffset, BOUNDARY_CHAR, + this.offset, + this.mAtWrappedLineEnd ? this.offset : nextOffset ], + [ testTextAfterOffset, BOUNDARY_CHAR, + this.mAtWrappedLineEnd ? this.offset : nextOffset, + this.mAtWrappedLineEnd ? nextOffset : nextAfterNextOffset ], + ]; + + return lineTests.concat(wordTests.concat(charTests)); + }, + }); + + Object.defineProperty(this, "failures", { get() { + if (this.mOffset == this.mLine.start) + return this.mLine.lineStartFailures; + if (this.mOffset == this.mLine.end) + return this.mLine.lineEndFailures; + return []; + }, + }); + + this.mOffset = -1; + this.mLine = new line(aWholeText, aLines, 0); + this.mAtWrappedLineEnd = false; + this.mWord = this.mLine.firstWord; + } + + /** + * A line object. Allows to navigate by lines and by words. + */ + function line(aWholeText, aLines, aIndex) { + Object.defineProperty(this, "prevLine", { get() { + return new line(aWholeText, aLines, aIndex - 1); + }, + }); + Object.defineProperty(this, "nextLine", { get() { + return new line(aWholeText, aLines, aIndex + 1); + }, + }); + + Object.defineProperty(this, "start", { get() { + if (aIndex < 0) + return 0; + + if (aIndex >= aLines.length) + return aWholeText.length; + + return aLines[aIndex][2]; + }, + }); + Object.defineProperty(this, "end", { get() { + if (aIndex < 0) + return 0; + + if (aIndex >= aLines.length) + return aWholeText.length; + + return aLines[aIndex][3]; + }, + }); + + Object.defineProperty(this, "number", { get() { return aIndex; }, + }); + Object.defineProperty(this, "wholeText", { get() { return aWholeText; }, + }); + this.isFakeLine = function line_isFakeLine() { + return aIndex < 0 || aIndex >= aLines.length; + }; + + Object.defineProperty(this, "lastWord", { get() { + if (aIndex < 0) + return new word(this, [], -1); + if (aIndex >= aLines.length) + return new word(this, [], 0); + + var words = aLines[aIndex][4].words; + return new word(this, words, words.length - 2); + }, + }); + Object.defineProperty(this, "firstWord", { get() { + if (aIndex < 0) + return new word(this, [], -1); + if (aIndex >= aLines.length) + return new word(this, [], 0); + + var words = aLines[aIndex][4].words; + return new word(this, words, 0); + }, + }); + + this.isLastWord = function line_isLastWord(aWord) { + var lastWord = this.lastWord; + return lastWord.start == aWord.start && lastWord.end == aWord.end; + }; + + Object.defineProperty(this, "lineStartFailures", { get() { + if (aIndex < 0 || aIndex >= aLines.length) + return []; + + return aLines[aIndex][4].lsf || []; + }, + }); + Object.defineProperty(this, "lineEndFailures", { get() { + if (aIndex < 0 || aIndex >= aLines.length) + return []; + + return aLines[aIndex][4].lef || []; + }, + }); + } + + /** + * A word object. Allows to navigate by words. + */ + function word(aLine, aWords, aIndex) { + Object.defineProperty(this, "prevWord", { get() { + if (aIndex >= 2) + return new word(aLine, aWords, aIndex - 2); + + var prevLineLastWord = aLine.prevLine.lastWord; + if (this.start == prevLineLastWord.start && !this.isFakeStartWord()) + return prevLineLastWord.prevWord; + return prevLineLastWord; + }, + }); + Object.defineProperty(this, "nextWord", { get() { + if (aIndex + 2 < aWords.length) + return new word(aLine, aWords, aIndex + 2); + + var nextLineFirstWord = aLine.nextLine.firstWord; + if (this.end == nextLineFirstWord.end && !this.isFakeEndWord()) + return nextLineFirstWord.nextWord; + return nextLineFirstWord; + }, + }); + + Object.defineProperty(this, "line", { get() { return aLine; } }); + + Object.defineProperty(this, "start", { get() { + if (this.isFakeStartWord()) + return 0; + + if (this.isFakeEndWord()) + return aLine.end; + return aWords[aIndex]; + }, + }); + Object.defineProperty(this, "end", { get() { + if (this.isFakeStartWord()) + return 0; + + return this.isFakeEndWord() ? aLine.end : aWords[aIndex + 1]; + }, + }); + + this.toString = function word_toString() { + var start = this.start, end = this.end; + return "'" + aLine.wholeText.substring(start, end) + + "' at [" + start + ", " + end + "]"; + }; + + this.isFakeStartWord = function() { return aIndex < 0; }; + this.isFakeEndWord = function() { return aIndex >= aWords.length; }; + } + + /** + * A template invoker to move through the text. + */ + function tmpl_moveTo(aID, aInvokerFunc, aWholeText, aCharIter) { + this.offset = aCharIter.offset; + + var checker = new caretMoveChecker(this.offset, true, aID); + this.__proto__ = new (aInvokerFunc)(aID, checker); + + this.finalCheck = function genericMoveTo_finalCheck() { + if (this.noTests()) + return; + + for (var i = 0; i < this.tests.length; i++) { + var func = this.tests[i][0]; + var boundary = this.tests[i][1]; + var startOffset = this.tests[i][2]; + var endOffset = this.tests[i][3]; + var text = aWholeText.substring(startOffset, endOffset); + + var isOk1 = kOk, isOk2 = kOk, isOk3 = kOk; + for (var fIdx = 0; fIdx < this.failures.length; fIdx++) { + var failure = this.failures[fIdx]; + if (func.name.includes(failure[0]) && boundary == failure[1]) { + isOk1 = failure[2]; + isOk2 = failure[3]; + isOk3 = failure[4]; + } + } + + func(kCaretOffset, boundary, text, startOffset, endOffset, + aID, isOk1, isOk2, isOk3); + } + }; + + this.getID = function genericMoveTo_getID() { + return "move to " + this.offsetDescr; + }; + + this.noTests = function tmpl_moveTo_noTests() { + return ("debugOffset" in aCharIter) && + (aCharIter.debugOffset != this.offset); + }; + + this.offsetDescr = aCharIter.offsetDescr; + this.tests = this.noTests() ? null : aCharIter.tests; + this.failures = aCharIter.failures; + } + + var gQueue = null; + function doTest() { + gQueue = new eventQueue(); + + // __a__w__o__r__d__\n + // 0 1 2 3 4 5 + // __t__w__o__ (soft line break) + // 6 7 8 9 + // __w__o__r__d__s + // 10 11 12 13 14 15 + + traverseTextByLines(gQueue, "textarea", + [ [ "aword", "\n", 0, 5, { words: [ 0, 5 ] } ], + [ "two ", "", 6, 10, { words: [ 6, 9 ] } ], + [ "words", "", 10, 15, { words: [ 10, 15 ] } ], + ] ); + + var line4 = [ // "riend " + [ "TextBeforeOffset", BOUNDARY_WORD_END, + kOk, kOk, kOk], + [ "TextAfterOffset", BOUNDARY_WORD_END, + kOk, kOk, kOk ], + ]; + traverseTextByLines(gQueue, "ta_wrapped", + [ [ "hi ", "", 0, 3, { words: [ 0, 2 ] } ], + [ "hello ", "", 3, 9, { words: [ 3, 8 ] } ], + [ "my ", "", 9, 12, { words: [ 9, 11 ] } ], + [ "longf", "", 12, 17, { words: [ 12, 17 ] } ], + [ "riend ", "", 17, 23, { words: [ 17, 22 ], lsf: line4 } ], + [ "t sq ", "", 23, 28, { words: [ 23, 24, 25, 27 ] } ], + [ "t", "", 28, 29, { words: [ 28, 29 ] } ], + ] ); + + gQueue.invoke(); // will call SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <a target="_blank" + title="nsIAccessibleText getText related functions tests at caret offset" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=852021"> + Bug 852021 + </a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + + <textarea id="textarea" cols="5">aword +two words</textarea> + + <!-- scrollbar-width: none is needed so that the width of the scrollbar + doesn't incorrectly affect the width of the textarea on some systems. + See bug 1600170 and bug 33654. + --> + <textarea id="ta_wrapped" cols="5" style="scrollbar-width: none;">hi hello my longfriend t sq t</textarea> + </pre> +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_charboundary.html b/accessible/tests/mochitest/text/test_charboundary.html new file mode 100644 index 0000000000..5ca4120a47 --- /dev/null +++ b/accessible/tests/mochitest/text/test_charboundary.html @@ -0,0 +1,138 @@ +<!DOCTYPE html> +<html> +<head> + <title>Char boundary text tests</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../text.js"></script> + + <script type="application/javascript"> + function doTest() { + // //////////////////////////////////////////////////////////////////////// + // + // __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + + var IDs = [ "i1", "d1", "e1", "t1" ]; + + testCharBeforeOffset(IDs, 0, "", 0, 0); + testCharBeforeOffset(IDs, 1, "h", 0, 1); + testCharBeforeOffset(IDs, 14, "n", 13, 14); + testCharBeforeOffset(IDs, 15, "d", 14, 15); + + testCharAtOffset(IDs, 0, "h", 0, 1); + testCharAtOffset(IDs, 1, "e", 1, 2); + testCharAtOffset(IDs, 14, "d", 14, 15); + testCharAtOffset(IDs, 15, "", 15, 15); + + testCharAfterOffset(IDs, 0, "e", 1, 2); + testCharAfterOffset(IDs, 1, "l", 2, 3); + testCharAfterOffset(IDs, 14, "", 15, 15); + testCharAfterOffset(IDs, 15, "", 15, 15); + + // //////////////////////////////////////////////////////////////////////// + // + // __B__r__a__v__e__ __S__i__r__ __ __R__o__b__i__n__ __ __ __r__a__n + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + + IDs = [ "i2", "d2", "e2", "t2" ]; + + testCharBeforeOffset(IDs, 0, "", 0, 0); + testCharBeforeOffset(IDs, 1, "B", 0, 1); + testCharBeforeOffset(IDs, 6, " ", 5, 6); + testCharBeforeOffset(IDs, 10, " ", 9, 10); + testCharBeforeOffset(IDs, 11, " ", 10, 11); + testCharBeforeOffset(IDs, 17, " ", 16, 17); + testCharBeforeOffset(IDs, 19, " ", 18, 19); + + testCharAtOffset(IDs, 0, "B", 0, 1); + testCharAtOffset(IDs, 1, "r", 1, 2); + testCharAtOffset(IDs, 5, " ", 5, 6); + testCharAtOffset(IDs, 9, " ", 9, 10); + testCharAtOffset(IDs, 10, " ", 10, 11); + testCharAtOffset(IDs, 17, " ", 17, 18); + + testCharAfterOffset(IDs, 0, "r", 1, 2); + testCharAfterOffset(IDs, 1, "a", 2, 3); + testCharAfterOffset(IDs, 4, " ", 5, 6); + testCharAfterOffset(IDs, 5, "S", 6, 7); + testCharAfterOffset(IDs, 8, " ", 9, 10); + testCharAfterOffset(IDs, 9, " ", 10, 11); + testCharAfterOffset(IDs, 10, "R", 11, 12); + testCharAfterOffset(IDs, 15, " ", 16, 17); + testCharAfterOffset(IDs, 16, " ", 17, 18); + testCharAfterOffset(IDs, 17, " ", 18, 19); + testCharAfterOffset(IDs, 18, "r", 19, 20); + + // //////////////////////////////////////////////////////////////////////// + // + // __o__n__e__w__o__r__d__\n + // 0 1 2 3 4 5 6 7 + // __\n + // 8 + // __t__w__o__ __w__o__r__d__s__\n + // 9 10 11 12 13 14 15 16 17 18 + + IDs = ["d3", "dbr3", "e3", "ebr3", "t3"]; + + testCharBeforeOffset(IDs, 8, "\n", 7, 8); + testCharBeforeOffset(IDs, 9, "\n", 8, 9); + testCharBeforeOffset(IDs, 10, "t", 9, 10); + + testCharAtOffset(IDs, 7, "\n", 7, 8); + testCharAtOffset(IDs, 8, "\n", 8, 9); + testCharAtOffset(IDs, 9, "t", 9, 10); + + testCharAfterOffset(IDs, 6, "\n", 7, 8); + testCharAfterOffset(IDs, 7, "\n", 8, 9); + testCharAfterOffset(IDs, 8, "t", 9, 10); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <input id="i1" value="hello my friend"/> + <div id="d1">hello my friend</div> + <div id="e1" contenteditable="true">hello my friend</div> + <textarea id="t1" contenteditable="true">hello my friend</textarea> + + <input id="i2" value="Brave Sir Robin ran"/> + <pre> + <div id="d2">Brave Sir Robin ran</div> + <div id="e2" contenteditable="true">Brave Sir Robin ran</div> + </pre> + <textarea id="t2" cols="300">Brave Sir Robin ran</textarea> + + <pre> + <div id="d3">oneword + +two words +</div> + <div id="dbr3">oneword<br/><br/>two words<br/></div> + <div id="e3" contenteditable="true">oneword + +two words +</div> + <div id="ebr3" contenteditable="true">oneword<br/><br/>two words<br/></div> + <textarea id="t3" cols="300">oneword + +two words</textarea> + </pre> + +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_doc.html b/accessible/tests/mochitest/text/test_doc.html new file mode 100644 index 0000000000..88b75b98c4 --- /dev/null +++ b/accessible/tests/mochitest/text/test_doc.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html> +<head> + <title>nsIAccessibleText getText related function tests for document accessible</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../text.js"></script> + <script type="application/javascript"> + + function doTest() { + var iframeDoc = [ getNode("iframe").contentDocument ]; + testCharacterCount(iframeDoc, 15); + testText(iframeDoc, 0, 15, "outbody inbody "); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <a target="_blank" + title="Elements appended outside the body aren't accessible" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=608887">Mozilla Bug 608887</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <iframe id="iframe" src="doc.html"></iframe> + +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_dynamic.html b/accessible/tests/mochitest/text/test_dynamic.html new file mode 100644 index 0000000000..63889fc664 --- /dev/null +++ b/accessible/tests/mochitest/text/test_dynamic.html @@ -0,0 +1,80 @@ +<!DOCTYPE html> +<html> +<head> + <title>nsIAccessibleText getText related function tests for tree mutations</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../text.js"></script> + <script type="application/javascript" + src="../events.js"></script> + + <script type="application/javascript"> + function insertBefore(aId, aEl, aTextBefore, aTextAfter, aStartIdx, aEndIdx) { + this.eventSeq = [ + new invokerChecker(EVENT_REORDER, aId), + ]; + + this.invoke = function insertBefore_invoke() { + testText(aId, 0, -1, aTextBefore); + getNode(aId).insertBefore(aEl, getNode(aId).firstChild); + }; + + this.finalCheck = function insertBefore_finalCheck() { + testText(aId, aStartIdx, aEndIdx, aTextAfter); + }; + + this.getID = function insertTextBefore_getID() { + return "insert " + prettyName(aEl) + " before"; + }; + } + + function insertTextBefore(aId, aTextBefore, aText) { + var el = document.createTextNode(aText); + this.__proto__ = new insertBefore(aId, el, aTextBefore, + aText + aTextBefore, 0, -1); + } + + function insertImgBefore(aId, aTextBefore) { + var el = document.createElement("img"); + el.setAttribute("src", "../moz.png"); + el.setAttribute("alt", "mozilla"); + + this.__proto__ = new insertBefore(aId, el, aTextBefore, + kEmbedChar + aTextBefore, 0, -1); + } + + function insertTextBefore2(aId) { + var el = document.createTextNode("hehe"); + this.__proto__ = new insertBefore(aId, el, "ho", "ho", 4, -1); + } + + var gQueue = null; + function doTest() { + gQueue = new eventQueue(); + gQueue.push(new insertTextBefore("c1", "ho", "ha")); + gQueue.push(new insertImgBefore("c1", "haho")); + gQueue.push(new insertImgBefore("c2", kEmbedChar)); + gQueue.push(new insertTextBefore2("c3")); + gQueue.invoke(); // will call SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <div id="c1">ho</div> + <div id="c2"><img src="../moz.png" alt="mozilla"></div> + <div id="c3">ho</div> +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_general.xhtml b/accessible/tests/mochitest/text/test_general.xhtml new file mode 100644 index 0000000000..df0ffcc0c6 --- /dev/null +++ b/accessible/tests/mochitest/text/test_general.xhtml @@ -0,0 +1,79 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" + type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:html="http://www.w3.org/1999/xhtml" + title="Tests: XUL label text interface"> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" /> + <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../role.js"></script> + <script type="application/javascript" + src="../text.js"></script> + + <script type="application/javascript"> + <![CDATA[ + //////////////////////////////////////////////////////////////////////////// + // Testing + + var gQueue = null; + function doTests() + { + ////////////////////////////////////////////////////////////////////////// + // XUL label + + var ids = ["label1", "label2"]; + + testCharacterCount(ids, 5); + + testText(ids, 0, -1, "Hello"); + testText(ids, 0, 1, "H"); + + testCharAfterOffset(ids, 0, "e", 1, 2); + testCharBeforeOffset(ids, 1, "H", 0, 1); + testCharAtOffset(ids, 1, "e", 1, 2); + + ////////////////////////////////////////////////////////////////////////// + // HTML input + + testTextAtOffset([ getNode("tbox1") ], BOUNDARY_LINE_START, + [ [ 0, 4, "test", 0, 4 ] ]); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTests); + ]]> + </script> + + <vbox flex="1" style="overflow: auto;"> + <body xmlns="http://www.w3.org/1999/xhtml"> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=396166" + title="xul:label@value accessible should implement nsIAccessibleText"> + Bug 396166 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=899433" + title="Accessibility returns empty line for last line in certain cases"> + Bug 899433 + </a> + <p id="display"></p> + <div id="content" style="display: none"> + </div> + <pre id="test"> + </pre> + </body> + <label id="label1" value="Hello"/> + <label id="label2">Hello</label> + + <html:input id="tbox1" value="test"/> + </vbox> +</window> diff --git a/accessible/tests/mochitest/text/test_gettext.html b/accessible/tests/mochitest/text/test_gettext.html new file mode 100644 index 0000000000..2f221a416b --- /dev/null +++ b/accessible/tests/mochitest/text/test_gettext.html @@ -0,0 +1,135 @@ +<!DOCTYPE html> +<html> +<head> + <title>Get text between offsets tests</title> + <meta charset="utf-8"> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../text.js"></script> + + <script type="application/javascript"> + function doTest() { + // //////////////////////////////////////////////////////////////////////// + // + // __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + + var IDs = [ "i1", "d1", "d1wrap", "e1", "t1" ]; + + testCharacterCount(IDs, 15); + + testText(IDs, 0, 1, "h"); + testText(IDs, 1, 3, "el"); + testText(IDs, 14, 15, "d"); + testText(IDs, 0, 15, "hello my friend"); + testText(IDs, 0, -1, "hello my friend"); + + // //////////////////////////////////////////////////////////////////////// + // + // __B__r__a__v__e__ __S__i__r__ __ __R__o__b__i__n__ __ __ __r__a__n + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + + IDs = [ "i2", "dpre2", "epre2", "t2" ]; + + testCharacterCount(IDs, 22); + + testText(IDs, 0, 1, "B"); + testText(IDs, 5, 6, " "); + testText(IDs, 9, 11, " "); + testText(IDs, 16, 19, " "); + testText(IDs, 0, 22, "Brave Sir Robin ran"); + testText(IDs, 0, -1, "Brave Sir Robin ran"); + + testCharacterCount(["d2", "e2"], 19); + testText(["d2", "e2"], 0, 19, "Brave Sir Robin ran"); + + // //////////////////////////////////////////////////////////////////////// + // + // __o__n__e__w__o__r__d__\n + // 0 1 2 3 4 5 6 7 + // __\n + // 8 + // __t__w__o__ __w__o__r__d__s__\n + // 9 10 11 12 13 14 15 16 17 18 + + IDs = ["d3", "dbr3", "e3", "ebr3", "t3"]; + + testCharacterCount(IDs, 19); + + testText(IDs, 0, 19, "oneword\n\ntwo words\n"); + testText(IDs, 0, -1, "oneword\n\ntwo words\n"); + + // //////////////////////////////////////////////////////////////////////// + // + // CSS text-transform + // + // Content with `text-transform:uppercase | lowercase | capitalize` returns + // the transformed content. + // + testText(["d4a"], 0, -1, "HELLO MY FRIEND"); + testText(["d4b"], 0, -1, "hello my friend"); + testText(["d4c"], 0, -1, "Hello My Friend"); + + // `text-transform: full-width | full-size-kana` should not be reflected in + // a11y. + testText(["d5a"], 0, -1, "hello my friend"); + testText(["d5b"], 0, -1, "ゕゖヵヶ"); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <input id="i1" value="hello my friend"/> + <div id="d1">hello my friend</div> + <div id="d1wrap" style="word-wrap:break-word; width:1px">hello my friend</div> + <div id="e1" contenteditable="true">hello my friend</div> + <textarea id="t1">hello my friend</textarea> + + <input id="i2" value="Brave Sir Robin ran"/> + <pre><div id="dpre2">Brave Sir Robin ran</div></pre> + <pre><div id="epre2" contenteditable="true">Brave Sir Robin ran</div></pre> + <textarea id="t2" cols="300">Brave Sir Robin ran</textarea> + <div id="d2">Brave Sir Robin ran</div> + <div id="e2" contenteditable="true">Brave Sir Robin ran</div> + + <pre> + <div id="d3">oneword + +two words +</div> + <div id="dbr3">oneword<br/><br/>two words<br/></div> + <div id="e3" contenteditable="true">oneword + +two words +</div> + <div id="ebr3" contenteditable="true">oneword<br/><br/>two words<br/></div> + <textarea id="t3" cols="300">oneword + +two words +</textarea> + </pre> + + <div id="d4a" style="text-transform:uppercase">Hello My Friend</div> + <div id="d4b" style="text-transform:lowercase">Hello My Friend</div> + <div id="d4c" style="text-transform:capitalize">hello my friend</div> + + <div id="d5a" style="text-transform:full-width">hello my friend</div> + <div id="d5b" style="text-transform:full-size-kana">ゕゖヵヶ</div> + +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_hypertext.html b/accessible/tests/mochitest/text/test_hypertext.html new file mode 100644 index 0000000000..b8a289ea52 --- /dev/null +++ b/accessible/tests/mochitest/text/test_hypertext.html @@ -0,0 +1,150 @@ +<!DOCTYPE html> +<html> +<head> + <title>nsIAccessibleText getText related function tests for rich text</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <style> + #listitemnone { + list-style-type: none; + } + h6.gencontent:before { + content: "aga" + } + </style> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../text.js"></script> + + <script type="application/javascript"> + function doTest() { + // //////////////////////////////////////////////////////////////////////// + // null getText + // //////////////////////////////////////////////////////////////////////// + + var emptyTextAcc = getAccessible("nulltext", [nsIAccessibleText]); + is(emptyTextAcc.getText(0, -1), "", "getText() END_OF_TEXT with null string"); + is(emptyTextAcc.getText(0, 0), "", "getText() Len==0 with null string"); + + // //////////////////////////////////////////////////////////////////////// + // hypertext + // //////////////////////////////////////////////////////////////////////// + + // ! - embedded object char + // __h__e__l__l__o__ __!__ __s__e__e__ __!__ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + + var IDs = [ "hypertext", "hypertext2", "ht_displaycontents" ]; + + // ////////////////////////////////////////////////////////////////////// + // characterCount + + testCharacterCount(IDs, 13); + + // ////////////////////////////////////////////////////////////////////// + // getText + + testText(IDs, 0, 1, "h"); + testText(IDs, 5, 7, " " + kEmbedChar); + testText(IDs, 10, 13, "e " + kEmbedChar); + testText(IDs, 0, 13, "hello " + kEmbedChar + " see " + kEmbedChar); + + // ////////////////////////////////////////////////////////////////////// + // getTextAtOffset line boundary + + testTextAtOffset(0, BOUNDARY_LINE_START, "line ", 0, 5, + "hypertext3", kOk, kOk, kOk); + + // XXX: see bug 634202. + testTextAtOffset(0, BOUNDARY_LINE_START, "line ", 0, 5, + "hypertext4", kOk, kOk, kOk); + + // //////////////////////////////////////////////////////////////////////// + // list + // //////////////////////////////////////////////////////////////////////// + + IDs = [ "list" ]; + testCharacterCount(IDs, 2); + testText(IDs, 0, 2, kEmbedChar + kEmbedChar); + + IDs = [ "listitem" ]; + testCharacterCount(IDs, 6); + testText(IDs, 0, 6, "1. foo"); + + IDs = [ "listitemnone" ]; + testCharacterCount(IDs, 3); + testText(IDs, 0, 3, "bar"); + + testText(["testbr"], 0, 3, "foo"); + + testTextAtOffset(2, nsIAccessibleText.BOUNDARY_CHAR, "o", 2, 3, "testbr", + kOk, kOk, kOk); + testTextAtOffset(2, nsIAccessibleText.BOUNDARY_WORD_START, "foo\n", 0, 4, + "testbr", kOk, kOk, kOk); + testTextBeforeOffset(2, nsIAccessibleText.BOUNDARY_LINE_START, "foo\n", + 0, 4, "testbr", kTodo, kOk, kTodo); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <a target="_blank" + title="Fix getText" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=630001"> + Bug 630001, part3 + </a> + <a target="_blank" + title="getTextAtOffset line boundary may return more than one line" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=638326"> + Bug 638326 + </a> + <a target="_blank" + title="getText(0, -1) fails with empty text" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=749810"> + Bug 749810 + </a> + + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <div id="nulltext"></div> + + <div id="hypertext">hello <a>friend</a> see <img src="about:blank"></div> + <div id="hypertext2">hello <a>friend</a> see <input></div> + <div id="ht_displaycontents">hello <a>friend</a> see <ul id="ul" style="display: contents;"> + <li>Supermarket 1</li> + <li>Supermarket 2</li> + </ul></div> + <ol id="list"> + <li id="listitem">foo</li> + <li id="listitemnone">bar</li> + </ol> + + <div id="hypertext3">line +<!-- haha --> +<!-- hahaha --> +<h6>heading</h6> + </div> + + <div id="hypertext4">line +<!-- haha --> +<!-- hahaha --> +<h6 role="presentation" class="gencontent">heading</h6> + </div> + + <div id="testbr">foo<br/></div> + + <div></div> +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_lineboundary.html b/accessible/tests/mochitest/text/test_lineboundary.html new file mode 100644 index 0000000000..77b35ece5d --- /dev/null +++ b/accessible/tests/mochitest/text/test_lineboundary.html @@ -0,0 +1,422 @@ +<!DOCTYPE html> +<html> +<head> + <title>Line boundary getText* functions tests</title> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../text.js"></script> + <script type="application/javascript"> + function doTest() { + testTextAtOffset("line_test_1", BOUNDARY_LINE_START, + [[0, 6, "Line 1 ", 0, 7], + // See the kOk test below. + // [7, 7, kEmbedChar, 7, 8], + [8, 15, "Line 3 ", 8, 15]]); + testTextAtOffset(/* aOffset */ 7, BOUNDARY_LINE_START, + kEmbedChar, /* aStartOffset */ 7, /* aEndOffset */ 8, + "line_test_1", + /* returned text */ kOk, + /* returned start offset */ kOk, /* returned end offset */ kOk); + + // //////////////////////////////////////////////////////////////////////// + // __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + + var IDs = [ "input", "div", "editable", "textarea", + getNode("ta", getNode("ta_cntr").contentDocument) ]; + + testTextBeforeOffset(IDs, BOUNDARY_LINE_START, + [ [ 0, 15, "", 0, 0 ] ]); + testTextBeforeOffset(IDs, BOUNDARY_LINE_END, + [ [ 0, 15, "", 0, 0 ] ]); + + testTextAtOffset(IDs, BOUNDARY_LINE_START, + [ [ 0, 15, "hello my friend", 0, 15 ] ]); + testTextAtOffset(IDs, BOUNDARY_LINE_END, + [ [ 0, 15, "hello my friend", 0, 15 ] ]); + + testTextAfterOffset(IDs, BOUNDARY_LINE_START, + [ [ 0, 15, "", 15, 15 ] ]); + testTextAfterOffset(IDs, BOUNDARY_LINE_END, + [ [ 0, 15, "", 15, 15 ] ]); + + // //////////////////////////////////////////////////////////////////////// + // __o__n__e__w__o__r__d__\n + // 0 1 2 3 4 5 6 7 + // __\n + // 8 + // __t__w__o__ __w__o__r__d__s__\n + // 9 10 11 12 13 14 15 16 17 18 + + IDs = [ "ml_div", "ml_divbr", "ml_editable", "ml_editablebr", "ml_textarea"]; + + testTextBeforeOffset(IDs, BOUNDARY_LINE_START, + [ [ 0, 7, "", 0, 0 ], + [ 8, 8, "oneword\n", 0, 8 ], + [ 9, 18, "\n", 8, 9 ], + [ 19, 19, "two words\n", 9, 19 ]]); + + testTextBeforeOffset(IDs, BOUNDARY_LINE_END, + [ [ 0, 7, "", 0, 0 ], + [ 8, 8, "oneword", 0, 7 ], + [ 9, 18, "\n", 7, 8 ], + [ 19, 19, "\ntwo words", 8, 18 ]]); + + testTextAtOffset(IDs, BOUNDARY_LINE_START, + [ [ 0, 7, "oneword\n", 0, 8 ], + [ 8, 8, "\n", 8, 9 ], + [ 9, 18, "two words\n", 9, 19 ], + [ 19, 19, "", 19, 19 ]]); + testTextAtOffset(IDs, BOUNDARY_LINE_END, + [ [ 0, 7, "oneword", 0, 7 ], + [ 8, 8, "\n", 7, 8 ], + [ 9, 18, "\ntwo words", 8, 18 ], + [ 19, 19, "\n", 18, 19 ]]); + + testTextAfterOffset(IDs, BOUNDARY_LINE_START, + [ [ 0, 7, "\n", 8, 9 ], + [ 8, 8, "two words\n", 9, 19 ], + [ 9, 19, "", 19, 19 ]]); + testTextAfterOffset(IDs, BOUNDARY_LINE_END, + [ [ 0, 7, "\n", 7, 8 ], + [ 8, 8, "\ntwo words", 8, 18 ], + [ 9, 18, "\n", 18, 19 ], + [ 19, 19, "", 19, 19 ]]); + + // //////////////////////////////////////////////////////////////////////// + // a * b (* is embedded char for link) + testTextBeforeOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_START, + [ [ 0, 5, "", 0, 0 ] ]); + + testTextBeforeOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_END, + [ [ 0, 5, "", 0, 0 ] ]); + + testTextAtOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_START, + [ [ 0, 5, "a " + kEmbedChar + " c", 0, 5 ] ]); + + testTextAtOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_END, + [ [ 0, 5, "a " + kEmbedChar + " c", 0, 5 ] ]); + + testTextAfterOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_START, + [ [ 0, 5, "", 5, 5 ] ]); + + testTextAfterOffset([ getAccessible("ht_1").firstChild ], BOUNDARY_LINE_END, + [ [ 0, 5, "", 5, 5 ] ]); + + // //////////////////////////////////////////////////////////////////////// + // foo<br> and foo<br><br> + + testTextAtOffset([ getAccessible("ht_2").firstChild.firstChild ], + BOUNDARY_LINE_START, + [ [ 0, 3, "foo\n", 0, 4 ] ]); + testTextAtOffset([ getAccessible("ht_3").firstChild.firstChild ], + BOUNDARY_LINE_START, + [ [ 0, 3, "foo\n", 0, 4 ], [ 4, 4, "\n", 4, 5 ] ]); + + // //////////////////////////////////////////////////////////////////////// + // 'Hello world ' (\n is rendered as space) + + testTextAtOffset([ "ht_4" ], BOUNDARY_LINE_START, + [ [ 0, 12, "Hello world ", 0, 12 ] ]); + + // //////////////////////////////////////////////////////////////////////// + // list items + + testTextAtOffset([ "li1" ], BOUNDARY_LINE_START, + [ [ 0, 6, kDiscBulletText + "Item", 0, 6 ] ]); + testTextAtOffset([ "li2" ], BOUNDARY_LINE_START, + [ [ 0, 2, kDiscBulletText, 0, 2 ] ]); + testTextAtOffset([ "li3" ], BOUNDARY_LINE_START, + [ [ 0, 8, kDiscBulletText + "a long ", 0, 9 ], + [ 9, 12, "and ", 9, 13 ] ]); + testTextAtOffset([ "li4" ], BOUNDARY_LINE_START, + [ [ 0, 7, kDiscBulletText + "a " + kEmbedChar + " c", 0, 7 ] ]); + testTextAtOffset([ "li5" ], BOUNDARY_LINE_START, + [ [ 0, 2, kDiscBulletText + "\n", 0, 3 ], + [ 3, 7, "hello", 3, 8 ] ]); + testTextAtOffset([ "ul1" ], BOUNDARY_LINE_START, + [ [ 0, 0, kEmbedChar, 0, 1 ], + [ 1, 1, kEmbedChar, 1, 2 ], + [ 2, 2, kEmbedChar, 2, 3 ], + [ 3, 3, kEmbedChar, 3, 4 ], + [ 4, 5, kEmbedChar, 4, 5 ] ]); + + testTextAtOffset([ "li6" ], BOUNDARY_LINE_START, + [ [ 0, 7, "1. Item", 0, 7 ] ]); + testTextAtOffset([ "li7" ], BOUNDARY_LINE_START, + [ [ 0, 3, "2. ", 0, 3 ] ]); + testTextAtOffset([ "li8" ], BOUNDARY_LINE_START, + [ [ 0, 9, "3. a long ", 0, 10 ], + [ 10, 13, "and ", 10, 14 ] ]); + testTextAtOffset([ "li9" ], BOUNDARY_LINE_START, + [ [ 0, 8, "4. a " + kEmbedChar + " c", 0, 8 ] ]); + testTextAtOffset([ "li10" ], BOUNDARY_LINE_START, + [ [ 0, 3, "5. \n", 0, 4 ], + [ 4, 8, "hello", 4, 9 ] ]); + testTextAtOffset([ "ol1" ], BOUNDARY_LINE_START, + [ [ 0, 0, kEmbedChar, 0, 1 ], + [ 1, 1, kEmbedChar, 1, 2 ], + [ 2, 2, kEmbedChar, 2, 3 ], + [ 3, 3, kEmbedChar, 3, 4 ], + [ 4, 5, kEmbedChar, 4, 5 ] ]); + + // //////////////////////////////////////////////////////////////////////// + // Nested hypertexts + + testTextAtOffset(["ht_5" ], BOUNDARY_LINE_START, + [ [ 0, 0, kEmbedChar, 0, 1 ] ]); + + // //////////////////////////////////////////////////////////////////////// + // Block followed by list + + testTextAtOffset([ "block_then_ul" ], BOUNDARY_LINE_START, + [ [ 0, 0, kEmbedChar, 0, 1 ], + [ 1, 1, kEmbedChar, 1, 2 ] ]); + + // Embedded char containing a line break breaks line offsets in parent. + testTextAtOffset([ "brInEmbed" ], BOUNDARY_LINE_START, + [ [0, 1, "a " + kEmbedChar, 0, 3], + [2, 2, "a " + kEmbedChar + " d", 0, 5], + [3, 5, kEmbedChar + " d", 2, 5] ]); + testTextAtOffset([ "brInEmbedAndBefore" ], BOUNDARY_LINE_START, + [ [0, 1, "a\n", 0, 2], + [2, 3, "b " + kEmbedChar, 2, 5], + [4, 4, "b " + kEmbedChar + " e", 2, 7], + [5, 7, kEmbedChar + " e", 4, 7] ]); + testTextAtOffset([ "brInEmbedAndAfter" ], BOUNDARY_LINE_START, + [ [0, 1, "a " + kEmbedChar, 0, 3], + [2, 2, "a " + kEmbedChar + " d\n", 0, 6], + [3, 5, kEmbedChar + " d\n", 2, 6], + [6, 7, "e", 6, 7] ]); + testTextAtOffset([ "brInEmbedAndBlockElementAfter" ], BOUNDARY_LINE_START, + [ [0, 2, "a " + kEmbedChar, 0, 3], + [3, 4, kEmbedChar, 3, 4] ]); + testTextAtOffset([ "brInEmbedThenTextThenBlockElement" ], BOUNDARY_LINE_START, + [ [0, 1, "a " + kEmbedChar, 0, 3], + [2, 2, "a " + kEmbedChar + " d", 0, 5], + [3, 4, kEmbedChar + " d", 2, 5], + [5, 6, kEmbedChar, 5, 6] ]); + testTextAtOffset([ "noBrInEmbedButOneBefore" ], BOUNDARY_LINE_START, + [ [0, 1, "a\n", 0, 2], + [2, 7, "b " + kEmbedChar + " d", 2, 7] ]); + testTextAtOffset([ "noBrInEmbedButOneAfter" ], BOUNDARY_LINE_START, + [ [0, 3, "a " + kEmbedChar + "\n", 0, 4], + [4, 5, "c", 4, 5] ]); + testTextAtOffset([ "twoEmbedsWithBRs" ], BOUNDARY_LINE_START, + [ [0, 1, "a " + kEmbedChar, 0, 3], + [2, 2, "a " + kEmbedChar + kEmbedChar, 0, 4], + [3, 3, kEmbedChar + kEmbedChar + " f", 2, 6], + [4, 6, kEmbedChar + " f", 3, 6] ]); + + // Inline block span with nested spans and BRs + testTextAtOffset([ "inlineBlockWithSpansAndBrs" ], BOUNDARY_LINE_START, + [ [0, 1, "a\n", 0, 2], + [2, 3, "b\n", 2, 4], + [4, 5, "c", 4, 5] ]); + + // Spans with BRs and whitespaces. + testTextAtOffset([ "spansWithWhitespaces" ], BOUNDARY_LINE_START, + [ [0, 6, "Line 1\n", 0, 7], + [7, 13, "Line 2\n", 7, 14], + [14, 20, "Line 3\n", 14, 21], + [21, 27, "Line 4\n", 21, 28], + [28, 28, "", 28, 28] ]); + + // A line with an empty display: contents leaf in the middle. + testTextAtOffset([ "displayContents" ], BOUNDARY_LINE_START, + // See the kOk test below. + // [ [0, 3, `a${kEmbedChar}b`, 0, 3] ]); + [ [0, 0, `a${kEmbedChar}b`, 0, 3], + [2, 3, `a${kEmbedChar}b`, 0, 3] ]); + testTextAtOffset(/* aOffset */ 1, BOUNDARY_LINE_START, + `a${kEmbedChar}b`, /* aStartOffset */ 0, /* aEndOffset */ 3, + "displayContents", + /* returned text */ kOk, + /* returned start offset */ kOk, + /* returned end offset */ kOk); + + // A line which wraps, followed by a br, followed by another line. + testTextAtOffset([ "brAfterWrapped" ], BOUNDARY_LINE_START, + [ [0, 1, "a ", 0, 2], + [2, 3, "b\n", 2, 4], + [4, 5, "c", 4, 5] ]); + + testTextAtOffset([ "inlineInput" ], BOUNDARY_LINE_END, + [ [0, 1, "a", 0, 1], + [2, 7, `\nb ${kEmbedChar} d`, 1, 7, + [ [ 4, "inlineInput", kOk, kOk, kOk] ] ] ]); + + testTextAtOffset([ "inlineInput2" ], BOUNDARY_LINE_END, + [ [0, 1, "a", 0, 1], + [2, 7, `\n${kEmbedChar} c d`, 1, 7, + [ [ 2, "inlineInput2", kOk, kOk, kOk] ] ] ]); + + testTextAtOffset([ "inlineInput3" ], BOUNDARY_LINE_END, + [ [0, 1, "a", 0, 1], + [2, 8, `\nb${kEmbedChar} c d`, 1, 8, + [ [ 3, "inlineInput3", kOk, kOk, kOk] ] ] ]); + + testTextAtOffset([ "inlineInput4" ], BOUNDARY_LINE_END, + [ [0, 1, "a", 0, 1], + [2, 7, `\n${kEmbedChar}b c d`, 1, 8, + [ [ 2, "inlineInput4", kOk, kOk, kOk ] ] ] ]); + + testTextAtOffset(/* aOffset */ 0, BOUNDARY_LINE_START, + kEmbedChar, 0, 1, "contentEditableTable", + /* returned text */ kOk, + /* returned start offset */ kOk, + /* returned end offset */ kOk); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <a target="_blank" + title="getTextAtOffset for word boundaries: beginning of a new life" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=853340"> + Bug 853340 + </a> + <a target="_blank" + title="getTextBeforeOffset for word boundaries: evolving" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=855732"> + Bug 855732 + </a> + <a target="_blank" + title=" getTextAfterOffset for line boundary on new rails" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=882292"> + Bug 882292 + </a> + <a target="_blank" + title="getTextAtOffset broken for last object when closing tag is preceded by newline char" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=947170"> + Bug 947170 + </a> + + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <input id="input" value="hello my friend"/> + <div id="div">hello my friend</div> + <div id="editable" contenteditable="true">hello my friend</div> + <textarea id="textarea">hello my friend</textarea> + <iframe id="ta_cntr" + src="data:text/html,<html><body><textarea id='ta'>hello my friend</textarea></body></html>"></iframe> + + <pre> + <div id="ml_div" style="border-style:outset;">oneword + +two words +</div> + <div id="ml_divbr" style="border-style:outset;">oneword<br/><br/>two words<br/></div> + <div id="ml_editable" style="border-style:outset;" contenteditable="true">oneword + +two words +</div> + <div id="ml_editablebr" contenteditable="true" style="border-style:outset;">oneword<br/><br/>two words<br/></div> + <textarea id="ml_textarea" cols="300">oneword + +two words +</textarea> + </pre> + + <iframe id="ht_1" src="data:text/html,<html><body>a <a href=''>b</a> c</body></html>"></iframe> + + <iframe id="ht_2" src="data:text/html,<div contentEditable='true'>foo<br/></div>"></iframe> + <iframe id="ht_3" src="data:text/html,<div contentEditable='true'>foo<br/><br/></div>"></iframe> + + <p id="ht_4">Hello world +</p> + + <ul id="ul1"> + <li id="li1">Item</li> + <li id="li2"></li> + <li id="li3" style="font-family:monospace; font-size:10pt; width:8ch;">a long and winding road that lead me to your door</li> + <li id="li4">a <a href=''>b</a> c</li> + <li id="li5"><br>hello</li> + </ul> + + <ol id="ol1"> + <li id="li6">Item</li> + <li id="li7"></li> + <li id="li8" style="font-family:monospace; font-size:10pt; width:8ch;">a long and winding road that lead me to your door</li> + <li id="li9">a <a href=''>b</a> c</li> + <li id="li10"><br>hello</li> + </ol> + + <div id="ht_5"> + <div> + <p>sectiounus</p> + <p>seciofarus</p> + </div> + </div> + <div id="line_test_1"> + Line 1 + <center><input type="TEXT"><input value="Button" type="SUBMIT"></center> + Line 3 + </div> + + <div id="block_then_ul"> + <p>Block</p> + <ul><li>Li</li></ul> + </div> + <div id="brInEmbed" contenteditable>a <a href="https://mozilla.org/">b<br>c</a> d</div> + <div id="brInEmbedAndBefore">a<br>b <a href="https://mozilla.org/">c<br>d</a> e</div> + <div id="brInEmbedAndAfter">a <a href="https://mozilla.org/">b<br>c</a> d<br>e</div> + <div id="brInEmbedAndBlockElementAfter">a <a href="https://mozilla.org/">b<br>c</a><p>d</p></div> + <div id="brInEmbedThenTextThenBlockElement">a <a href="https://mozilla.org/">b<br>c</a> d<p>e</p></div> + <div id="noBrInEmbedButOneBefore">a<br>b <a href="https://mozilla.org/">c</a> d</div> + <div id="noBrInEmbedButOneAfter">a <a href="https://mozilla.org/">b</a><br>c</div> + <div id="twoEmbedsWithBRs">a <a href="https://mozilla.org">b<br>c</a><a href="https://mozilla.org">d<br>e</a> f</div> + <span id="inlineBlockWithSpansAndBrs" style="display: inline-block;"><span>a<br>b<br><span></span></span>c</span> + <div id="spansWithWhitespaces"> <!-- Don't indent the following block --> +<span>Line 1<br/> +</span> +<span>Line 2<br/> +</span> +<span>Line 3<br/> +</span> +<span>Line 4<br/> +</span></div><!-- OK to indent again --> + <div id="displayContents">a<ul style="display: contents;"><li style="display: contents;"></li></ul>b</div> + <div id="brAfterWrapped" style="width: 10px;">a b<br>c</div> + <div id="inlineInput">a<br>b <input value="c"> d</div> + <div id="inlineInput2">a<br><input value="b"> c d</div> + <div id="inlineInput3">a<br> b<input value=""> c d</div> + <div id="inlineInput4">a<br><input value="">b c d</div> + <div id="contentEditableTable" contenteditable> + <table style="display: inline-table"> + <thead> + <th>Foo</th> + </thead> + <tbody> + <tr> + <td>Bar</td> + </tr> + </tbody> + </table> + <br> + <table style="display: inline-table"> + <thead> + <th>Foo</th> + </thead> + <tbody> + <tr> + <td>Bar</td> + </tr> + </tbody> + </table> + <br> + </div> +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_paragraphboundary.html b/accessible/tests/mochitest/text/test_paragraphboundary.html new file mode 100644 index 0000000000..8b270b661c --- /dev/null +++ b/accessible/tests/mochitest/text/test_paragraphboundary.html @@ -0,0 +1,148 @@ +<!DOCTYPE html> +<html> +<head> + <title>Paragraph boundary getText* functions tests</title> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../text.js"></script> + <script type="application/javascript"> + function doTest() { + // First, test the contentEditable. + testTextAtOffset("ce", BOUNDARY_PARAGRAPH, + [[0, 0, kEmbedChar, 0, 1], + [1, 2, kEmbedChar, 1, 2]]); + + // Now, test each paragraph. + var ID = getNode("ce").firstElementChild; + testTextAtOffset(ID, BOUNDARY_PARAGRAPH, + [[0, 15, "hello my friend", 0, 15]]); + ID = getNode("ce").lastElementChild; + testTextAtOffset(ID, BOUNDARY_PARAGRAPH, + [[0, 11, "hello again", 0, 11]]); + + // Test a paragraph whose line forcefully wraps. + testTextAtOffset("forced_wrap", BOUNDARY_PARAGRAPH, + [[0, 2, "ab", 0, 2]]); + + // Test paragraphs with a few line breaks. + testTextAtOffset("forced_br", BOUNDARY_PARAGRAPH, + [[0, 1, "a\n", 0, 2], // a and br treated as a paragraph + [2, 3, "b\n", 2, 4], // b treated as a paragraph, excl 2nd line break + [4, 4, "\n", 4, 5], // second br treated as a separate paragraph + [5, 6, "c", 5, 6]]); // Last paragraph treated as usual + testTextAtOffset("br_at_beginning", BOUNDARY_PARAGRAPH, + [[0, 0, "\n", 0, 1], // br treated as a separate paragraph + [1, 2, "a\n", 1, 3], // a and br treated as a paragraph + [3, 4, "b", 3, 4]]); // b treated as last paragraph + + // Test a paragraph with an embedded link. + testTextAtOffset("pWithLink", BOUNDARY_PARAGRAPH, + [[0, 3, "a" + kEmbedChar + "d", 0, 3]]); + testTextAtOffset("link", BOUNDARY_PARAGRAPH, + [[0, 2, "bc", 0, 2]]); + + // Paragraph with link that contains a line break. + testTextAtOffset("pWithLinkWithBr", BOUNDARY_PARAGRAPH, + [[0, 0, "a" + kEmbedChar, 0, 2], + [1, 1, "a" + kEmbedChar + "d", 0, 3], + [2, 3, kEmbedChar + "d", 1, 3]]); + + // Test a list and list item + testTextAtOffset("ul", BOUNDARY_PARAGRAPH, + [[0, 0, kEmbedChar, 0, 1], + [1, 2, kEmbedChar, 1, 2]]); + testTextAtOffset("li1", BOUNDARY_PARAGRAPH, + [[0, 3, "• a", 0, 3]]); + testTextAtOffset("li2", BOUNDARY_PARAGRAPH, + [[0, 3, "• a", 0, 3]]); + // Test a list item containing multiple text leaf nodes. + testTextAtOffset("liMultiLeaf", BOUNDARY_PARAGRAPH, + [[0, 4, "• ab", 0, 4]]); + + // Test line breaks in a textarea. + testTextAtOffset("textarea", BOUNDARY_PARAGRAPH, + [[0, 1, "a\n", 0, 2], + [2, 3, "b\n", 2, 4], + [4, 4, "\n", 4, 5], + [5, 6, "c", 5, 6]]); + + // Test that a textarea has a blank paragraph at the end if it contains + // a line break as its last character. + testTextAtOffset("textarea_with_trailing_br", BOUNDARY_PARAGRAPH, + [[0, 15, "This is a test.\n", 0, 16], + [16, 16, "", 16, 16]]); + + // Paragraph with a presentational line break. + testTextAtOffset("presentational_br", BOUNDARY_PARAGRAPH, + [[0, 3, "a b", 0, 3]]); + + // Two paragraphs in a div, non-editable case. + testTextAtOffset("two_paragraphs", BOUNDARY_PARAGRAPH, + [[0, 0, kEmbedChar, 0, 1], + [1, 2, kEmbedChar, 1, 2]]); + + // Div containing a paragraph containing a link + testTextAtOffset("divWithParaWithLink", BOUNDARY_PARAGRAPH, + [[0, 0, kEmbedChar, 0, 1], + [1, 2, "b", 1, 2]]); + + // Two text nodes and a br + testTextAtOffset("twoTextNodesAndBr", BOUNDARY_PARAGRAPH, + [[0, 2, "ab\n", 0, 3], + [3, 3, "", 3, 3]]); + + // Link followed by a paragraph. + testTextAtOffset("linkThenPara", BOUNDARY_PARAGRAPH, + [[0, 0, kEmbedChar, 0, 1], + [1, 2, kEmbedChar, 1, 2]]); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <a target="_blank" + title="getTextAtOffset for paragraph boundaries" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=1520779"> + Bug 1520779 + </a> + + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <div id="ce" contenteditable="true"> + <p>hello my friend</p> + <p>hello again</p> + </div> + <p id="forced_wrap" style="width: 1px; word-break: break-all;">ab</p> + <p id="forced_br">a<br>b<br><br>c</p> + <p id="br_at_beginning"><br>a<br>b</p> + <p id="pWithLink">a<a id="link" href="https://example.com/">bc</a>d</p> + <p id="pWithLinkWithBr">a<a href="#">b<br>c</a>d</p> + <ul id="ul"><li id="li1">a</li><li>b</li></ul> + <style>#li2::marker { content:'\2022\0020'; }</style> + <ul id="ul"><li id="li2">a</li><li>b</li></ul> + <ul><li id="liMultiLeaf">a<span>b</span></li></ul> + <textarea id="textarea">a +b + +c</textarea> <!-- This must be outdented for a correct test case --> + <textarea id="textarea_with_trailing_br">This is a test. +</textarea> <!-- This must be outdented for a correct test case --> + <p id="presentational_br" style="white-space: pre-wrap;">a<span> <br role="presentation"></span>b</p> + <div id="two_paragraphs"><p>a</p><p>b</p></div> + <div id ="divWithParaWithLink"><p><a href="#">a</a></p>b</div> + <p id="twoTextNodesAndBr">a<span>b</span><br></p> + <div id="linkThenPara"><a href="#">a</a><p>b</p></div> +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_passwords.html b/accessible/tests/mochitest/text/test_passwords.html new file mode 100644 index 0000000000..fc184f2d45 --- /dev/null +++ b/accessible/tests/mochitest/text/test_passwords.html @@ -0,0 +1,72 @@ +<!DOCTYPE html> +<html> +<head> + <title>nsIAccessibleText getText related function tests for text and password inputs</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../text.js"></script> + + <script type="application/javascript"> + function doTest() { + // //////////////////////////////////////////////////////////////////////// + // regular text and password inputs + // //////////////////////////////////////////////////////////////////////// + + // ////////////////////////////////////////////////////////////////////// + // characterCount and getText for regular text field + + var IDs = [ "username" ]; + testCharacterCount(IDs, 4); + testText(IDs, 0, 4, "test"); + + // ////////////////////////////////////////////////////////////////////// + // characterCount and getText for password field + + IDs = [ "password" ]; + testCharacterCount(IDs, 4); + let password = document.getElementById("password"); + let editor = SpecialPowers.wrap(password).editor; + let passwordMask = editor.passwordMask; + testText(IDs, 0, 4, `${passwordMask}${passwordMask}${passwordMask}${passwordMask}`); + // a11y data is updated at next tick so that we need to refresh here. + editor.unmask(0, 2); + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(0); + testText(IDs, 0, 4, `te${passwordMask}${passwordMask}`); + editor.unmask(2, 4); + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(0); + testText(IDs, 0, 4, `${passwordMask}${passwordMask}st`); + editor.unmask(0, 4); + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(0); + testText(IDs, 0, 4, `test`); + SpecialPowers.DOMWindowUtils.restoreNormalRefresh(); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <a target="_blank" + title="mochitest for getText for password fields" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=415943">Mozilla Bug 415943</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <form action="post.php" method="post"> + <label for="username">User name:</label> + <input id="username" value="test"><br /> + <label for="password">Password:</label> + <input type="password" id="password" value="test"/> + </form> +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_selection.html b/accessible/tests/mochitest/text/test_selection.html new file mode 100644 index 0000000000..ce83e57086 --- /dev/null +++ b/accessible/tests/mochitest/text/test_selection.html @@ -0,0 +1,119 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test text selection functions</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../text.js"></script> + + <script type="application/javascript"> + + function doTest() { + // Test selection count: clean selection / check count. + testTextAddSelection("div0", 0, 2, 1); // |Test selection... + cleanTextSelections("div0"); + testTextSelectionCount("div0", 0); + + // Test addition: adding two equal selections, the second one should + // not be added. + testTextAddSelection("div1", 7, 9, 1); // Test ad|di|ng two... + testTextAddSelection("div1", 7, 9, 1); // Test ad|di|ng two... + testTextGetSelection("div1", 7, 9, 0); + + // Test overlapping selections: adding three selections, one adjacent. + testTextAddSelection("div2", 0, 3, 1); // |Tes|t adding 3... + testTextAddSelection("div2", 7, 9, 2); // |Tes|t ad|di|ng 3... + testTextAddSelection("div2", 3, 4, 3); // |Tes||t| ad|di|ng 3... + testTextGetSelection("div2", 0, 3, 0); + testTextGetSelection("div2", 3, 4, 1); + testTextGetSelection("div2", 7, 9, 2); + + // Test selection re-ordering: adding two selections. + // NOTE: removeSelections aSelectionIndex is from start of document. + testTextAddSelection("div3", 0, 3, 1); // |Tes|t adding 2... + testTextAddSelection("div3", 7, 9, 2); // |Tes|t ad|di|ng 2... + testTextRemoveSelection("div3", 4, 1); // Test ad|di|ng 2... + + // Test extending existing selection. + // NOTE: setSelectionBounds aSelectionIndex is from start of document. + testTextAddSelection("div4", 4, 5, 1); // Test| |extending... + testTextSetSelection("div4", 4, 9, 6, 1); // Test| exte|nding... + + // Test moving an existing selection. + // NOTE: setSelectionBounds aSelectionIndex is from start of document. + testTextAddSelection("div5", 1, 3, 1); // T|es|t moving... + testTextSetSelection("div5", 5, 9, 6, 1); // Test |movi|ng... + + // Test adding selections to multiple inner elements. + testTextAddSelection("div71", 0, 3, 1); // |Tes|t adding... + testTextAddSelection("div71", 7, 8, 2); // |Tes|t ad|d|ing... + testTextAddSelection("div72", 4, 6, 1); // Test| a|dding... + testTextAddSelection("div72", 7, 8, 2); // Test| a|d|d|ing... + + // Test adding selection to parent element. + // NOTE: If inner elements are represented as embedded chars + // we count their internal selections. + testTextAddSelection("div7", 7, 8, 5); // Test ad|d|ing... + + // Test attempt to selected generated content. + // range's start is clipped to end of generated content. + testTextAddSelection("div8", 1, 8, 1); + testTextGetSelection("div8", 6, 8, 0); + // range's end is expanded to end of container hypertext. + testTextAddSelection("div8", 10, 15, 2); + testTextGetSelection("div8", 10, 23, 1); + + testTextAddSelection("li", 0, 8, 1); + testTextGetSelection("li", 3, 8, 0); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + +</script> +</head> + +<body> + + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <div id="div0">Test selection count</div> + </br> + <div id="div1">Test adding two equal selections </div> + <div id="div2">Test adding 3 selections one adjacent </div> + <div id="div3">Test adding 2 selections, remove first one </div> + <div id="div4">Test extending a selection </div> + <div id="div5">Test moving a selection </div> + </br> + <div id="div7">Test adding selections to parent element + <div id="div71">Test adding selections to inner element1 </div> + <div id="div72">Test adding selections to inner element2 </div> + </div> + <style> + #div8:before { + content: 'hello '; + } + #div8:after { + content: ', i love you'; + } + </style> + <div id="div8">world</div> + <ol> + <li id="li">Number one</li> + </ol> + +</body> + +</html> diff --git a/accessible/tests/mochitest/text/test_settext_input_event.html b/accessible/tests/mochitest/text/test_settext_input_event.html new file mode 100644 index 0000000000..2f0ecacf30 --- /dev/null +++ b/accessible/tests/mochitest/text/test_settext_input_event.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test that setTextContents only sends one DOM input event</title> + <meta charset="utf-8" /> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript"> + async function doTest() { + let input = getAccessible("input", [nsIAccessibleEditableText]); + let eventPromise = new Promise(resolve => + document.getElementById("input").addEventListener( + "input", resolve, { once: true })); + + input.setTextContents("goodbye"); + let inputEvent = await eventPromise; + is(inputEvent.target.value, "goodbye", "input set to new value."); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <a target="_blank" + title="HyperTextAccessible::ReplaceText causes two distinct DOM 'input' events" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=1490840">Mozilla Bug 1490840</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <input id="input" value="hello"> +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_textBounds.html b/accessible/tests/mochitest/text/test_textBounds.html new file mode 100644 index 0000000000..66e7f1a93f --- /dev/null +++ b/accessible/tests/mochitest/text/test_textBounds.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> +<head> + <title>TextBounds tests</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../layout.js"></script> + + <script type="application/javascript"> + function doTest() { + // Returned rect should be all 0 if no frame; e.g. display: contents. + testTextBounds( + "displayContents", 0, 0, [0, 0, 0, 0], COORDTYPE_SCREEN_RELATIVE + ); + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <section id="displayContents" style="display: contents;"></section> +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_wordboundary.html b/accessible/tests/mochitest/text/test_wordboundary.html new file mode 100644 index 0000000000..49d4d95561 --- /dev/null +++ b/accessible/tests/mochitest/text/test_wordboundary.html @@ -0,0 +1,361 @@ +<!DOCTYPE html> +<html> +<head> + <title>Word boundary text tests</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../text.js"></script> + + <script type="application/javascript"> + function doTest() { + // "hello" + // __h__e__l__l__o__ + // 0 1 2 3 4 5 + var ids = [ "i1", "d1", "e1", "t1" ]; + testTextBeforeOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "", 0, 0 ] ]); + testTextBeforeOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, "", 0, 0 ] ]); + + testTextAtOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "hello", 0, 5 ] ]); + testTextAtOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, "hello", 0, 5 ] ]); + + testTextAfterOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "", 5, 5 ] ]); + testTextAfterOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, "", 5, 5 ] ]); + + // "hello " + // __h__e__l__l__o__ __ + // 0 1 2 3 4 5 6 + ids = [ "i2", "d2", "p2", "e2", "t2" ]; + testTextBeforeOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 6, "", 0, 0 ] ]); + testTextBeforeOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, "", 0, 0 ], + [ 6, 6, "hello", 0, 5 ], + ]); + + testTextAtOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 6, "hello ", 0, 6 ] ]); + testTextAtOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 4, "hello", 0, 5 ], + [ 5, 6, " ", 5, 6 ], + ]); + + testTextAfterOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 6, "", 6, 6 ] ]); + testTextAfterOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, " ", 5, 6 ], + [ 6, 6, "", 6, 6 ], + ]); + + // "hello all" + // __h__e__l__l__o__ __a__l__l__ + // 0 1 2 3 4 5 6 7 8 9 + ids = [ "i6", "d6", "e6", "t6" ]; + testTextBeforeOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "", 0, 0 ], + [ 6, 9, "hello ", 0, 6 ]]); + testTextBeforeOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, "", 0, 0 ], + [ 6, 9, "hello", 0, 5 ] ]); + + testTextAtOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "hello ", 0, 6 ], + [ 6, 9, "all", 6, 9 ] ]); + testTextAtOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 4, "hello", 0, 5 ], + [ 5, 9, " all", 5, 9 ] ]); + + testTextAfterOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "all", 6, 9 ], + [ 6, 9, "", 9, 9 ] ]); + testTextAfterOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, " all", 5, 9 ], + [ 6, 9, "", 9, 9 ] ]); + + // " hello all " (with whitespace collapsing) + // __h__e__l__l__o__ __a__l__l__ __ + // 0 1 2 3 4 5 6 7 8 9 10 + ids = [ "d6a", "e6a" ]; + testTextBeforeOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "", 0, 0 ], + [ 6, 10, "hello ", 0, 6 ] ]); + testTextBeforeOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, "", 0, 0 ], + [ 6, 9, "hello", 0, 5 ], + [ 10, 10, " all", 5, 9 ] ]); + + testTextAtOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "hello ", 0, 6 ], + [ 6, 10, "all ", 6, 10 ] ]); + testTextAtOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 4, "hello", 0, 5 ], + [ 5, 8, " all", 5, 9 ], + [ 9, 10, " ", 9, 10 ] ]); + + testTextAfterOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "all ", 6, 10 ], + [ 6, 10, "", 10, 10 ] ]); + testTextAfterOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, " all", 5, 9 ], + [ 6, 9, " ", 9, 10 ], + [ 10, 10, "", 10, 10 ] ]); + + // "hello my friend" + // __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + ids = [ "i7", "d7", "e7", "t7", "w7" ]; + testTextBeforeOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "", 0, 0 ], + [ 6, 8, "hello ", 0, 6 ], + [ 9, 15, "my ", 6, 9 ] ]); + testTextBeforeOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, "", 0, 0 ], + [ 6, 8, "hello", 0, 5 ], + [ 9, 15, " my", 5, 8 ] ]); + + testTextAtOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "hello ", 0, 6 ], + [ 6, 8, "my ", 6, 9 ], + [ 9, 15, "friend", 9, 15] ]); + testTextAtOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 4, "hello", 0, 5 ], + [ 5, 7, " my", 5, 8 ], + [ 8, 15, " friend", 8, 15] ]); + + testTextAfterOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "my ", 6, 9 ], + [ 6, 8, "friend", 9, 15 ], + [ 9, 15, "", 15, 15 ] ]); + testTextAfterOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, " my", 5, 8 ], + [ 6, 8, " friend", 8, 15 ], + [ 9, 15, "", 15, 15 ] ]); + + // "Brave Sir Robin ran" + // __B__r__a__v__e__ __S__i__r__ __ __R__o__b__i__n__ __ __ __r__a__n__ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + ids = [ "i8", "d8", "e8", "t8" ]; + testTextBeforeOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "", 0, 0 ], + [ 6, 10, "Brave ", 0, 6 ], + [ 11, 18, "Sir ", 6, 11 ], + [ 19, 22, "Robin ", 11, 19 ] ]); + testTextBeforeOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, "", 0, 0 ], + [ 6, 9, "Brave", 0, 5 ], + [ 10, 16, " Sir", 5, 9 ], + [ 17, 22, " Robin", 9, 16 ] ]); + + testTextAtOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "Brave ", 0, 6 ], + [ 6, 10, "Sir ", 6, 11 ], + [ 11, 18, "Robin ", 11, 19 ], + [ 19, 22, "ran", 19, 22 ] ]); + testTextAtOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 4, "Brave", 0, 5 ], + [ 5, 8, " Sir", 5, 9 ], + [ 9, 15, " Robin", 9, 16 ], + [ 16, 22, " ran", 16, 22 ] ]); + + testTextAfterOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 5, "Sir ", 6, 11 ], + [ 6, 10, "Robin ", 11, 19 ], + [ 11, 18, "ran", 19, 22 ], + [ 19, 22, "", 22, 22 ] ]); + testTextAfterOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 5, " Sir", 5, 9 ], + [ 6, 9, " Robin", 9, 16 ], + [ 10, 16, " ran", 16, 22 ], + [ 17, 22, "", 22, 22 ] ]); + + // 'oneword + // ' + // 'two words + // ' + // __o__n__e__w__o__r__d__\n + // 0 1 2 3 4 5 6 7 + // __\n + // 8 + // __t__w__o__ __w__o__r__d__s__\n__ + // 9 10 11 12 13 14 15 16 17 18 19 + + ids = ["ml_div1", "ml_divbr1", "ml_ediv1", "ml_edivbr1", "ml_t1"]; + testTextBeforeOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 8, "", 0, 0 ], + [ 9, 12, "oneword\n\n", 0, 9 ], + [ 13, 19, "two ", 9, 13 ] ]); + testTextBeforeOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 7, "", 0, 0 ], + [ 8, 12, "oneword", 0, 7, + [ [ 8, "ml_divbr1", kOk, kOk, kOk ], + [ 8, "ml_edivbr1", kOk, kOk, kOk ], + [ 9, "ml_divbr1", kOk, kOk, kOk ], + [ 9, "ml_edivbr1", kOk, kOk, kOk ] ] ], + [ 13, 18, "\n\ntwo", 7, 12 ], + [ 19, 19, " words", 12, 18, + [ [ 19, "ml_divbr1", kOk, kOk, kOk ], + [ 19, "ml_edivbr1", kOk, kOk, kOk ] ] ], + ] ); + + testTextAtOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 8, "oneword\n\n", 0, 9 ], + [ 9, 12, "two ", 9, 13 ], + [ 13, 19, "words\n", 13, 19 ] ]); + testTextAtOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 6, "oneword", 0, 7 ], + [ 7, 11, "\n\ntwo", 7, 12 ], + [ 12, 17, " words", 12, 18 ], + [ 18, 19, "\n", 18, 19, + [ [ 18, "ml_divbr1", kOk, kOk, kOk ], + [ 18, "ml_edivbr1", kOk, kOk, kOk ], + [ 19, "ml_divbr1", kOk, kOk, kOk ], + [ 19, "ml_edivbr1", kOk, kOk, kOk ] ] ] ]); + + testTextAfterOffset(ids, BOUNDARY_WORD_START, + [ [ 0, 8, "two ", 9, 13 ], + [ 9, 12, "words\n", 13, 19 ], + [ 13, 19, "", 19, 19 ] ]); + testTextAfterOffset(ids, BOUNDARY_WORD_END, + [ [ 0, 7, "\n\ntwo", 7, 12 ], + [ 8, 12, " words", 12, 18 ], + [ 13, 18, "\n", 18, 19, + [ [ 18, "ml_divbr1", kOk, kOk, kOk ], + [ 18, "ml_edivbr1", kOk, kOk, kOk ] ] ], + [ 19, 19, "", 19, 19 ] ]); + + // a <a href="#">b</a> + // a * + testTextBeforeOffset("cntr_1", BOUNDARY_WORD_START, + [ [ 0, 1, "", 0, 0 ], + [ 2, 3, "a ", 0, 2 ] ]); + + testTextAtOffset("cntr_1", BOUNDARY_WORD_START, + [ [ 0, 1, "a ", 0, 2 ], + [ 2, 3, kEmbedChar, 2, 3 ] ]); + testTextAfterOffset("cntr_1", BOUNDARY_WORD_START, + [ [ 0, 1, kEmbedChar, 2, 3 ], + [ 2, 3, "", 3, 3 ] ]); + + // Punctuation tests. + testTextAtOffset("punc_alone", BOUNDARY_WORD_START, [ + [ 0, 1, "a ", 0, 2 ], + [ 2, 4, "@@ ", 2, 5 ], + [ 5, 6, "b", 5, 6 ] + ]); + testTextAtOffset("punc_begin", BOUNDARY_WORD_START, [ + [ 0, 1, "a ", 0, 2 ], + [ 2, 5, "@@b ", 2, 6 ], + [ 6, 7, "c", 6, 7 ] + ]); + testTextAtOffset("punc_end", BOUNDARY_WORD_START, [ + [ 0, 1, "a ", 0, 2 ], + [ 2, 5, "b@@ ", 2, 6 ], + [ 6, 7, "c", 6, 7 ] + ]); + testTextAtOffset("punc_middle", BOUNDARY_WORD_START, [ + [ 0, 1, "a ", 0, 2 ], + [ 2, 4, "b@@", 2, 5 ], + [ 5, 6, "c ", 5, 7 ], + [ 7, 8, "d", 7, 8 ] + ]); + testTextAtOffset("punc_everywhere", BOUNDARY_WORD_START, [ + [ 0, 1, "a ", 0, 2 ], + [ 2, 6, "@@b@@", 2, 7 ], + [ 7, 10, "c@@ ", 7, 11 ], + [ 11, 12, "d", 11, 12 ] + ]); + + // Multi-word embedded object test. + testTextAtOffset("multiword_embed", BOUNDARY_WORD_START, [ + [ 0, 1, "a ", 0, 2 ], + [ 2, 3, `${kEmbedChar} `, 2, 4, [ + // Word at offset 2 returns end offset 3, should be 4. + [ 2, "multiword_embed", kOk, kOk, kOk ] + ] ], + [ 4, 5, "b", 4, 5 ] + ]); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <input id="i1" value="hello"/> + <div id="d1">hello</div> + <div id="e1" contenteditable="true">hello</div> + <textarea id="t1">hello</textarea> + + <input id="i2" value="hello "/> + <div id="d2"> hello </div> + <pre><div id="p2">hello </div></pre> + <div id="e2" contenteditable="true" style='white-space:pre'>hello </div> + <textarea id="t2">hello </textarea> + + <input id="i6" value="hello all"/> + <div id="d6"> hello all</div> + <div id="e6" contenteditable="true">hello all</div> + <textarea id="t6">hello all</textarea> + + <div id="d6a"> hello all </div> + <div id="e6a" contenteditable="true"> hello all </div> + + <input id="i7" value="hello my friend"/> + <div id="d7"> hello my friend</div> + <div id="e7" contenteditable="true">hello my friend</div> + <textarea id="t7">hello my friend</textarea> + <div id="w7" style="width:1em"> hello my friend</div> + + <input id="i8" value="Brave Sir Robin ran"/> + <pre> + <div id="d8">Brave Sir Robin ran</div> + <div id="e8" contenteditable="true">Brave Sir Robin ran</div> + </pre> + <textarea id="t8" cols="300">Brave Sir Robin ran</textarea> + + <pre> +<div id="ml_div1">oneword + +two words +</div> +<div id="ml_divbr1">oneword<br/><br/>two words<br/></div> +<div id="ml_ediv1" contenteditable="true">oneword + +two words +</div> +<div id="ml_edivbr1" contenteditable="true">oneword<br/><br/>two words<br/></div> +<textarea id="ml_t1" cols="300">oneword + +two words +</textarea> + </pre> + + <div id="cntr_1">a <a href="#">b</a></div> + + <p id="punc_alone">a @@ b</p> + <p id="punc_begin">a @@b c</p> + <p id="punc_end">a b@@ c</p> + <p id="punc_middle">a b@@c d</p> + <p id="punc_everywhere">a @@b@@c@@ d</p> + + <p id="multiword_embed">a <a href="#">x y</a> b</p> +</body> +</html> diff --git a/accessible/tests/mochitest/text/test_words.html b/accessible/tests/mochitest/text/test_words.html new file mode 100644 index 0000000000..db61dc09ce --- /dev/null +++ b/accessible/tests/mochitest/text/test_words.html @@ -0,0 +1,154 @@ +<!DOCTYPE html> +<html> +<head> + <title>nsIAccessibleText getText related function tests for html:input,html:div and html:textarea</title> + <meta charset="utf-8" /> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../text.js"></script> + <script type="application/javascript"> + if (navigator.platform.startsWith("Mac")) { + SimpleTest.expectAssertions(0, 1); + } else { + SimpleTest.expectAssertions(0, 1); + } + + async function doTest() { + test_common(); + for (let newSegmenter of [true, false]) { + for (let stopAtPunctuation of [true, false]) { + await test_per_segmenter(newSegmenter, stopAtPunctuation); + } + } + SimpleTest.finish(); + } + + function test_common() { + // "one two" + testWords("div1", ["one", "two"]); + + // "one two" + testWords("div2", ["one", "two"]); + + // "one,two" + testWordCount("div3", 2, kOk); + testWordAt("div3", 0, "one", kTodo); + testWordAt("div3", 1, "two", kOk); + + // "one, two" + testWordCount("div4", 2, kOk); + testWordAt("div4", 0, "one", kTodo); + testWordAt("div4", 1, "two", kOk); + + // "one+two" + testWordCount("div5", 2, kOk); + testWordAt("div5", 0, "one", kTodo); + testWordAt("div5", 1, "two", kOk); + + // "one+two " + testWordCount("div6", 2, kOk); + testWordAt("div6", 0, "one", kTodo); + testWordAt("div6", 1, "two", kOk); + + // "one\ntwo" + testWordCount("div7", 2, kOk); + testWordAt("div7", 0, "one", kOk); + testWordAt("div7", 1, "two", kTodo); + + // "345" + testWords("div9", ["345"]); + + // "3a A4" + testWords("div10", ["3a", "A4"]); + + // "カタカナ" + testWords("div13", ["カタカナ"], kOk); + + // "3+4*5=23" + testWordCount("div16", 4, kOk); + testWordAt("div16", 0, "3", kTodo); + testWordAt("div16", 1, "4", kTodo); + testWordAt("div16", 2, "5", kTodo); + testWordAt("div16", 3, "23", kTodo); + + // "Hello. Friend, are you here?!" + testWordCount("div17", 5, kOk); + testWordAt("div17", 0, "Hello", kTodo); + testWordAt("div17", 1, "Friend", kTodo); + testWordAt("div17", 2, "are", kOk); + testWordAt("div17", 3, "you", kOk); + testWordAt("div17", 4, "here", kTodo); + + testWords("input_1", ["foo", "bar"]); + } + + async function test_per_segmenter(aNewSegmenter, aStopAtPunctuation) { + // If aNewSegmenter is true, use UAX#14/#29 compatible segmenter. + await SpecialPowers.pushPrefEnv({"set": [ + ["intl.icu4x.segmenter.enabled", aNewSegmenter], + ["layout.word_select.stop_at_punctuation", aStopAtPunctuation], + ]}); + + // "one.two" + if (!aStopAtPunctuation) { + testWordCount("div8", 1, kOk); + testWordAt("div8", 0, "one.two", kOk); + } else { + testWordCount("div8", 2, kOk); + testWordAt("div8", 0, "one", kTodo); + testWordAt("div8", 1, "two", kOk); + } + + // "3.1416" + testWords("div11", ["3.1416"], !aStopAtPunctuation ? kOk : kTodo); + + // "4,261.01" + testWords("div12", ["4,261.01"], !aStopAtPunctuation ? kOk: kTodo); + + // "Peter's car" + testWords("div14", ["Peter's", "car"], !aStopAtPunctuation ? kOk : kTodo); + + // "N.A.T.O." + testWords("div15", ["N.A.T.O."], !aStopAtPunctuation ? kOk : kTodo); + + await SpecialPowers.popPrefEnv(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <a target="_blank" + title="nsIAccessibleText test word boundaries" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=452769">Mozilla Bug 452769</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + <div id="div1">one two</div> + <div id="div2">one two</div> + <div id="div3">one,two</div> + <div id="div4">one, two</div> + <div id="div5">one+two</div> + <div id="div6">one+two </div> + <div id="div7">one<br/>two</div> + <div id="div8">one.two</div> + <div id="div9">345</div> + <div id="div10">3a A4</div> + <div id="div11">3.1416</div> + <div id="div12">4,261.01</div> + <div id="div13">カタカナ</div> + <div id="div14">Peter's car</div> + <div id="div15">N.A.T.O.</div> + <div id="div16">3+4*5=23</div> + <div id="div17">Hello. Friend, are you here?!</div> + </pre> + <input id="input_1" type="text" value="foo bar" placeholder="something or other"> + +</body> +</html> |