diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /editor/libeditor/tests/test_texteditor_keyevent_handling.html | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'editor/libeditor/tests/test_texteditor_keyevent_handling.html')
-rw-r--r-- | editor/libeditor/tests/test_texteditor_keyevent_handling.html | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/editor/libeditor/tests/test_texteditor_keyevent_handling.html b/editor/libeditor/tests/test_texteditor_keyevent_handling.html new file mode 100644 index 000000000..5c4a8d1c2 --- /dev/null +++ b/editor/libeditor/tests/test_texteditor_keyevent_handling.html @@ -0,0 +1,386 @@ +<html> +<head> + <title>Test for key event handler of text editor</title> + <script type="text/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" + src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +</head> +<body> +<div id="display"> + <input type="text" id="inputField"> + <input type="password" id="passwordField"> + <textarea id="textarea"></textarea> +</div> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> + +<script class="testbody" type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(runTests, window); + +var inputField = document.getElementById("inputField"); +var passwordField = document.getElementById("passwordField"); +var textarea = document.getElementById("textarea"); + +const kIsMac = navigator.platform.indexOf("Mac") == 0; +const kIsWin = navigator.platform.indexOf("Win") == 0; +const kIsLinux = navigator.platform.indexOf("Linux") == 0; + +function runTests() +{ + var fm = SpecialPowers.Cc["@mozilla.org/focus-manager;1"]. + getService(SpecialPowers.Ci.nsIFocusManager); + + var capturingPhase = { fired: false, prevented: false }; + var bubblingPhase = { fired: false, prevented: false }; + + var listener = { + handleEvent: function _hv(aEvent) + { + is(aEvent.type, "keypress", "unexpected event is handled"); + switch (aEvent.eventPhase) { + case aEvent.CAPTURING_PHASE: + capturingPhase.fired = true; + capturingPhase.prevented = aEvent.defaultPrevented; + break; + case aEvent.BUBBLING_PHASE: + bubblingPhase.fired = true; + bubblingPhase.prevented = aEvent.defaultPrevented; + aEvent.preventDefault(); // prevent the browser default behavior + break; + default: + ok(false, "event is handled in unexpected phase"); + } + } + }; + + function check(aDescription, + aFiredOnCapture, aFiredOnBubbling, aPreventedOnBubbling) + { + function getDesciption(aExpected) + { + return aDescription + (aExpected ? " wasn't " : " was "); + } + + is(capturingPhase.fired, aFiredOnCapture, + getDesciption(aFiredOnCapture) + "fired on capture phase"); + is(bubblingPhase.fired, aFiredOnBubbling, + getDesciption(aFiredOnBubbling) + "fired on bubbling phase"); + + // If the event is fired on bubbling phase and it was already prevented + // on capture phase, it must be prevented on bubbling phase too. + if (capturingPhase.prevented) { + todo(false, aDescription + + " was consumed already, so, we cannot test the editor behavior actually"); + aPreventedOnBubbling = true; + } + + is(bubblingPhase.prevented, aPreventedOnBubbling, + getDesciption(aPreventedOnBubbling) + "prevented on bubbling phase"); + } + + var parentElement = document.getElementById("display"); + SpecialPowers.addSystemEventListener(parentElement, "keypress", listener, + true); + SpecialPowers.addSystemEventListener(parentElement, "keypress", listener, + false); + + function doTest(aElement, aDescription, aIsSingleLine, aIsReadonly, + aIsTabbable) + { + function reset(aText) + { + capturingPhase.fired = false; + capturingPhase.prevented = false; + bubblingPhase.fired = false; + bubblingPhase.prevented = false; + aElement.value = aText; + } + + if (document.activeElement) { + document.activeElement.blur(); + } + + aDescription += ": " + + aElement.focus(); + is(SpecialPowers.unwrap(fm.focusedElement), aElement, aDescription + "failed to move focus"); + + // Backspace key: + // If editor is readonly, it doesn't consume. + // If editor is editable, it consumes backspace and shift+backspace. + // Otherwise, editor doesn't consume the event but the native key + // bindings on nsTextControlFrame may consume it. + reset(""); + synthesizeKey("VK_BACK_SPACE", { }); + check(aDescription + "Backspace", true, true, true); + + reset(""); + synthesizeKey("VK_BACK_SPACE", { shiftKey: true }); + check(aDescription + "Shift+Backspace", true, true, true); + + reset(""); + synthesizeKey("VK_BACK_SPACE", { ctrlKey: true }); + // Win: cmd_deleteWordBackward + check(aDescription + "Ctrl+Backspace", + true, true, aIsReadonly || kIsWin); + + reset(""); + synthesizeKey("VK_BACK_SPACE", { altKey: true }); + // Win: cmd_undo + // Mac: cmd_deleteWordBackward + check(aDescription + "Alt+Backspace", + true, true, aIsReadonly || kIsWin || kIsMac); + + reset(""); + synthesizeKey("VK_BACK_SPACE", { metaKey: true }); + check(aDescription + "Meta+Backspace", true, true, aIsReadonly); + + reset(""); + synthesizeKey("VK_BACK_SPACE", { osKey: true }); + check(aDescription + "OS+Backspace", true, true, aIsReadonly); + + // Delete key: + // If editor is readonly, it doesn't consume. + // If editor is editable, delete is consumed. + // Otherwise, editor doesn't consume the event but the native key + // bindings on nsTextControlFrame may consume it. + reset(""); + synthesizeKey("VK_DELETE", { }); + // Linux: native handler + // Mac: cmd_deleteCharForward + check(aDescription + "Delete", + true, true, !aIsReadonly || kIsLinux || kIsMac); + + reset(""); + // Win: cmd_cutOrDelete + // Linux: cmd_cut + // Mac: cmd_deleteCharForward + synthesizeKey("VK_DELETE", { shiftKey: true }); + check(aDescription + "Shift+Delete", + true, true, true); + + reset(""); + synthesizeKey("VK_DELETE", { ctrlKey: true }); + // Win: cmd_deleteWordForward + // Linux: cmd_copy + check(aDescription + "Ctrl+Delete", + true, true, kIsWin || kIsLinux); + + reset(""); + synthesizeKey("VK_DELETE", { altKey: true }); + // Mac: cmd_deleteWordForward + check(aDescription + "Alt+Delete", + true, true, kIsMac); + + reset(""); + synthesizeKey("VK_DELETE", { metaKey: true }); + // Linux: native handler consumed. + check(aDescription + "Meta+Delete", + true, true, kIsLinux); + + reset(""); + synthesizeKey("VK_DELETE", { osKey: true }); + check(aDescription + "OS+Delete", + true, true, false); + + // XXX input.value returns "\n" when it's empty, so, we should use dummy + // value ("a") for the following tests. + + // Return key: + // If editor is readonly, it doesn't consume. + // If editor is editable and not single line editor, it consumes Return + // and Shift+Return. + // Otherwise, editor doesn't consume the event. + reset("a"); + synthesizeKey("VK_RETURN", { }); + check(aDescription + "Return", + true, true, !aIsSingleLine && !aIsReadonly); + is(aElement.value, !aIsSingleLine && !aIsReadonly ? "a\n" : "a", + aDescription + "Return"); + + reset("a"); + synthesizeKey("VK_RETURN", { shiftKey: true }); + check(aDescription + "Shift+Return", + true, true, !aIsSingleLine && !aIsReadonly); + is(aElement.value, !aIsSingleLine && !aIsReadonly ? "a\n" : "a", + aDescription + "Shift+Return"); + + reset("a"); + synthesizeKey("VK_RETURN", { ctrlKey: true }); + check(aDescription + "Ctrl+Return", true, true, false); + is(aElement.value, "a", aDescription + "Ctrl+Return"); + + reset("a"); + synthesizeKey("VK_RETURN", { altKey: true }); + check(aDescription + "Alt+Return", true, true, false); + is(aElement.value, "a", aDescription + "Alt+Return"); + + reset("a"); + synthesizeKey("VK_RETURN", { metaKey: true }); + check(aDescription + "Meta+Return", true, true, false); + is(aElement.value, "a", aDescription + "Meta+Return"); + + reset("a"); + synthesizeKey("VK_RETURN", { osKey: true }); + check(aDescription + "OS+Return", true, true, false); + is(aElement.value, "a", aDescription + "OS+Return"); + + // Tab key: + // If editor is tabbable, editor doesn't consume all tab key events. + // Otherwise, editor consumes tab key event without any modifier keys. + reset("a"); + synthesizeKey("VK_TAB", { }); + check(aDescription + "Tab", + true, true, !aIsTabbable && !aIsReadonly); + is(aElement.value, !aIsTabbable && !aIsReadonly ? "a\t" : "a", + aDescription + "Tab"); + is(SpecialPowers.unwrap(fm.focusedElement), aElement, + aDescription + "focus moved unexpectedly (Tab)"); + + // If the editor is not tabbable, make sure that it accepts tab characters + // even if it's empty. + if (!aIsTabbable && !aIsReadonly) { + reset(""); + synthesizeKey("VK_TAB", {}); + check(aDescription + "Tab on empty textarea", + true, true, !aIsReadonly); + is(aElement.value, "\t", aDescription + "Tab on empty textarea"); + is(SpecialPowers.unwrap(fm.focusedElement), aElement, + aDescription + "focus moved unexpectedly (Tab on empty textarea"); + } + + reset("a"); + synthesizeKey("VK_TAB", { shiftKey: true }); + check(aDescription + "Shift+Tab", true, true, false); + is(aElement.value, "a", aDescription + "Shift+Tab"); + is(SpecialPowers.unwrap(fm.focusedElement), aElement, + aDescription + "focus moved unexpectedly (Shift+Tab)"); + + // Ctrl+Tab should be consumed by tabbrowser at keydown, so, keypress + // event should never be fired. + reset("a"); + synthesizeKey("VK_TAB", { ctrlKey: true }); + check(aDescription + "Ctrl+Tab", false, false, false); + is(aElement.value, "a", aDescription + "Ctrl+Tab"); + is(SpecialPowers.unwrap(fm.focusedElement), aElement, + aDescription + "focus moved unexpectedly (Ctrl+Tab)"); + + reset("a"); + synthesizeKey("VK_TAB", { altKey: true }); + check(aDescription + "Alt+Tab", true, true, false); + is(aElement.value, "a", aDescription + "Alt+Tab"); + is(SpecialPowers.unwrap(fm.focusedElement), aElement, + aDescription + "focus moved unexpectedly (Alt+Tab)"); + + reset("a"); + synthesizeKey("VK_TAB", { metaKey: true }); + check(aDescription + "Meta+Tab", true, true, false); + is(aElement.value, "a", aDescription + "Meta+Tab"); + is(SpecialPowers.unwrap(fm.focusedElement), aElement, + aDescription + "focus moved unexpectedly (Meta+Tab)"); + + reset("a"); + synthesizeKey("VK_TAB", { osKey: true }); + check(aDescription + "OS+Tab", true, true, false); + is(aElement.value, "a", aDescription + "OS+Tab"); + is(SpecialPowers.unwrap(fm.focusedElement), aElement, + aDescription + "focus moved unexpectedly (OS+Tab)"); + + // Esc key: + // In all cases, esc key events are not consumed + reset("abc"); + synthesizeKey("VK_ESCAPE", { }); + check(aDescription + "Esc", true, true, false); + + reset("abc"); + synthesizeKey("VK_ESCAPE", { shiftKey: true }); + check(aDescription + "Shift+Esc", true, true, false); + + reset("abc"); + synthesizeKey("VK_ESCAPE", { ctrlKey: true }); + check(aDescription + "Ctrl+Esc", true, true, false); + + reset("abc"); + synthesizeKey("VK_ESCAPE", { altKey: true }); + check(aDescription + "Alt+Esc", true, true, false); + + reset("abc"); + synthesizeKey("VK_ESCAPE", { metaKey: true }); + check(aDescription + "Meta+Esc", true, true, false); + + reset("abc"); + synthesizeKey("VK_ESCAPE", { osKey: true }); + check(aDescription + "OS+Esc", true, true, false); + + // typical typing tests: + reset(""); + synthesizeKey("M", { shiftKey: true }); + check(aDescription + "M", true, true, !aIsReadonly); + synthesizeKey("o", { }); + check(aDescription + "o", true, true, !aIsReadonly); + synthesizeKey("z", { }); + check(aDescription + "z", true, true, !aIsReadonly); + synthesizeKey("i", { }); + check(aDescription + "i", true, true, !aIsReadonly); + synthesizeKey("l", { }); + check(aDescription + "l", true, true, !aIsReadonly); + synthesizeKey("l", { }); + check(aDescription + "l", true, true, !aIsReadonly); + synthesizeKey("a", { }); + check(aDescription + "a", true, true, !aIsReadonly); + synthesizeKey(" ", { }); + check(aDescription + "' '", true, true, !aIsReadonly); + is(aElement.value, !aIsReadonly ? "Mozilla " : "", + aDescription + "typed \"Mozilla \""); + } + + doTest(inputField, "<input type=\"text\">", true, false, true); + + inputField.setAttribute("readonly", "readonly"); + doTest(inputField, "<input type=\"text\" readonly>", true, true, true); + + doTest(passwordField, "<input type=\"password\">", true, false, true); + + passwordField.setAttribute("readonly", "readonly"); + doTest(passwordField, "<input type=\"password\" readonly>", true, true, true); + + doTest(textarea, "<textarea>", false, false, true); + + textarea.setAttribute("readonly", "readonly"); + doTest(textarea, "<textarea readonly>", false, true, true); + + // make non-tabbable plaintext editor + textarea.removeAttribute("readonly"); + const nsIPlaintextEditor = SpecialPowers.Ci.nsIPlaintextEditor; + const nsIDOMNSEditableElement = SpecialPowers.Ci.nsIDOMNSEditableElement; + var editor = SpecialPowers.wrap(textarea).editor; + var flags = editor.flags; + editor.flags = flags & ~(nsIPlaintextEditor.eEditorWidgetMask | + nsIPlaintextEditor.eEditorAllowInteraction); + doTest(textarea, "non-tabbable <textarea>", false, false, false); + + textarea.setAttribute("readonly", "readonly"); + doTest(textarea, "non-tabbable <textarea readonly>", false, true, false); + + editor.flags = flags; + + SpecialPowers.removeSystemEventListener(parentElement, "keypress", listener, + true); + SpecialPowers.removeSystemEventListener(parentElement, "keypress", listener, + false); + + SimpleTest.finish(); +} + +</script> +</body> + +</html> |