Bug 964939 - Allow clicking on autocomplete items for CSS source editor. r=pbrosset

This commit is contained in:
Brian Grinstead 2015-03-17 11:42:00 -04:00
Родитель 7d51c8230a
Коммит cd8796ecf9
5 изменённых файлов: 143 добавлений и 25 удалений

Просмотреть файл

@ -10,6 +10,7 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
const events = require("devtools/toolkit/event-emitter");
/**
* Autocomplete popup UI implementation.
@ -109,6 +110,8 @@ function AutocompletePopup(aDocument, aOptions = {})
this._list.addEventListener("keypress", this.onKeypress, false);
}
this._itemIdCounter = 0;
events.decorate(this);
}
exports.AutocompletePopup = AutocompletePopup;
@ -144,6 +147,8 @@ AutocompletePopup.prototype = {
if (this.autoSelect) {
this.selectFirstItem();
}
this.emit("popup-opened");
},
/**

Просмотреть файл

@ -104,11 +104,30 @@ function initializeAutoCompletion(ctx, options = {}) {
completer = new cssAutoCompleter({walker: options.walker});
}
function insertSelectedPopupItem() {
let autocompleteState = autocompleteMap.get(ed);
if (!popup || !popup.isOpen || !autocompleteState) {
return;
}
if (!autocompleteState.suggestionInsertedOnce && popup.selectedItem) {
autocompleteMap.get(ed).insertingSuggestion = true;
let {label, preLabel, text} = popup.selectedItem;
let cur = ed.getCursor();
ed.replaceText(text.slice(preLabel.length), cur, cur);
}
popup.hidePopup();
ed.emit("popup-hidden"); // This event is used in tests.
return true;
}
let popup = new AutocompletePopup(win.parent.document, {
position: "after_start",
fixedWidth: true,
theme: "auto",
autoSelect: true
autoSelect: true,
onClick: insertSelectedPopupItem
});
let cycle = (reverse) => {
@ -126,20 +145,8 @@ function initializeAutoCompletion(ctx, options = {}) {
"Shift-Tab": cycle.bind(null, true),
"Up": cycle.bind(null, true),
"Enter": () => {
if (popup && popup.isOpen) {
if (!autocompleteMap.get(ed).suggestionInsertedOnce) {
autocompleteMap.get(ed).insertingSuggestion = true;
let {label, preLabel, text} = popup.getItemAtIndex(0);
let cur = ed.getCursor();
ed.replaceText(text.slice(preLabel.length), cur, cur);
}
popup.hidePopup();
// This event is used in tests
ed.emit("popup-hidden");
return;
}
return CodeMirror.Pass;
let wasHandled = insertSelectedPopupItem();
return wasHandled ? true : CodeMirror.Pass;
}
};
let autoCompleteCallback = autoComplete.bind(null, ctx);

Просмотреть файл

@ -21,6 +21,7 @@ support-files =
helper_codemirror_runner.js
[browser_editor_autocomplete_basic.js]
[browser_editor_autocomplete_events.js]
[browser_editor_autocomplete_js.js]
[browser_editor_basic.js]
[browser_editor_cursor.js]

Просмотреть файл

@ -0,0 +1,62 @@
/* 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";
const {InspectorFront} = require("devtools/server/actors/inspector");
const AUTOCOMPLETION_PREF = "devtools.editor.autocomplete";
const TEST_URI = "data:text/html;charset=UTF-8,<html><body><b1></b1><b2></b2><body></html>";
add_task(function*() {
yield promiseTab(TEST_URI);
yield runTests();
});
function* runTests() {
let target = devtools.TargetFactory.forTab(gBrowser.selectedTab);
yield target.makeRemote();
let inspector = InspectorFront(target.client, target.form);
let walker = yield inspector.getWalker();
let {ed, win, edWin} = yield setup(null, {
autocomplete: true,
mode: Editor.modes.css,
autocompleteOpts: {walker: walker}
});
yield testMouse(ed, edWin);
yield testKeyboard(ed, edWin);
teardown(ed, win);
}
function* testKeyboard(ed, win) {
ed.focus();
ed.setText("b");
ed.setCursor({line: 1, ch: 1});
let popupOpened = ed.getAutocompletionPopup().once("popup-opened");
let autocompleteKey = Editor.keyFor("autocompletion", { noaccel: true }).toUpperCase();
EventUtils.synthesizeKey("VK_" + autocompleteKey, { ctrlKey: true }, win);
info ("Waiting for popup to be opened");
yield popupOpened;
EventUtils.synthesizeKey("VK_RETURN", { }, win);
is (ed.getText(), "b1", "Editor text has been updated");
}
function* testMouse(ed, win) {
ed.focus();
ed.setText("b");
ed.setCursor({line: 1, ch: 1});
let popupOpened = ed.getAutocompletionPopup().once("popup-opened");
let autocompleteKey = Editor.keyFor("autocompletion", { noaccel: true }).toUpperCase();
EventUtils.synthesizeKey("VK_" + autocompleteKey, { ctrlKey: true }, win);
info ("Waiting for popup to be opened");
yield popupOpened;
ed.getAutocompletionPopup()._list.firstChild.click();
is (ed.getText(), "b1", "Editor text has been updated");
}

Просмотреть файл

@ -14,32 +14,71 @@ SimpleTest.registerCleanupFunction(() => {
gDevTools.testing = false;
});
function setup(cb) {
/**
* Open a new tab at a URL and call a callback on load
*/
function addTab(aURL, aCallback) {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
content.location = aURL;
let tab = gBrowser.selectedTab;
let browser = gBrowser.getBrowserForTab(tab);
function onTabLoad() {
browser.removeEventListener("load", onTabLoad, true);
aCallback(browser, tab, browser.contentDocument);
}
browser.addEventListener("load", onTabLoad, true);
}
function promiseTab(aURL) {
return new Promise(resolve =>
addTab(aURL, resolve));
}
function setup(cb, additionalOpts = {}) {
cb = cb || function() {};
let def = promise.defer();
const opt = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
const url = "data:text/xml;charset=UTF-8,<?xml version='1.0'?>" +
const url = "data:application/vnd.mozilla.xul+xml;charset=UTF-8,<?xml version='1.0'?>" +
"<?xml-stylesheet href='chrome://global/skin/global.css'?>" +
"<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
" title='Editor' width='600' height='500'><box flex='1'/></window>";
let win = Services.ww.openWindow(null, url, "_blank", opt, null);
let opts = {
value: "Hello.",
lineNumbers: true,
foldGutter: true,
gutters: [ "CodeMirror-linenumbers", "breakpoints", "CodeMirror-foldgutter" ]
}
for (let o in additionalOpts) {
opts[o] = additionalOpts[o];
}
win.addEventListener("load", function onLoad() {
win.removeEventListener("load", onLoad, false);
waitForFocus(function () {
let box = win.document.querySelector("box");
let editor = new Editor({
value: "Hello.",
lineNumbers: true,
foldGutter: true,
gutters: [ "CodeMirror-linenumbers", "breakpoints", "CodeMirror-foldgutter" ]
});
let editor = new Editor(opts);
editor.appendTo(box)
.then(() => cb(editor, win))
.then(null, (err) => ok(false, err.message));
.then(() => {
def.resolve({
ed: editor,
win: win,
edWin: editor.container.contentWindow.wrappedJSObject
});
cb(editor, win);
}, err => ok(false, err.message));
}, win);
}, false);
return def.promise;
}
function ch(exp, act, label) {
@ -50,6 +89,10 @@ function ch(exp, act, label) {
function teardown(ed, win) {
ed.destroy();
win.close();
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
finish();
}