2011-08-12 02:58:40 -07:00
|
|
|
/* 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";
|
|
|
|
|
2011-08-17 05:35:35 -07:00
|
|
|
testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
|
|
|
|
testWin.addEventListener("load", function onWindowLoad() {
|
|
|
|
testWin.removeEventListener("load", onWindowLoad, false);
|
|
|
|
waitForFocus(initEditor, testWin);
|
|
|
|
}, false);
|
2011-08-12 02:58:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2011-10-12 05:52:45 -07:00
|
|
|
is(editor.getText(), "code-ed.. aitor", "Tab works");
|
2011-08-12 02:58:40 -07:00
|
|
|
|
|
|
|
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)");
|
|
|
|
|
2011-10-31 04:07:51 -07:00
|
|
|
testEclipseBug362107();
|
|
|
|
testBug687577();
|
2011-08-12 02:58:40 -07:00
|
|
|
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");
|
2011-10-12 05:52:45 -07:00
|
|
|
let chars = editor.getText().length;
|
2011-08-12 02:58:40 -07:00
|
|
|
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");
|
|
|
|
|
2011-10-12 05:52:45 -07:00
|
|
|
event = null;
|
2011-08-12 02:58:40 -07:00
|
|
|
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);
|
|
|
|
|
2011-10-12 05:52:45 -07:00
|
|
|
testClipboardEvents();
|
|
|
|
}
|
2011-08-12 02:58:40 -07:00
|
|
|
|
2011-10-12 05:52:45 -07:00
|
|
|
function testEnd()
|
|
|
|
{
|
2011-08-12 02:58:40 -07:00
|
|
|
editor.destroy();
|
|
|
|
ok(!editor.parentElement && !editor.editorElement, "destroy() works");
|
|
|
|
|
|
|
|
testWin.close();
|
|
|
|
|
|
|
|
testWin = testDoc = editor = null;
|
2011-08-15 08:38:53 -07:00
|
|
|
|
2011-08-17 05:35:35 -07:00
|
|
|
waitForFocus(finish, window);
|
2011-08-12 02:58:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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)");
|
|
|
|
}
|
|
|
|
|
2011-10-12 05:52:45 -07:00
|
|
|
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);
|
|
|
|
}
|
2011-10-31 04:07:51 -07:00
|
|
|
|
|
|
|
function testEclipseBug362107()
|
|
|
|
{
|
|
|
|
// Test for Eclipse Bug 362107:
|
|
|
|
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=362107
|
|
|
|
let OS = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
|
|
|
if (OS != "Linux") {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
editor.setText("line 1\nline 2\nline 3");
|
|
|
|
editor.setCaretOffset(16);
|
|
|
|
|
|
|
|
EventUtils.synthesizeKey("VK_UP", {ctrlKey: true}, testWin);
|
|
|
|
is(editor.getCaretOffset(), 7, "Ctrl-Up works");
|
|
|
|
|
|
|
|
EventUtils.synthesizeKey("VK_UP", {ctrlKey: true}, testWin);
|
|
|
|
is(editor.getCaretOffset(), 0, "Ctrl-Up works twice");
|
|
|
|
|
|
|
|
EventUtils.synthesizeKey("VK_DOWN", {ctrlKey: true}, testWin);
|
|
|
|
is(editor.getCaretOffset(), 13, "Ctrl-Down works");
|
|
|
|
|
|
|
|
EventUtils.synthesizeKey("VK_DOWN", {ctrlKey: true}, testWin);
|
|
|
|
is(editor.getCaretOffset(), 20, "Ctrl-Down works twice");
|
|
|
|
}
|
|
|
|
|
|
|
|
function testBug687577()
|
|
|
|
{
|
|
|
|
// Test for Mozilla Bug 687577:
|
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=687577
|
|
|
|
let OS = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
|
|
|
if (OS != "Linux") {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
editor.setText("line foobar 1\nline foobar 2\nline foobar 3");
|
|
|
|
editor.setCaretOffset(39);
|
|
|
|
|
|
|
|
EventUtils.synthesizeKey("VK_LEFT", {ctrlKey: true, shiftKey: true}, testWin);
|
|
|
|
let selection = editor.getSelection();
|
|
|
|
is(selection.start, 33, "select.start after Ctrl-Shift-Left");
|
|
|
|
is(selection.end, 39, "select.end after Ctrl-Shift-Left");
|
|
|
|
|
|
|
|
EventUtils.synthesizeKey("VK_UP", {ctrlKey: true, shiftKey: true}, testWin);
|
|
|
|
selection = editor.getSelection();
|
|
|
|
is(selection.start, 14, "select.start after Ctrl-Shift-Up");
|
|
|
|
is(selection.end, 39, "select.end after Ctrl-Shift-Up");
|
|
|
|
|
|
|
|
EventUtils.synthesizeKey("VK_UP", {ctrlKey: true, shiftKey: true}, testWin);
|
|
|
|
selection = editor.getSelection();
|
|
|
|
is(selection.start, 0, "select.start after Ctrl-Shift-Up (again)");
|
|
|
|
is(selection.end, 39, "select.end after Ctrl-Shift-Up (again)");
|
|
|
|
|
|
|
|
EventUtils.synthesizeKey("VK_DOWN", {ctrlKey: true, shiftKey: true}, testWin);
|
|
|
|
selection = editor.getSelection();
|
|
|
|
is(selection.start, 27, "select.start after Ctrl-Shift-Down");
|
|
|
|
is(selection.end, 39, "select.end after Ctrl-Shift-Down");
|
|
|
|
|
|
|
|
EventUtils.synthesizeKey("VK_DOWN", {ctrlKey: true, shiftKey: true}, testWin);
|
|
|
|
selection = editor.getSelection();
|
|
|
|
is(selection.start, 39, "select.start after Ctrl-Shift-Down (again)");
|
|
|
|
is(selection.end, 41, "select.end after Ctrl-Shift-Down (again)");
|
|
|
|
}
|