mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
399 lines
11 KiB
JavaScript
399 lines
11 KiB
JavaScript
/* vim: set ts=2 et sw=2 tw=80: */
|
|
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
Cu.import("resource:///modules/source-editor.jsm");
|
|
|
|
let testWin;
|
|
let testDoc;
|
|
let editor;
|
|
|
|
function test()
|
|
{
|
|
waitForExplicitFinish();
|
|
|
|
const windowUrl = "data:text/xml,<?xml version='1.0'?>" +
|
|
"<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
|
|
" title='test for bug 660784' width='600' height='500'><hbox flex='1'/></window>";
|
|
const windowFeatures = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
|
|
|
|
testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
|
|
testWin.addEventListener("load", function onWindowLoad() {
|
|
testWin.removeEventListener("load", onWindowLoad, false);
|
|
waitForFocus(initEditor, testWin);
|
|
}, false);
|
|
}
|
|
|
|
function initEditor()
|
|
{
|
|
testDoc = testWin.document;
|
|
|
|
let hbox = testDoc.querySelector("hbox");
|
|
|
|
editor = new SourceEditor();
|
|
let config = {
|
|
showLineNumbers: true,
|
|
placeholderText: "foobarbaz",
|
|
tabSize: 7,
|
|
expandTab: true,
|
|
};
|
|
|
|
editor.init(hbox, config, editorLoaded);
|
|
}
|
|
|
|
function editorLoaded()
|
|
{
|
|
ok(editor.editorElement, "editor loaded");
|
|
|
|
is(editor.parentElement, testDoc.querySelector("hbox"),
|
|
"parentElement is correct");
|
|
|
|
editor.focus();
|
|
|
|
is(editor.getMode(), SourceEditor.DEFAULTS.MODE, "default editor mode");
|
|
|
|
// Test general editing methods.
|
|
|
|
ok(!editor.canUndo(), "canUndo() works (nothing to undo), just loaded");
|
|
|
|
ok(!editor.readOnly, "editor is not read-only");
|
|
|
|
is(editor.getText(), "foobarbaz", "placeholderText works");
|
|
|
|
is(editor.getText().length, editor.getCharCount(),
|
|
"getCharCount() is correct");
|
|
|
|
is(editor.getText(3, 5), "ba", "getText() range works");
|
|
|
|
editor.setText("source-editor");
|
|
|
|
is(editor.getText(), "source-editor", "setText() works");
|
|
|
|
editor.setText("code", 0, 6);
|
|
|
|
is(editor.getText(), "code-editor", "setText() range works");
|
|
|
|
ok(editor.canUndo(), "canUndo() works (things to undo)");
|
|
ok(!editor.canRedo(), "canRedo() works (nothing to redo yet)");
|
|
|
|
editor.undo();
|
|
|
|
is(editor.getText(), "source-editor", "undo() works");
|
|
|
|
ok(editor.canRedo(), "canRedo() works (things to redo)");
|
|
|
|
editor.redo();
|
|
|
|
is(editor.getText(), "code-editor", "redo() works");
|
|
|
|
// Test selection methods.
|
|
|
|
editor.setSelection(0, 4);
|
|
|
|
is(editor.getSelectedText(), "code", "getSelectedText() works");
|
|
|
|
let selection = editor.getSelection();
|
|
ok(selection.start == 0 && selection.end == 4, "getSelection() works");
|
|
|
|
editor.dropSelection();
|
|
|
|
selection = editor.getSelection();
|
|
ok(selection.start == 4 && selection.end == 4, "dropSelection() works");
|
|
|
|
editor.setCaretOffset(7);
|
|
is(editor.getCaretOffset(), 7, "setCaretOffset() works");
|
|
|
|
// Test grouped changes.
|
|
|
|
editor.setText("foobar");
|
|
|
|
editor.startCompoundChange();
|
|
|
|
editor.setText("foo1");
|
|
editor.setText("foo2");
|
|
editor.setText("foo3");
|
|
|
|
editor.endCompoundChange();
|
|
|
|
is(editor.getText(), "foo3", "editor content is correct");
|
|
|
|
editor.undo();
|
|
is(editor.getText(), "foobar", "compound change undo() works");
|
|
|
|
editor.redo();
|
|
is(editor.getText(), "foo3", "compound change redo() works");
|
|
|
|
// Minimal keyboard usage tests.
|
|
|
|
ok(editor.hasFocus(), "editor has focus");
|
|
|
|
editor.setText("code-editor");
|
|
editor.setCaretOffset(7);
|
|
EventUtils.synthesizeKey(".", {}, testWin);
|
|
|
|
is(editor.getText(), "code-ed.itor", "focus() and typing works");
|
|
|
|
EventUtils.synthesizeKey("a", {}, testWin);
|
|
|
|
is(editor.getText(), "code-ed.aitor", "typing works");
|
|
|
|
is(editor.getCaretOffset(), 9, "caret moved");
|
|
|
|
EventUtils.synthesizeKey("VK_LEFT", {}, testWin);
|
|
|
|
is(editor.getCaretOffset(), 8, "caret moved to the left");
|
|
|
|
EventUtils.synthesizeKey(".", {}, testWin);
|
|
EventUtils.synthesizeKey("VK_TAB", {}, testWin);
|
|
|
|
is(editor.getText(), "code-ed.. aitor", "Tab works");
|
|
|
|
is(editor.getCaretOffset(), 14, "caret location is correct");
|
|
|
|
// Test the Tab key.
|
|
|
|
editor.setText("a\n b\n c");
|
|
editor.setCaretOffset(0);
|
|
|
|
EventUtils.synthesizeKey("VK_TAB", {}, testWin);
|
|
is(editor.getText(), " a\n b\n c", "Tab works");
|
|
|
|
// Code editor specific tests. These are not applicable when the textarea
|
|
// fallback is used.
|
|
let component = Services.prefs.getCharPref(SourceEditor.PREFS.COMPONENT);
|
|
if (component != "textarea") {
|
|
editor.setMode(SourceEditor.MODES.JAVASCRIPT);
|
|
is(editor.getMode(), SourceEditor.MODES.JAVASCRIPT, "setMode() works");
|
|
|
|
editor.setSelection(0, editor.getCharCount() - 1);
|
|
EventUtils.synthesizeKey("VK_TAB", {}, testWin);
|
|
is(editor.getText(), " a\n b\n c", "lines indented");
|
|
|
|
EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}, testWin);
|
|
is(editor.getText(), " a\n b\n c", "lines outdented (shift-tab)");
|
|
|
|
testBackspaceKey();
|
|
testReturnKey();
|
|
}
|
|
|
|
// Test the read-only mode.
|
|
|
|
editor.setText("foofoo");
|
|
|
|
editor.readOnly = true;
|
|
EventUtils.synthesizeKey("b", {}, testWin);
|
|
is(editor.getText(), "foofoo", "editor is now read-only (keyboard)");
|
|
|
|
editor.setText("foobar");
|
|
is(editor.getText(), "foobar", "editor allows programmatic changes (setText)");
|
|
|
|
editor.readOnly = false;
|
|
|
|
editor.setCaretOffset(editor.getCharCount());
|
|
EventUtils.synthesizeKey("-", {}, testWin);
|
|
is(editor.getText(), "foobar-", "editor is now editable again");
|
|
|
|
// Test the Selection event.
|
|
|
|
editor.setText("foobarbaz");
|
|
|
|
editor.setSelection(1, 4);
|
|
|
|
let event = null;
|
|
|
|
let eventHandler = function(aEvent) {
|
|
event = aEvent;
|
|
};
|
|
editor.addEventListener(SourceEditor.EVENTS.SELECTION, eventHandler);
|
|
|
|
editor.setSelection(0, 3);
|
|
|
|
ok(event, "selection event fired");
|
|
ok(event.oldValue.start == 1 && event.oldValue.end == 4,
|
|
"event.oldValue is correct");
|
|
ok(event.newValue.start == 0 && event.newValue.end == 3,
|
|
"event.newValue is correct");
|
|
|
|
event = null;
|
|
editor.dropSelection();
|
|
|
|
ok(event, "selection dropped");
|
|
ok(event.oldValue.start == 0 && event.oldValue.end == 3,
|
|
"event.oldValue is correct");
|
|
ok(event.newValue.start == 3 && event.newValue.end == 3,
|
|
"event.newValue is correct");
|
|
|
|
event = null;
|
|
EventUtils.synthesizeKey("a", {accelKey: true}, testWin);
|
|
|
|
ok(event, "select all worked");
|
|
ok(event.oldValue.start == 3 && event.oldValue.end == 3,
|
|
"event.oldValue is correct");
|
|
ok(event.newValue.start == 0 && event.newValue.end == 9,
|
|
"event.newValue is correct");
|
|
|
|
event = null;
|
|
editor.removeEventListener(SourceEditor.EVENTS.SELECTION, eventHandler);
|
|
editor.dropSelection();
|
|
|
|
ok(!event, "selection event listener removed");
|
|
|
|
// Test the TextChanged event.
|
|
|
|
editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, eventHandler);
|
|
|
|
EventUtils.synthesizeKey(".", {}, testWin);
|
|
|
|
ok(event, "the TextChanged event fired after keypress");
|
|
is(event.start, 9, "event.start is correct");
|
|
is(event.removedCharCount, 0, "event.removedCharCount is correct");
|
|
is(event.addedCharCount, 1, "event.addedCharCount is correct");
|
|
|
|
editor.setText("line1\nline2\nline3");
|
|
let chars = editor.getText().length;
|
|
event = null;
|
|
|
|
editor.setText("a\nline4\nline5", chars);
|
|
|
|
ok(event, "the TextChanged event fired after setText()");
|
|
is(event.start, chars, "event.start is correct");
|
|
is(event.removedCharCount, 0, "event.removedCharCount is correct");
|
|
is(event.addedCharCount, 13, "event.addedCharCount is correct");
|
|
|
|
event = null;
|
|
editor.setText("line3b\nline4b\nfoo", 12, 24);
|
|
|
|
ok(event, "the TextChanged event fired after setText() again");
|
|
is(event.start, 12, "event.start is correct");
|
|
is(event.removedCharCount, 12, "event.removedCharCount is correct");
|
|
is(event.addedCharCount, 17, "event.addedCharCount is correct");
|
|
|
|
editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED, eventHandler);
|
|
|
|
testClipboardEvents();
|
|
}
|
|
|
|
function testEnd()
|
|
{
|
|
editor.destroy();
|
|
ok(!editor.parentElement && !editor.editorElement, "destroy() works");
|
|
|
|
testWin.close();
|
|
|
|
testWin = testDoc = editor = null;
|
|
|
|
waitForFocus(finish, window);
|
|
}
|
|
|
|
function testBackspaceKey()
|
|
{
|
|
editor.setText(" a\n b\n c");
|
|
editor.setCaretOffset(7);
|
|
EventUtils.synthesizeKey("VK_BACK_SPACE", {}, testWin);
|
|
is(editor.getText(), "a\n b\n c", "line outdented (Backspace)");
|
|
|
|
editor.undo();
|
|
|
|
editor.setCaretOffset(6);
|
|
EventUtils.synthesizeKey("VK_BACK_SPACE", {}, testWin);
|
|
is(editor.getText(), " a\n b\n c", "backspace one char works");
|
|
}
|
|
|
|
function testReturnKey()
|
|
{
|
|
editor.setText(" a\n b\n c");
|
|
|
|
editor.setCaretOffset(8);
|
|
EventUtils.synthesizeKey("VK_RETURN", {}, testWin);
|
|
EventUtils.synthesizeKey("x", {}, testWin);
|
|
|
|
let lineDelimiter = editor.getLineDelimiter();
|
|
ok(lineDelimiter, "we have the line delimiter");
|
|
|
|
is(editor.getText(), " a" + lineDelimiter + " x\n b\n c",
|
|
"return maintains indentation");
|
|
|
|
editor.setCaretOffset(12 + lineDelimiter.length);
|
|
EventUtils.synthesizeKey("z", {}, testWin);
|
|
EventUtils.synthesizeKey("VK_RETURN", {}, testWin);
|
|
EventUtils.synthesizeKey("y", {}, testWin);
|
|
is(editor.getText(), " a" + lineDelimiter +
|
|
" z" + lineDelimiter + " yx\n b\n c",
|
|
"return maintains indentation (again)");
|
|
}
|
|
|
|
function testClipboardEvents()
|
|
{
|
|
editor.setText("foobar");
|
|
|
|
let doCut = function() {
|
|
EventUtils.synthesizeKey("a", {accelKey: true}, testWin);
|
|
|
|
is(editor.getSelectedText(), "foobar", "select all worked");
|
|
|
|
EventUtils.synthesizeKey("x", {accelKey: true}, testWin);
|
|
};
|
|
|
|
let onCut = function() {
|
|
ok(!editor.getText(), "cut works");
|
|
editor.setText("test--");
|
|
editor.setCaretOffset(5);
|
|
|
|
editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onPaste1);
|
|
EventUtils.synthesizeKey("v", {accelKey: true}, testWin);
|
|
};
|
|
|
|
let onPaste1 = function() {
|
|
editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onPaste1);
|
|
|
|
is(editor.getText(), "test-foobar-", "paste works");
|
|
|
|
executeSoon(waitForClipboard.bind(this, "test", doCopy, onCopy, testEnd));
|
|
};
|
|
|
|
let doCopy = function() {
|
|
editor.setSelection(0, 4);
|
|
EventUtils.synthesizeKey("c", {accelKey: true}, testWin);
|
|
};
|
|
|
|
let onCopy = function() {
|
|
editor.setSelection(5, 11);
|
|
editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onPaste2);
|
|
EventUtils.synthesizeKey("v", {accelKey: true}, testWin);
|
|
};
|
|
|
|
let pasteTextChanges = 0;
|
|
let removedCharCount = 0;
|
|
let addedCharCount = 0;
|
|
let onPaste2 = function(aEvent) {
|
|
pasteTextChanges++;
|
|
ok(aEvent && (pasteTextChanges == 1 || pasteTextChanges == 2),
|
|
"event TEXT_CHANGED fired " + pasteTextChanges + " time(s)");
|
|
|
|
is(aEvent.start, 5, "event.start is correct");
|
|
if (aEvent.removedCharCount) {
|
|
removedCharCount = aEvent.removedCharCount;
|
|
}
|
|
if (aEvent.addedCharCount) {
|
|
addedCharCount = aEvent.addedCharCount;
|
|
}
|
|
|
|
if (pasteTextChanges == 2 || addedCharCount && removedCharCount) {
|
|
editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onPaste2);
|
|
executeSoon(checkPaste2Result);
|
|
}
|
|
};
|
|
|
|
let checkPaste2Result = function() {
|
|
is(removedCharCount, 6, "event.removedCharCount is correct");
|
|
is(addedCharCount, 4, "event.addedCharCount is correct");
|
|
|
|
is(editor.getText(), "test-test-", "paste works after copy");
|
|
testEnd();
|
|
};
|
|
|
|
waitForClipboard("foobar", doCut, onCut, testEnd);
|
|
}
|