<!DOCTYPE> <html> <head> <meta charset="utf-8"> <title>multi-click selection extension test</title> <script src="/tests/SimpleTest/SimpleTest.js"></script> <script src="/tests/SimpleTest/EventUtils.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> <style> .testingDiv { font: 16px/1.25 monospace; width: -moz-fit-content; } p { margin: 0; unicode-bidi: bidi-override; } </style> </head> <body> <div id="testDiv" class="testingDiv"> <p>one two three</p> <p>un deux trois</p> <p>ein zwei drei</p> </div> <br> <div id="rtlTestDiv" class="testingDiv" dir="rtl"> <p>one two three</p> <p>un deux trois</p> <p>ein zwei drei</p> </div> <pre id="test"> <script class="testbody" type="text/javascript"> function test() { const testDiv = document.getElementById("testDiv"); const rtlTestDiv = document.getElementById("rtlTestDiv"); // Expected line height (CSS 'lh' unit), given that font-size = 16px and // line-height = 1.25. const lh = 20; // Width of one character in the monospace font (the CSS 'ch' unit), // calculated by measuring the test text that contains 13 chars per line. const ch = testDiv.offsetWidth / 13; const platformIsWindows = !navigator.platform.indexOf("Win"); const eatSpaceAfterWord = SpecialPowers.getBoolPref("layout.word_select.eat_space_to_next_word"); // Y-coordinates that will fall within each line: const firstLine = 0.5 * lh; const secondLine = 1.5 * lh; const thirdLine = 2.5 * lh; // Return the character offset of "^", representing the position to click/drag // within the test string. function xPosForClick(s) { return s.indexOf("^") * ch; } // Test expectation strings use "_" to represent a space that is only expected // to be present on Windows, where layout.word_select.eat_space_to_next_word // is set by default, and <PAR> to denote a paragraph separator sequence (two // platform-specific newlines). function expectation(s) { let result = s.replace("_", eatSpaceAfterWord ? " " : ""); result = result.replace("<PAR>", platformIsWindows ? "\r\n\r\n" : "\n\n"); return result; } // Sanity-check that we're hitting what we expect with our clicks: synthesizeMouse(testDiv, xPosForClick("un de^ux trois"), secondLine, { clickCount: 2 }); is(window.getSelection().toString(), expectation("deux_"), "Double-click middle word"); // Each entry in the array specifies which line to drag to, the character position // within that line (indicated by the caret ^ in the given string), and what the // expected selection should then be. const wordSelectTests = [ [secondLine, "un^ deux trois", "un deux_", "Drag left to extend by word"], [secondLine, "un ^deux trois", "deux_", "Return to edge of anchor word"], [secondLine, "un d^eux trois", "deux_", "Return to within anchor word"], [secondLine, "un deux t^rois", "deux trois", "Drag right to extend by word"], [firstLine, "one t^wo three", "two three<PAR>un deux_", "Drag into previous line"], [secondLine, "un ^deux trois", "deux_", "Drag back to start of anchor word"], [secondLine, "un de^ux trois", "deux_", "Drag back to middle of anchor word"], [thirdLine, "ein zw^ei drei", "deux trois<PAR>ein zwei_", "Drag into next line"], [secondLine, "un de^ux trois", "deux_", "Return to anchor word"], ]; const lineSelectTests = [ [secondLine, "un de^ux trois", "un deux trois", "Triple-click selected whole line"], [firstLine, "one t^wo three", "one two three<PAR>un deux trois", "Drag up into previous line"], [secondLine, "un de^ux trois", "un deux trois", "Return to middle line"], [thirdLine, "ein z^wei drei", "un deux trois<PAR>ein zwei drei", "Drag down into next line"], [secondLine, "un de^ux trois", "un deux trois", "Return to middle line"], ]; // The RTL tests use monospaced latin text with bidi-override applied; // we specify caret positions by counting characters in a reversed string. const rtlWordSelectTests = [ [secondLine, "siort xued ^nu", "un deux_", "Drag right to extend by word"], [secondLine, "siort xued^ nu", "deux_", "Return to edge of anchor word"], [secondLine, "siort xu^ed nu", "deux_", "Return to within anchor word"], [secondLine, "siort^ xued nu", "deux trois", "Drag left to extend by word"], [firstLine, "eerht ow^t eno", "two three<PAR>un deux_", "Drag into previous line"], [secondLine, "siort xued^ nu", "deux_", "Drag back to start of anchor word"], [secondLine, "siort xu^ed nu", "deux_", "Drag back to middle of anchor word"], [thirdLine, "ierd ie^wz nie", "deux trois<PAR>ein zwei_", "Drag into next line"], [secondLine, "siort xu^ed nu", "deux_", "Return to anchor word"], ]; function testMultiClickAndDrag(elem, initialPos, clickCount, tests) { // Initial multi-click in the middle word of the middle line: synthesizeMouse(elem, xPosForClick(initialPos), secondLine, { type: "mousedown", clickCount: clickCount }); // Now drag to each test position and check the resulting selection: tests.forEach(function(t) { synthesizeMouse(elem, xPosForClick(t[1]), t[0], { type: "mousemove" }); is(window.getSelection().toString(), expectation(t[2]), t[3]); }); // Finish the test sequence with mouseUp. synthesizeMouse(elem, xPosForClick(initialPos), secondLine, { type: "mouseup" }); } testMultiClickAndDrag(testDiv, "un de^ux trois", 2, wordSelectTests); testMultiClickAndDrag(testDiv, "un de^ux trois", 3, lineSelectTests); testMultiClickAndDrag(rtlTestDiv, "siort xu^ed nu", 2, rtlWordSelectTests); SimpleTest.finish(); } window.onload = function() { setTimeout(test, 0); }; SimpleTest.waitForExplicitFinish(); </script> </pre> </body> </html>