blob: 4b90e5b74542cc64c57758c2f493abc06dfae08e [file] [log] [blame]
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
div.test {
-webkit-user-modify: read-write;
padding: 4px;
border: 1px dashed lightblue;
margin: 4px 4px 4px 24px;
outline: none;
font-family: Lucida Grande;
counter-increment: test-number;
}
div.test:before { content: counter(test-number); position: absolute; left: 8px; font-size: x-small; text-align: right; width: 20px; }
div.test span { background-color: #def; }
div.test img { width: 1em; height: 1em; background-color: lightgreen; }
div.test img + img { background-color: lightblue; }
div.test div { border: 1px dashed pink; padding: 3px; height: 2em; }
</style>
<script>
var messages = [];
function log(message)
{
messages.push(message);
}
function flushLog()
{
document.getElementById("console").appendChild(document.createTextNode(messages.join("")));
}
function caretCoordinates()
{
if (!window.textInputController)
return { x: 0, y :0 };
var caretRect = textInputController.firstRectForCharacterRange(textInputController.selectedRange()[0], 0);
return { x: caretRect[0], y: caretRect[1] };
}
function positionsMovingInDirection(sel, direction)
{
var positions = [];
while (true) {
positions.push({ node: sel.anchorNode, offset: sel.anchorOffset, point: caretCoordinates() });
sel.modify("move", direction, "character");
if (positions[positions.length - 1].node == sel.anchorNode && positions[positions.length - 1].offset == sel.anchorOffset)
break;
};
return positions;
}
function fold(string)
{
var result = "";
for (var i = 0; i < string.length; ++i) {
var char = string.charCodeAt(i);
if (char >= 0x0660) // Arabic numeral 0
char = char - 0x660 + '0'.charCodeAt(0);
else if (char >= 0x0627) // Alif
char = char - 0x0627 + 'A'.charCodeAt(0);
else if (char >= 0x05d0)
char -= 0x058f;
else if (char == 10) {
result += "\\n";
continue;
}
result += String.fromCharCode(char);
}
return result;
}
function logPositions(positions)
{
for (var i = 0; i < positions.length; ++i) {
if (i) {
if (positions[i].node != positions[i - 1].node)
log("]");
log(", ");
}
if (!i || positions[i].node != positions[i - 1].node)
log((positions[i].node instanceof Text ? '"' + fold(positions[i].node.data) + '"' : "<" + positions[i].node.tagName + ">") + "[");
log(positions[i].offset);
}
log("]");
}
function checkReverseOrder(positions, reversePositions)
{
var mismatch = positions.length != reversePositions.length;
while (!mismatch) {
var pos = positions.pop();
if (!pos)
break;
var reversePos = reversePositions.shift();
if (pos.node != reversePos.node || pos.offset != reversePos.offset)
mismatch = true;
}
if (mismatch)
log("WARNING: Moving to the left did not visit the same positions in reverse order as moving to the right.\n");
}
function checkCoordinatesMovingRightDown(positions)
{
for (var i = 1; i < positions.length; ++i) {
if (positions[i].point.y > positions[i - 1].point.y || positions[i].point.x < positions[i - 1].point.x && positions[i].point.y >= positions[i - 1].point.y)
log("WARNING: Moved in the wrong direction in step " + i + ": from (" + positions[i - 1].point.x + ", " + positions[i - 1].point.y + ") to (" + positions[i].point.x + ", " + positions[i].point.y + ").\n");
}
}
function checkCoordinatesMovingLeftDown(positions)
{
for (var i = 1; i < positions.length; ++i) {
if (positions[i].point.y > positions[i - 1].point.y || positions[i].point.x > positions[i - 1].point.x && positions[i].point.y >= positions[i - 1].point.y)
log("WARNING: Moved in the wrong direction in step " + i + ": from (" + positions[i - 1].point.x + ", " + positions[i - 1].point.y + ") to (" + positions[i].point.x + ", " + positions[i].point.y + ").\n");
}
}
function checkCoordinatesMovingRightUp(positions)
{
for (var i = 1; i < positions.length; ++i) {
if (positions[i].point.y < positions[i - 1].point.y || positions[i].point.x < positions[i - 1].point.x && positions[i].point.y <= positions[i - 1].point.y)
log("WARNING: Moved in the wrong direction in step " + i + ": from (" + positions[i - 1].point.x + ", " + positions[i - 1].point.y + ") to (" + positions[i].point.x + ", " + positions[i].point.y + ").\n");
}
}
function checkCoordinatesMovingLeftUp(positions)
{
for (var i = 1; i < positions.length; ++i) {
if (positions[i].point.y < positions[i - 1].point.y || positions[i].point.x > positions[i - 1].point.x && positions[i].point.y <= positions[i - 1].point.y)
log("WARNING: Moved in the wrong direction in step " + i + ": from (" + positions[i - 1].point.x + ", " + positions[i - 1].point.y + ") to (" + positions[i].point.x + ", " + positions[i].point.y + ").\n");
}
}
function runTest()
{
var tests = document.getElementsByClassName("test");
var sel = getSelection();
for (var i = 0; i < tests.length; ++i) {
var positionsMovingRight;
var positionsMovingLeft;
log("Test " + (i + 1) + ", LTR:\n Moving right: ");
sel.collapse(tests[i], 0);
positionsMovingRight = positionsMovingInDirection(sel, "right");
logPositions(positionsMovingRight);
log("\n");
checkCoordinatesMovingRightDown(positionsMovingRight);
log(" Moving left: ");
positionsMovingLeft = positionsMovingInDirection(sel, "left");
logPositions(positionsMovingLeft);
log("\n");
checkCoordinatesMovingLeftUp(positionsMovingLeft);
checkReverseOrder(positionsMovingLeft, positionsMovingRight);
tests[i].style.direction = "rtl";
log("Test " + (i + 1) + ", RTL:\n Moving left: ");
sel.collapse(tests[i], 0);
positionsMovingLeft = positionsMovingInDirection(sel, "left");
logPositions(positionsMovingLeft);
log("\n");
checkCoordinatesMovingLeftDown(positionsMovingLeft);
log(" Moving right: ");
positionsMovingRight = positionsMovingInDirection(sel, "right");
logPositions(positionsMovingRight);
log("\n");
checkCoordinatesMovingRightUp(positionsMovingRight);
checkReverseOrder(positionsMovingLeft, positionsMovingRight);
}
document.getElementById("testGroup").style.display = "none";
}
onload = function() {
try {
runTest();
} finally {
flushLog();
}
};
if (window.testRunner)
testRunner.dumpAsText();
</script>
</head>
<body>
<div id="testGroup">
<div class="test">
abc
</div>
<div class="test">
אבג
</div>
<div class="test"><br>abc
</div>
<div class="test"><br>אבג
</div>
<div class="test">
abcאבגdef
</div>
<div class="test">
אבגabcדהו
</div>
<div class="test">
abcאבגדהו
</div>
<div class="test">
אבגabcdef
</div>
<div class="test">١٢٣ابة</div>
<div class="test">ابة١٢٣</div>
<div class="test">
<span>abc</span>אבגdef
</div>
<div class="test">
<span>אבג</span>abcדהו
</div>
<div class="test">abcאבג123דהוdef
</div>
<div class="test">abcאבג123
</div>
<div class="test">abcאבג123def
</div>
<div class="test">אבג123דהוabcזחט456יכל
</div>
<div class="test" style="width: 120px;">
before אחרי אנציקלופדיה
</div>
<div class="test" style="width: 120px;">
לפני after encyclopedia
</div>
<div class="test" contenteditable style="width: 120px;">
before אחרי אנציקלופדיה
</div>
<div class="test" contenteditable style="width: 120px;">
לפני after encyclopedia
</div>
<div class="test" style="width: 100px;">
This is יותר צר מיתר the boxes.
</div>
<div contenteditable class="test" style="width: 100px;">
This is יותר צר מיתר the boxes.
</div>
<div class="test">
Lorem
<div></div>
ipsum
</div>
<div class="test">
צלחת
<div></div>
מצנפת
</div>
<div class="test">
abcdefאבג<img>דהו
</div>
<div class="test">
אבגדהוabc<img>def
</div>
<div class="test">
abc<input>אבג<img><img>דהוghi
</div>
<div class="test">
אבג<input>abc<img><img>defדהו
</div>
<div class="test">
abcאבג<span>דהו</span>
</div>
<div class="test">
אבגabc<span>def</span>
</div>
<div class="test">
ab<span>cאבגdef</span>
</div>
<div class="test">
אב<span>גabcדהו</span>
</div>
<div class="test">
abc<span>אבגdef</span>
</div>
<div class="test">
אבג<span>abcדהו</span>
</div>
<div class="test">
abcאdef
</div>
<div class="test">
אבגaדהו
</div>
<div class="test">
abcאבג<span>def</span>
</div>
<div class="test">
אבגabc<span>דהו</span>
</div>
<div class="test">
abcא<span>בגdef</span>
</div>
<div class="test">
אבגa<span>bcדהו</span>
</div>
<div class="test" style="white-space: pre;">abc<!-- -->
<!-- -->def</div>
<div class="test" style="white-space: pre;">אבג<!-- -->
<!-- -->דהו</div>
<div class="test">
<span dir="rtl">abcקקק123נננdef</span>
</div>
</div>
<pre id="console"></pre>
</body>