зеркало из https://github.com/mozilla/gecko-dev.git
Bug 964939 - Allow clicking on autocomplete items for CSS source editor. r=pbrosset
This commit is contained in:
Родитель
7d51c8230a
Коммит
cd8796ecf9
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче