зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
67945694c1
|
@ -39,7 +39,6 @@ support-files =
|
|||
file_bug1045809_1.html
|
||||
file_bug1045809_2.html
|
||||
[browser_csp_block_all_mixedcontent.js]
|
||||
skip-if = (verify && debug && (os == 'mac')) || (os == 'linux') || (os == 'mac') # Bug 1438402
|
||||
tags = mcb
|
||||
support-files =
|
||||
file_csp_block_all_mixedcontent.html
|
||||
|
|
|
@ -38,8 +38,8 @@ function runTests() {
|
|||
newTab.linkedBrowser.stop();
|
||||
|
||||
// Starting the test
|
||||
BrowserTestUtils.browserLoaded(gTestBrowser).then(verifyUInotDegraded);
|
||||
var url = PRE_PATH + "file_csp_block_all_mixedcontent.html";
|
||||
BrowserTestUtils.browserLoaded(gTestBrowser, false, url).then(verifyUInotDegraded);
|
||||
gTestBrowser.loadURI(url);
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,8 @@ devtools.jar:
|
|||
skin/tooltips.css (themes/tooltips.css)
|
||||
skin/images/accessibility.svg (themes/images/accessibility.svg)
|
||||
skin/images/add.svg (themes/images/add.svg)
|
||||
skin/images/arrowhead-down.svg (themes/images/arrowhead-down.svg)
|
||||
skin/images/arrowhead-up.svg (themes/images/arrowhead-up.svg)
|
||||
skin/images/breadcrumbs-divider.svg (themes/images/breadcrumbs-divider.svg)
|
||||
skin/images/filters.svg (themes/images/filters.svg)
|
||||
skin/images/filter-swatch.svg (themes/images/filter-swatch.svg)
|
||||
|
|
|
@ -285,3 +285,35 @@ webconsole.closeSplitConsoleButton.tooltip=Close Split Console (Esc)
|
|||
# LOCALIZATION NOTE (webconsole.closeSidebarButton.tooltip): This is the tooltip for
|
||||
# the close button of the sidebar.
|
||||
webconsole.closeSidebarButton.tooltip=Close Sidebar
|
||||
|
||||
# LOCALIZATION NOTE (webconsole.reverseSearch.input.placeHolder):
|
||||
# This string is displayed in the placeholder of the reverse search input in the console.
|
||||
webconsole.reverseSearch.input.placeHolder=Search history
|
||||
|
||||
# LOCALIZATION NOTE (webconsole.reverseSearch.result.closeButton.tooltip):
|
||||
# This string is displayed in the tooltip of the close button in the reverse search toolbar.
|
||||
# A keyboard shortcut will be shown inside the latter pair of brackets.
|
||||
webconsole.reverseSearch.closeButton.tooltip=Close (%S)
|
||||
|
||||
# LOCALIZATION NOTE (webconsole.reverseSearch.results):
|
||||
# This string is displayed in the reverse search UI when there are at least one result
|
||||
# to the search.
|
||||
# This is a semi-colon list of plural forms.
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# #1 index of current search result displayed.
|
||||
# #2 total number of search results.
|
||||
webconsole.reverseSearch.results=1 result;#1 of #2 results
|
||||
|
||||
# LOCALIZATION NOTE (webconsole.reverseSearch.noResult):
|
||||
# This string is displayed in the reverse search UI when there is no results to the search.
|
||||
webconsole.reverseSearch.noResult=No results
|
||||
|
||||
# LOCALIZATION NOTE (webconsole.reverseSearch.result.previousButton.tooltip):
|
||||
# This string is displayed in the tooltip of the "previous result" button in the reverse search toolbar.
|
||||
# A keyboard shortcut will be shown inside the latter pair of brackets.
|
||||
webconsole.reverseSearch.result.previousButton.tooltip=Previous result (%S)
|
||||
|
||||
# LOCALIZATION NOTE (webconsole.reverseSearch.result.nextButton.tooltip):
|
||||
# This string is displayed in the tooltip of the "next result" button in the reverse search toolbar.
|
||||
# A keyboard shortcut will be shown inside the latter pair of brackets.
|
||||
webconsole.reverseSearch.result.nextButton.tooltip=Next result (%S)
|
||||
|
|
|
@ -74,7 +74,7 @@ class CustomRequestPanel extends Component {
|
|||
* @return {array} array of headers info {name, value}
|
||||
*/
|
||||
parseRequestText(text, namereg, divider) {
|
||||
const regex = new RegExp(`(${namereg})\\${divider}\\s*(.+)`);
|
||||
const regex = new RegExp(`(${namereg})\\${divider}\\s*(\\S.*)`);
|
||||
const pairs = [];
|
||||
|
||||
for (const line of text.split("\n")) {
|
||||
|
|
|
@ -21,7 +21,7 @@ const { gDevTools } = require("devtools/client/framework/devtools");
|
|||
/**
|
||||
* Opens given request in a new tab.
|
||||
*/
|
||||
function openRequestInTab(url, requestPostData) {
|
||||
function openRequestInTab(url, requestHeaders, requestPostData) {
|
||||
const win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
|
||||
const rawData = requestPostData ? requestPostData.postData : null;
|
||||
let postData;
|
||||
|
@ -30,7 +30,13 @@ function openRequestInTab(url, requestPostData) {
|
|||
const stringStream = getInputStreamFromString(rawData.text);
|
||||
postData = Cc["@mozilla.org/network/mime-input-stream;1"]
|
||||
.createInstance(Ci.nsIMIMEInputStream);
|
||||
postData.addHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
|
||||
const contentTypeHeader = requestHeaders.headers.find(e => {
|
||||
return e.name.toLowerCase() === "content-type";
|
||||
});
|
||||
|
||||
postData.addHeader("Content-Type", contentTypeHeader ?
|
||||
contentTypeHeader.value : "application/x-www-form-urlencoded");
|
||||
postData.setData(stringStream);
|
||||
}
|
||||
const userContextId = win.gBrowser.contentPrincipal.userContextId;
|
||||
|
|
|
@ -18,8 +18,10 @@ loader.lazyRequireGetter(this, "openContentLink", "devtools/client/shared/link",
|
|||
|
||||
/**
|
||||
* Opens given request in a new tab.
|
||||
*
|
||||
* For POST request supports application/x-www-form-urlencoded content-type only.
|
||||
*/
|
||||
function openRequestInTab(url, requestPostData) {
|
||||
function openRequestInTab(url, requestHeaders, requestPostData) {
|
||||
if (!requestPostData) {
|
||||
openContentLink(url, {relatedToCurrent: true});
|
||||
} else {
|
||||
|
|
|
@ -193,7 +193,7 @@ class RequestListContextMenu {
|
|||
label: L10N.getStr("netmonitor.context.newTab"),
|
||||
accesskey: L10N.getStr("netmonitor.context.newTab.accesskey"),
|
||||
visible: !!selectedRequest,
|
||||
click: () => this.openRequestInTab(id, url, requestPostData),
|
||||
click: () => this.openRequestInTab(id, url, requestHeaders, requestPostData),
|
||||
});
|
||||
|
||||
menu.push({
|
||||
|
@ -231,10 +231,14 @@ class RequestListContextMenu {
|
|||
/**
|
||||
* Opens selected item in a new tab.
|
||||
*/
|
||||
async openRequestInTab(id, url, requestPostData) {
|
||||
async openRequestInTab(id, url, requestHeaders, requestPostData) {
|
||||
requestHeaders = requestHeaders ||
|
||||
await this.props.connector.requestData(id, "requestHeaders");
|
||||
|
||||
requestPostData = requestPostData ||
|
||||
await this.props.connector.requestData(id, "requestPostData");
|
||||
openRequestInTab(url, requestPostData);
|
||||
|
||||
openRequestInTab(url, requestHeaders, requestPostData);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,14 +24,19 @@ add_task(async function() {
|
|||
|
||||
// Open GET request in new tab
|
||||
await performRequest("GET");
|
||||
|
||||
newTab = await openLastRequestInTab();
|
||||
await checkTabResponse(newTab, "GET");
|
||||
|
||||
// Open POST request in new tab
|
||||
await performRequest("POST");
|
||||
await performRequest("POST", "application/x-www-form-urlencoded", "foo=bar&baz=42");
|
||||
newTab = await openLastRequestInTab();
|
||||
await checkTabResponse(newTab, "POST");
|
||||
await checkTabResponse(newTab, "POST", "application/x-www-form-urlencoded",
|
||||
"foo=bar&baz=42");
|
||||
|
||||
// Open POST application/json request in new tab
|
||||
await performRequest("POST", "application/json", '{"foo":"bar"}');
|
||||
newTab = await openLastRequestInTab();
|
||||
await checkTabResponse(newTab, "POST", "application/json", '{"foo":"bar"}');
|
||||
|
||||
await teardown(monitor);
|
||||
|
||||
|
@ -49,7 +54,7 @@ add_task(async function() {
|
|||
monitor.panelWin.parent.document
|
||||
.querySelector("#request-list-context-newtab").click();
|
||||
await onTabOpen;
|
||||
ok(true, "A new tab has been opened");
|
||||
info("A new tab has been opened");
|
||||
|
||||
const awaitedTab = gBrowser.selectedTab;
|
||||
await BrowserTestUtils.browserLoaded(awaitedTab.linkedBrowser);
|
||||
|
@ -58,20 +63,26 @@ add_task(async function() {
|
|||
return awaitedTab;
|
||||
}
|
||||
|
||||
async function performRequest(method) {
|
||||
async function performRequest(method, contentType, payload) {
|
||||
const wait = waitForNetworkEvents(monitor, 1);
|
||||
await ContentTask.spawn(tab.linkedBrowser, method, async function(meth) {
|
||||
content.wrappedJSObject.performRequest(meth);
|
||||
});
|
||||
await ContentTask.spawn(tab.linkedBrowser, [method, contentType, payload],
|
||||
async function([method_, contentType_, payload_]) {
|
||||
content.wrappedJSObject.performRequest(method_, contentType_, payload_);
|
||||
}
|
||||
);
|
||||
await wait;
|
||||
info("Performed request to test server");
|
||||
}
|
||||
|
||||
async function checkTabResponse(checkedTab, method) {
|
||||
await ContentTask.spawn(checkedTab.linkedBrowser, method, async function(met) {
|
||||
const { body } = content.wrappedJSObject.document;
|
||||
const responseRE =
|
||||
RegExp(met + (met == "POST" ? "\n*\s*foo\=bar\&baz\=42" : ""));
|
||||
ok(body.innerHTML.match(responseRE), "Tab method and data match original request");
|
||||
});
|
||||
async function checkTabResponse(checkedTab, method, contentType, payload) {
|
||||
await ContentTask.spawn(checkedTab.linkedBrowser, [method, contentType, payload],
|
||||
async function([method_, contentType_, payload_]) {
|
||||
const { body } = content.wrappedJSObject.document;
|
||||
const expected = [method_, contentType_, payload_].join("\n");
|
||||
info("Response from the server:" + body.innerHTML.replace(/\n/g, "\\n"));
|
||||
ok(body.innerHTML.includes(expected),
|
||||
"Tab method and data match original request");
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -18,13 +18,15 @@ http://creativecommons.org/publicdomain/zero/1.0/ -->
|
|||
/* exported performRequest */
|
||||
"use strict";
|
||||
|
||||
function performRequest(method) {
|
||||
function performRequest(method, contentType, payload) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
const url = "sjs_method-test-server.sjs";
|
||||
const payload = method == "POST" ? "foo=bar&baz=42" : null;
|
||||
xhr.open(method, url, true);
|
||||
xhr.setRequestHeader("Accept-Language", window.navigator.language);
|
||||
xhr.send(payload);
|
||||
if (contentType) {
|
||||
xhr.setRequestHeader("Content-Type", contentType);
|
||||
}
|
||||
xhr.send(payload || "");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -11,7 +11,7 @@ function handleRequest(request, response) {
|
|||
response.setStatusLine(request.httpVersion, 200, "Och Aye");
|
||||
response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
|
||||
|
||||
var body = request.method + "\n" ;
|
||||
var body = "";
|
||||
if (request.method == "POST") {
|
||||
var bodyStream = new BinaryInputStream(request.bodyInputStream);
|
||||
var bytes = [], avail = 0;
|
||||
|
@ -19,6 +19,8 @@ function handleRequest(request, response) {
|
|||
body += String.fromCharCode.apply(String, bodyStream.readByteArray(avail));
|
||||
}
|
||||
}
|
||||
var contentType = request.hasHeader("content-type") ? request.getHeader("content-type") : ""
|
||||
var bodyOutput = [request.method, contentType, body].join("\n");
|
||||
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
response.bodyOutputStream.write(bodyOutput, bodyOutput.length);
|
||||
}
|
||||
|
|
|
@ -290,6 +290,13 @@ pref("devtools.webconsole.jsterm.codeMirror", true);
|
|||
pref("devtools.webconsole.jsterm.codeMirror", false);
|
||||
#endif
|
||||
|
||||
// Enable console input reverse-search in Nightly builds
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
pref("devtools.webconsole.jsterm.reverse-search", true);
|
||||
#else
|
||||
pref("devtools.webconsole.jsterm.reverse-search", false);
|
||||
#endif
|
||||
|
||||
// Disable the new performance recording panel by default
|
||||
pref("devtools.performance.new-panel-enabled", false);
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="context-fill #0C0C0D" fill-rule="evenodd" clip-rule="evenodd" d="M4.293 8.293a1 1 0 0 1 1.414 0L12 14.586l6.293-6.293a1 1 0 1 1 1.414 1.414l-7 7a1 1 0 0 1-1.414 0l-7-7a1 1 0 0 1 0-1.414z"></path>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 525 B |
|
@ -0,0 +1,6 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="context-fill #0C0C0D" fill-rule="evenodd" clip-rule="evenodd" d="M12.707 7.293a1 1 0 0 0-1.414 0l-7 7a1 1 0 0 0 1.414 1.414L12 9.414l6.293 6.293a1 1 0 0 0 1.414-1.414l-7-7z"></path>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 511 B |
|
@ -1,6 +1,6 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#aaa">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="context-fill #aaa">
|
||||
<path d="M10.716 10.032C11.516 9.077 12 7.845 12 6.5 12 3.462 9.538 1 6.5 1S1 3.462 1 6.5 3.462 12 6.5 12c1.345 0 2.577-.483 3.532-1.284l4.143 4.142c.19.19.495.19.683 0 .19-.188.19-.494 0-.683l-4.142-4.143zM6.5 11C8.985 11 11 8.985 11 6.5S8.985 2 6.5 2 2 4.015 2 6.5 4.015 11 6.5 11z" fill-rule="evenodd"/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 624 B После Ширина: | Высота: | Размер: 637 B |
|
@ -882,6 +882,7 @@ body {
|
|||
min-height: 28px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.jsterm-cm .jsterm-input-container {
|
||||
|
@ -892,11 +893,6 @@ body {
|
|||
border-top: none;
|
||||
}
|
||||
|
||||
/* Last item in the flex wrapper should take the whole remaining height */
|
||||
.webconsole-flex-wrapper > :last-child {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
/* Object Inspector */
|
||||
.webconsole-output-wrapper .object-inspector.tree {
|
||||
display: inline-block;
|
||||
|
|
|
@ -11,6 +11,9 @@ const {
|
|||
CLEAR_HISTORY,
|
||||
HISTORY_LOADED,
|
||||
UPDATE_HISTORY_POSITION,
|
||||
REVERSE_SEARCH_INPUT_CHANGE,
|
||||
REVERSE_SEARCH_BACK,
|
||||
REVERSE_SEARCH_NEXT,
|
||||
} = require("devtools/client/webconsole/constants");
|
||||
|
||||
/**
|
||||
|
@ -57,9 +60,31 @@ function updateHistoryPosition(direction, expression) {
|
|||
};
|
||||
}
|
||||
|
||||
function reverseSearchInputChange(value) {
|
||||
return {
|
||||
type: REVERSE_SEARCH_INPUT_CHANGE,
|
||||
value,
|
||||
};
|
||||
}
|
||||
|
||||
function showReverseSearchNext() {
|
||||
return {
|
||||
type: REVERSE_SEARCH_NEXT,
|
||||
};
|
||||
}
|
||||
|
||||
function showReverseSearchBack() {
|
||||
return {
|
||||
type: REVERSE_SEARCH_BACK
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
appendToHistory,
|
||||
clearHistory,
|
||||
historyLoaded,
|
||||
updateHistoryPosition,
|
||||
reverseSearchInputChange,
|
||||
showReverseSearchNext,
|
||||
showReverseSearchBack,
|
||||
};
|
||||
|
|
|
@ -14,14 +14,15 @@ const {
|
|||
INITIALIZE,
|
||||
PERSIST_TOGGLE,
|
||||
PREFS,
|
||||
REVERSE_SEARCH_INPUT_TOGGLE,
|
||||
SELECT_NETWORK_MESSAGE_TAB,
|
||||
SIDEBAR_CLOSE,
|
||||
SHOW_OBJECT_IN_SIDEBAR,
|
||||
TIMESTAMPS_TOGGLE,
|
||||
SIDEBAR_CLOSE,
|
||||
SPLIT_CONSOLE_CLOSE_BUTTON_TOGGLE,
|
||||
TIMESTAMPS_TOGGLE,
|
||||
} = require("devtools/client/webconsole/constants");
|
||||
|
||||
function filterBarToggle(show) {
|
||||
function filterBarToggle() {
|
||||
return (dispatch, getState, {prefsService}) => {
|
||||
dispatch({
|
||||
type: FILTER_BAR_TOGGLE,
|
||||
|
@ -31,7 +32,7 @@ function filterBarToggle(show) {
|
|||
};
|
||||
}
|
||||
|
||||
function persistToggle(show) {
|
||||
function persistToggle() {
|
||||
return (dispatch, getState, {prefsService}) => {
|
||||
dispatch({
|
||||
type: PERSIST_TOGGLE,
|
||||
|
@ -102,14 +103,21 @@ function showObjectInSidebar(grip) {
|
|||
};
|
||||
}
|
||||
|
||||
function reverseSearchInputToggle() {
|
||||
return {
|
||||
type: REVERSE_SEARCH_INPUT_TOGGLE
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
filterBarToggle,
|
||||
initialize,
|
||||
persistToggle,
|
||||
reverseSearchInputToggle,
|
||||
selectNetworkMessageTab,
|
||||
sidebarClose,
|
||||
showMessageObjectInSidebar,
|
||||
showObjectInSidebar,
|
||||
timestampsToggle,
|
||||
sidebarClose,
|
||||
splitConsoleCloseButtonToggle,
|
||||
timestampsToggle,
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const Services = require("Services");
|
||||
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
@ -12,6 +13,7 @@ const actions = require("devtools/client/webconsole/actions/index");
|
|||
const ConsoleOutput = createFactory(require("devtools/client/webconsole/components/ConsoleOutput"));
|
||||
const FilterBar = createFactory(require("devtools/client/webconsole/components/FilterBar"));
|
||||
const SideBar = createFactory(require("devtools/client/webconsole/components/SideBar"));
|
||||
const ReverseSearchInput = createFactory(require("devtools/client/webconsole/components/ReverseSearchInput"));
|
||||
const JSTerm = createFactory(require("devtools/client/webconsole/components/JSTerm"));
|
||||
const NotificationBox = createFactory(require("devtools/client/shared/components/NotificationBox").NotificationBox);
|
||||
|
||||
|
@ -27,8 +29,8 @@ const {
|
|||
} = require("devtools/client/shared/components/NotificationBox");
|
||||
|
||||
const { getAllNotifications } = require("devtools/client/webconsole/selectors/notifications");
|
||||
|
||||
const { div } = dom;
|
||||
const isMacOS = Services.appinfo.OS === "Darwin";
|
||||
|
||||
/**
|
||||
* Console root Application component.
|
||||
|
@ -44,13 +46,87 @@ class App extends Component {
|
|||
serviceContainer: PropTypes.object.isRequired,
|
||||
closeSplitConsole: PropTypes.func.isRequired,
|
||||
jstermCodeMirror: PropTypes.bool,
|
||||
jstermReverseSearch: PropTypes.bool,
|
||||
currentReverseSearchEntry: PropTypes.string,
|
||||
reverseSearchInputVisible: PropTypes.bool,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.onPaste = this.onPaste.bind(this);
|
||||
this.onKeyDown = this.onKeyDown.bind(this);
|
||||
}
|
||||
|
||||
onKeyDown(event) {
|
||||
const {
|
||||
dispatch,
|
||||
jstermReverseSearch,
|
||||
} = this.props;
|
||||
|
||||
if (
|
||||
jstermReverseSearch && (
|
||||
(!isMacOS && event.key === "F9") ||
|
||||
(isMacOS && event.key === "r" && event.ctrlKey === true)
|
||||
)
|
||||
) {
|
||||
dispatch(actions.reverseSearchInputToggle());
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
onClick(event) {
|
||||
const target = event.originalTarget || event.target;
|
||||
const {
|
||||
reverseSearchInputVisible,
|
||||
dispatch,
|
||||
hud,
|
||||
} = this.props;
|
||||
|
||||
if (reverseSearchInputVisible === true && !target.closest(".reverse-search")) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
dispatch(actions.reverseSearchInputToggle());
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not focus on middle/right-click or 2+ clicks.
|
||||
if (event.detail !== 1 || event.button !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not focus if a link was clicked
|
||||
if (target.closest("a")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not focus if an input field was clicked
|
||||
if (target.closest("input")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not focus if the click happened in the reverse search toolbar.
|
||||
if (target.closest(".reverse-search")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not focus if something other than the output region was clicked
|
||||
// (including e.g. the clear messages button in toolbar)
|
||||
if (!target.closest(".webconsole-output-wrapper")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not focus if something is selected
|
||||
const selection = hud.document.defaultView.getSelection();
|
||||
if (selection && !selection.isCollapsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hud && hud.jsterm) {
|
||||
hud.jsterm.focus();
|
||||
}
|
||||
}
|
||||
|
||||
onPaste(event) {
|
||||
|
@ -123,6 +199,7 @@ class App extends Component {
|
|||
serviceContainer,
|
||||
closeSplitConsole,
|
||||
jstermCodeMirror,
|
||||
jstermReverseSearch,
|
||||
} = this.props;
|
||||
|
||||
const classNames = ["webconsole-output-wrapper"];
|
||||
|
@ -134,12 +211,15 @@ class App extends Component {
|
|||
// from the following parts:
|
||||
// * FilterBar - Buttons & free text for content filtering
|
||||
// * Content - List of logs & messages
|
||||
// * SideBar - Object inspector
|
||||
// * NotificationBox - Notifications for JSTerm (self-xss warning at the moment)
|
||||
// * JSTerm - Input command line.
|
||||
// * ReverseSearchInput - Reverse search input.
|
||||
// * SideBar - Object inspector
|
||||
return (
|
||||
div({
|
||||
className: classNames.join(" "),
|
||||
onKeyDown: this.onKeyDown,
|
||||
onClick: this.onClick,
|
||||
ref: node => {
|
||||
this.node = node;
|
||||
}},
|
||||
|
@ -165,6 +245,11 @@ class App extends Component {
|
|||
onPaste: this.onPaste,
|
||||
codeMirrorEnabled: jstermCodeMirror,
|
||||
}),
|
||||
jstermReverseSearch
|
||||
? ReverseSearchInput({
|
||||
hud,
|
||||
})
|
||||
: null
|
||||
),
|
||||
SideBar({
|
||||
serviceContainer,
|
||||
|
@ -176,6 +261,7 @@ class App extends Component {
|
|||
|
||||
const mapStateToProps = state => ({
|
||||
notifications: getAllNotifications(state),
|
||||
reverseSearchInputVisible: state.ui.reverseSearchInputVisible,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
|
|
@ -682,7 +682,10 @@ class JSTerm extends Component {
|
|||
* The new value to set.
|
||||
* @returns void
|
||||
*/
|
||||
setInputValue(newValue = "") {
|
||||
setInputValue(newValue) {
|
||||
newValue = newValue || "";
|
||||
this.lastInputValue = newValue;
|
||||
|
||||
if (this.props.codeMirrorEnabled) {
|
||||
if (this.editor) {
|
||||
// In order to get the autocomplete popup to work properly, we need to set the
|
||||
|
@ -710,9 +713,7 @@ class JSTerm extends Component {
|
|||
this.completeNode.value = "";
|
||||
}
|
||||
|
||||
this.lastInputValue = newValue;
|
||||
this.resizeInput();
|
||||
|
||||
this.emit("set-input-value");
|
||||
}
|
||||
|
||||
|
@ -1071,20 +1072,26 @@ class JSTerm extends Component {
|
|||
const {editor, inputNode} = this;
|
||||
const frameActor = this.getFrameActor(this.SELECTED_FRAME);
|
||||
|
||||
// Only complete if the selection is empty and the input value is not.
|
||||
const cursor = this.getSelectionStart();
|
||||
|
||||
// Complete if:
|
||||
// - The input is not empty
|
||||
// - AND there is not text selected
|
||||
// - AND the input or frameActor are different from previous completion
|
||||
// - AND there is not an alphanumeric (+ "_" and "$") right after the cursor
|
||||
if (
|
||||
!inputValue ||
|
||||
(inputNode && inputNode.selectionStart != inputNode.selectionEnd) ||
|
||||
(editor && editor.getSelection()) ||
|
||||
(this.lastInputValue === inputValue && frameActor === this._lastFrameActorId)
|
||||
(this.lastInputValue === inputValue && frameActor === this._lastFrameActorId) ||
|
||||
/^[a-zA-Z0-9_$]/.test(inputValue.substring(cursor))
|
||||
) {
|
||||
this.clearCompletion();
|
||||
this.emit("autocomplete-updated");
|
||||
return;
|
||||
}
|
||||
|
||||
const cursor = this.getSelectionStart();
|
||||
const input = inputValue.substring(0, cursor);
|
||||
const input = this.getInputValueBeforeCursor();
|
||||
|
||||
// If the current input starts with the previous input, then we already
|
||||
// have a list of suggestions and we just need to filter the cached
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
.reverse-search {
|
||||
display: flex;
|
||||
font-size: inherit;
|
||||
min-height: 26px;
|
||||
color: var(--theme-body-color);
|
||||
padding-block-start: 2px;
|
||||
align-items: baseline;
|
||||
border: 1px solid transparent;
|
||||
transition: border-color 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.reverse-search:focus-within {
|
||||
border-color: var(--blue-50);
|
||||
}
|
||||
|
||||
.reverse-search {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.reverse-search input {
|
||||
border: none;
|
||||
flex-grow: 1;
|
||||
padding-inline-start: var(--console-inline-start-gutter);
|
||||
background: transparent;
|
||||
color: currentColor;
|
||||
background-image: var(--magnifying-glass-image);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 12px 12px;
|
||||
background-position: 10px 2px;
|
||||
-moz-context-properties: fill;
|
||||
}
|
||||
|
||||
.reverse-search input:focus {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.reverse-search:not(.no-result) input:focus {
|
||||
fill: var(--console-input-icon-focused);
|
||||
}
|
||||
|
||||
.reverse-search-info {
|
||||
flex-shrink: 0;
|
||||
padding: 0 8px;
|
||||
color: var(--comment-node-color);
|
||||
}
|
||||
|
||||
.search-result-button-prev,
|
||||
.search-result-button-next,
|
||||
.reverse-search-close-button {
|
||||
padding: 4px 0;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.search-result-button-prev::before {
|
||||
background-image: url("chrome://devtools/skin/images/arrowhead-up.svg");
|
||||
background-size: 16px;
|
||||
fill: var(--comment-node-color);
|
||||
}
|
||||
|
||||
.search-result-button-next::before {
|
||||
background-image: url("chrome://devtools/skin/images/arrowhead-down.svg");
|
||||
background-size: 16px;
|
||||
fill: var(--comment-node-color);
|
||||
}
|
||||
|
||||
.reverse-search-close-button::before {
|
||||
fill: var(--comment-node-color);
|
||||
background-image: var(--close-button-image);
|
||||
}
|
||||
|
||||
.reverse-search.no-result input {
|
||||
fill: var(--error-color);
|
||||
}
|
||||
|
||||
.reverse-search.no-result,
|
||||
.reverse-search.no-result input {
|
||||
color: var(--error-color);
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// React & Redux
|
||||
const { Component } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const { l10n } = require("devtools/client/webconsole/utils/messages");
|
||||
const { PluralForm } = require("devtools/shared/plural-form");
|
||||
const { KeyCodes } = require("devtools/client/shared/keycodes");
|
||||
|
||||
const actions = require("devtools/client/webconsole/actions/index");
|
||||
const {
|
||||
getReverseSearchTotalResults,
|
||||
getReverseSearchResultPosition,
|
||||
getReverseSearchResult,
|
||||
} = require("devtools/client/webconsole/selectors/history");
|
||||
|
||||
const Services = require("Services");
|
||||
const isMacOS = Services.appinfo.OS === "Darwin";
|
||||
|
||||
class ReverseSearchInput extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
hud: PropTypes.object.isRequired,
|
||||
reverseSearchResult: PropTypes.string,
|
||||
reverseSearchTotalResults: PropTypes.Array,
|
||||
reverseSearchResultPosition: PropTypes.int,
|
||||
visible: PropTypes.bool,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onInputKeyDown = this.onInputKeyDown.bind(this);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {jsterm} = this.props.hud;
|
||||
if (
|
||||
prevProps.reverseSearchResult !== this.props.reverseSearchResult
|
||||
&& this.props.visible
|
||||
&& this.props.reverseSearchTotalResults > 0
|
||||
) {
|
||||
jsterm.setInputValue(this.props.reverseSearchResult);
|
||||
}
|
||||
|
||||
if (prevProps.visible === true && this.props.visible === false) {
|
||||
jsterm.focus();
|
||||
}
|
||||
}
|
||||
|
||||
onInputKeyDown(event) {
|
||||
const {
|
||||
keyCode,
|
||||
key,
|
||||
ctrlKey,
|
||||
shiftKey,
|
||||
} = event;
|
||||
|
||||
const {
|
||||
dispatch,
|
||||
hud,
|
||||
reverseSearchTotalResults,
|
||||
} = this.props;
|
||||
|
||||
// On Enter, we trigger an execute.
|
||||
if (keyCode === KeyCodes.DOM_VK_RETURN) {
|
||||
event.stopPropagation();
|
||||
dispatch(actions.reverseSearchInputToggle());
|
||||
hud.jsterm.execute();
|
||||
return;
|
||||
}
|
||||
|
||||
// On Escape (and Ctrl + c on OSX), we close the reverse search input.
|
||||
if (
|
||||
keyCode === KeyCodes.DOM_VK_ESCAPE || (
|
||||
isMacOS && ctrlKey === true && key.toLowerCase() === "c"
|
||||
)
|
||||
) {
|
||||
event.stopPropagation();
|
||||
dispatch(actions.reverseSearchInputToggle());
|
||||
return;
|
||||
}
|
||||
|
||||
const canNavigate = Number.isInteger(reverseSearchTotalResults)
|
||||
&& reverseSearchTotalResults > 1;
|
||||
|
||||
if (
|
||||
(!isMacOS && key === "F9" && shiftKey === false) ||
|
||||
(isMacOS && ctrlKey === true && key.toLowerCase() === "r")
|
||||
) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
if (canNavigate) {
|
||||
dispatch(actions.showReverseSearchBack());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(!isMacOS && key === "F9" && shiftKey === true) ||
|
||||
(isMacOS && ctrlKey === true && key.toLowerCase() === "s")
|
||||
) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
if (canNavigate) {
|
||||
dispatch(actions.showReverseSearchNext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderSearchInformation() {
|
||||
const {
|
||||
reverseSearchTotalResults,
|
||||
reverseSearchResultPosition,
|
||||
} = this.props;
|
||||
|
||||
if (!Number.isInteger(reverseSearchTotalResults)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let text;
|
||||
if (reverseSearchTotalResults === 0) {
|
||||
text = l10n.getStr("webconsole.reverseSearch.noResult");
|
||||
} else {
|
||||
const resultsString = l10n.getStr("webconsole.reverseSearch.results");
|
||||
text = PluralForm.get(reverseSearchTotalResults, resultsString)
|
||||
.replace("#1", reverseSearchResultPosition)
|
||||
.replace("#2", reverseSearchTotalResults);
|
||||
}
|
||||
|
||||
return dom.div({className: "reverse-search-info"}, text);
|
||||
}
|
||||
|
||||
renderNavigationButtons() {
|
||||
const {
|
||||
dispatch,
|
||||
reverseSearchTotalResults,
|
||||
} = this.props;
|
||||
|
||||
if (!Number.isInteger(reverseSearchTotalResults) || reverseSearchTotalResults <= 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
dom.button({
|
||||
className: "devtools-button search-result-button-prev",
|
||||
title: l10n.getFormatStr("webconsole.reverseSearch.result.previousButton.tooltip",
|
||||
[isMacOS ? "Ctrl + R" : "F9"]),
|
||||
onClick: () => {
|
||||
dispatch(actions.showReverseSearchBack());
|
||||
this.inputNode.focus();
|
||||
}
|
||||
}),
|
||||
dom.button({
|
||||
className: "devtools-button search-result-button-next",
|
||||
title: l10n.getFormatStr("webconsole.reverseSearch.result.nextButton.tooltip",
|
||||
[isMacOS ? "Ctrl + S" : "Shift + F9"]),
|
||||
onClick: () => {
|
||||
dispatch(actions.showReverseSearchNext());
|
||||
this.inputNode.focus();
|
||||
}
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
dispatch,
|
||||
visible,
|
||||
reverseSearchTotalResults,
|
||||
} = this.props;
|
||||
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const classNames = ["reverse-search"];
|
||||
if (reverseSearchTotalResults === 0) {
|
||||
classNames.push("no-result");
|
||||
}
|
||||
|
||||
return dom.div({className: classNames.join(" ")},
|
||||
dom.input({
|
||||
ref: node => {
|
||||
this.inputNode = node;
|
||||
},
|
||||
autoFocus: true,
|
||||
placeHolder: l10n.getStr("webconsole.reverseSearch.input.placeHolder"),
|
||||
className: "reverse-search-input devtools-monospace",
|
||||
onKeyDown: this.onInputKeyDown,
|
||||
onInput: ({target}) => dispatch(actions.reverseSearchInputChange(target.value))
|
||||
}),
|
||||
this.renderSearchInformation(),
|
||||
this.renderNavigationButtons(),
|
||||
dom.button({
|
||||
className: "devtools-button reverse-search-close-button",
|
||||
title: l10n.getFormatStr("webconsole.reverseSearch.closeButton.tooltip",
|
||||
["Esc" + (isMacOS ? " | Ctrl + C" : "")]),
|
||||
onClick: () => {
|
||||
dispatch(actions.reverseSearchInputToggle());
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
visible: state.ui.reverseSearchInputVisible,
|
||||
reverseSearchTotalResults: getReverseSearchTotalResults(state),
|
||||
reverseSearchResultPosition: getReverseSearchResultPosition(state),
|
||||
reverseSearchResult: getReverseSearchResult(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({dispatch});
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(ReverseSearchInput);
|
|
@ -22,5 +22,7 @@ DevToolsModules(
|
|||
'MessageIcon.js',
|
||||
'MessageIndent.js',
|
||||
'MessageRepeat.js',
|
||||
'ReverseSearchInput.css',
|
||||
'ReverseSearchInput.js',
|
||||
'SideBar.js'
|
||||
)
|
||||
|
|
|
@ -6,12 +6,16 @@
|
|||
"use strict";
|
||||
|
||||
const actionTypes = {
|
||||
APPEND_NOTIFICATION: "APPEND_NOTIFICATION",
|
||||
APPEND_TO_HISTORY: "APPEND_TO_HISTORY",
|
||||
BATCH_ACTIONS: "BATCH_ACTIONS",
|
||||
CLEAR_HISTORY: "CLEAR_HISTORY",
|
||||
DEFAULT_FILTERS_RESET: "DEFAULT_FILTERS_RESET",
|
||||
FILTER_BAR_TOGGLE: "FILTER_BAR_TOGGLE",
|
||||
FILTER_TEXT_SET: "FILTER_TEXT_SET",
|
||||
FILTER_TOGGLE: "FILTER_TOGGLE",
|
||||
FILTERS_CLEAR: "FILTERS_CLEAR",
|
||||
HISTORY_LOADED: "HISTORY_LOADED",
|
||||
INITIALIZE: "INITIALIZE",
|
||||
MESSAGE_CLOSE: "MESSAGE_CLOSE",
|
||||
MESSAGE_OPEN: "MESSAGE_OPEN",
|
||||
|
@ -22,18 +26,18 @@ const actionTypes = {
|
|||
NETWORK_UPDATE_REQUEST: "NETWORK_UPDATE_REQUEST",
|
||||
PERSIST_TOGGLE: "PERSIST_TOGGLE",
|
||||
PRIVATE_MESSAGES_CLEAR: "PRIVATE_MESSAGES_CLEAR",
|
||||
REMOVED_ACTORS_CLEAR: "REMOVED_ACTORS_CLEAR",
|
||||
SELECT_NETWORK_MESSAGE_TAB: "SELECT_NETWORK_MESSAGE_TAB",
|
||||
SIDEBAR_CLOSE: "SIDEBAR_CLOSE",
|
||||
SHOW_OBJECT_IN_SIDEBAR: "SHOW_OBJECT_IN_SIDEBAR",
|
||||
TIMESTAMPS_TOGGLE: "TIMESTAMPS_TOGGLE",
|
||||
APPEND_NOTIFICATION: "APPEND_NOTIFICATION",
|
||||
REMOVE_NOTIFICATION: "REMOVE_NOTIFICATION",
|
||||
REMOVED_ACTORS_CLEAR: "REMOVED_ACTORS_CLEAR",
|
||||
REVERSE_SEARCH_INPUT_TOGGLE: "REVERSE_SEARCH_INPUT_TOGGLE",
|
||||
SELECT_NETWORK_MESSAGE_TAB: "SELECT_NETWORK_MESSAGE_TAB",
|
||||
SHOW_OBJECT_IN_SIDEBAR: "SHOW_OBJECT_IN_SIDEBAR",
|
||||
SIDEBAR_CLOSE: "SIDEBAR_CLOSE",
|
||||
SPLIT_CONSOLE_CLOSE_BUTTON_TOGGLE: "SPLIT_CONSOLE_CLOSE_BUTTON_TOGGLE",
|
||||
APPEND_TO_HISTORY: "APPEND_TO_HISTORY",
|
||||
CLEAR_HISTORY: "CLEAR_HISTORY",
|
||||
HISTORY_LOADED: "HISTORY_LOADED",
|
||||
TIMESTAMPS_TOGGLE: "TIMESTAMPS_TOGGLE",
|
||||
UPDATE_HISTORY_POSITION: "UPDATE_HISTORY_POSITION",
|
||||
REVERSE_SEARCH_INPUT_CHANGE: "REVERSE_SEARCH_INPUT_CHANGE",
|
||||
REVERSE_SEARCH_NEXT: "REVERSE_SEARCH_NEXT",
|
||||
REVERSE_SEARCH_BACK: "REVERSE_SEARCH_BACK",
|
||||
};
|
||||
|
||||
const prefs = {
|
||||
|
@ -63,6 +67,7 @@ const prefs = {
|
|||
// We use the same pref to enable the sidebar on webconsole and browser console.
|
||||
SIDEBAR_TOGGLE: "devtools.webconsole.sidebarToggle",
|
||||
JSTERM_CODE_MIRROR: "devtools.webconsole.jsterm.codeMirror",
|
||||
JSTERM_REVERSE_SEARCH: "devtools.webconsole.jsterm.reverse-search",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/TabBar.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/NotificationBox.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/content/netmonitor/src/assets/styles/httpi.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/webconsole/components/ReverseSearchInput.css"/>
|
||||
|
||||
<script src="chrome://devtools/content/shared/theme-switching.js"></script>
|
||||
<script type="application/javascript"
|
||||
|
|
|
@ -12,6 +12,10 @@ const {
|
|||
UPDATE_HISTORY_POSITION,
|
||||
HISTORY_BACK,
|
||||
HISTORY_FORWARD,
|
||||
REVERSE_SEARCH_INPUT_TOGGLE,
|
||||
REVERSE_SEARCH_INPUT_CHANGE,
|
||||
REVERSE_SEARCH_BACK,
|
||||
REVERSE_SEARCH_NEXT,
|
||||
} = require("devtools/client/webconsole/constants");
|
||||
|
||||
/**
|
||||
|
@ -32,6 +36,10 @@ function getInitialState() {
|
|||
// pick up anything from the history and wants to return all
|
||||
// the way back to see the original input text.
|
||||
originalUserValue: null,
|
||||
|
||||
reverseSearchEnabled: false,
|
||||
currentReverseSearchResults: null,
|
||||
currentReverseSearchResultsPosition: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -45,6 +53,14 @@ function history(state = getInitialState(), action, prefsState) {
|
|||
return historyLoaded(state, action.entries);
|
||||
case UPDATE_HISTORY_POSITION:
|
||||
return updateHistoryPosition(state, action.direction, action.expression);
|
||||
case REVERSE_SEARCH_INPUT_TOGGLE:
|
||||
return reverseSearchInputToggle(state);
|
||||
case REVERSE_SEARCH_INPUT_CHANGE:
|
||||
return reverseSearchInputChange(state, action.value);
|
||||
case REVERSE_SEARCH_BACK:
|
||||
return reverseSearchBack(state);
|
||||
case REVERSE_SEARCH_NEXT:
|
||||
return reverseSearchNext(state);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
@ -127,4 +143,66 @@ function updateHistoryPosition(state, direction, expression) {
|
|||
return state;
|
||||
}
|
||||
|
||||
function reverseSearchInputToggle(state) {
|
||||
return {
|
||||
...state,
|
||||
reverseSearchEnabled: !state.reverseSearchEnabled,
|
||||
position: state.reverseSearchEnabled === true ? state.entries.length : undefined,
|
||||
currentReverseSearchResults: null,
|
||||
currentReverseSearchResultsPosition: null,
|
||||
};
|
||||
}
|
||||
|
||||
function reverseSearchInputChange(state, searchString) {
|
||||
if (searchString === "") {
|
||||
return {
|
||||
...state,
|
||||
position: undefined,
|
||||
currentReverseSearchResults: null,
|
||||
currentReverseSearchResultsPosition: null,
|
||||
};
|
||||
}
|
||||
|
||||
searchString = searchString.toLocaleLowerCase();
|
||||
const matchingEntries = state.entries.filter(entry =>
|
||||
entry.toLocaleLowerCase().includes(searchString));
|
||||
// We only return unique entries, but we want to keep the latest entry in the array if
|
||||
// it's duplicated (e.g. if we have [1,2,1], we want to get [2,1], not [1,2]).
|
||||
// To do that, we need to reverse the matching entries array, provide it to a Set,
|
||||
// transform it back to an array and reverse it again.
|
||||
const uniqueEntries = new Set(matchingEntries.reverse());
|
||||
const currentReverseSearchResults = Array.from(new Set(uniqueEntries)).reverse();
|
||||
|
||||
return {
|
||||
...state,
|
||||
position: undefined,
|
||||
currentReverseSearchResults,
|
||||
currentReverseSearchResultsPosition: currentReverseSearchResults.length - 1,
|
||||
};
|
||||
}
|
||||
|
||||
function reverseSearchBack(state) {
|
||||
let nextPosition = state.currentReverseSearchResultsPosition - 1;
|
||||
if (nextPosition < 0) {
|
||||
nextPosition = state.currentReverseSearchResults.length - 1;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
currentReverseSearchResultsPosition: nextPosition
|
||||
};
|
||||
}
|
||||
|
||||
function reverseSearchNext(state) {
|
||||
let previousPosition = state.currentReverseSearchResultsPosition + 1;
|
||||
if (previousPosition >= state.currentReverseSearchResults.length) {
|
||||
previousPosition = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
currentReverseSearchResultsPosition: previousPosition
|
||||
};
|
||||
}
|
||||
|
||||
exports.history = history;
|
||||
|
|
|
@ -8,13 +8,14 @@
|
|||
const {
|
||||
FILTER_BAR_TOGGLE,
|
||||
INITIALIZE,
|
||||
PERSIST_TOGGLE,
|
||||
SELECT_NETWORK_MESSAGE_TAB,
|
||||
SIDEBAR_CLOSE,
|
||||
SHOW_OBJECT_IN_SIDEBAR,
|
||||
TIMESTAMPS_TOGGLE,
|
||||
MESSAGES_CLEAR,
|
||||
PERSIST_TOGGLE,
|
||||
REVERSE_SEARCH_INPUT_TOGGLE,
|
||||
SELECT_NETWORK_MESSAGE_TAB,
|
||||
SHOW_OBJECT_IN_SIDEBAR,
|
||||
SIDEBAR_CLOSE,
|
||||
SPLIT_CONSOLE_CLOSE_BUTTON_TOGGLE,
|
||||
TIMESTAMPS_TOGGLE,
|
||||
} = require("devtools/client/webconsole/constants");
|
||||
|
||||
const {
|
||||
|
@ -30,6 +31,7 @@ const UiState = (overrides) => Object.freeze(Object.assign({
|
|||
timestampsVisible: true,
|
||||
gripInSidebar: null,
|
||||
closeButtonVisible: false,
|
||||
reverseSearchInputVisible: false,
|
||||
}, overrides));
|
||||
|
||||
function ui(state = UiState(), action) {
|
||||
|
@ -58,6 +60,8 @@ function ui(state = UiState(), action) {
|
|||
return Object.assign({}, state, {sidebarVisible: true, gripInSidebar: action.grip});
|
||||
case SPLIT_CONSOLE_CLOSE_BUTTON_TOGGLE:
|
||||
return Object.assign({}, state, {closeButtonVisible: action.shouldDisplayButton});
|
||||
case REVERSE_SEARCH_INPUT_TOGGLE:
|
||||
return {...state, reverseSearchInputVisible: !state.reverseSearchInputVisible};
|
||||
}
|
||||
|
||||
return state;
|
||||
|
|
|
@ -46,8 +46,44 @@ function getPreviousHistoryValue(state) {
|
|||
return null;
|
||||
}
|
||||
|
||||
function getReverseSearchResult(state) {
|
||||
const { history } = state;
|
||||
const { currentReverseSearchResults, currentReverseSearchResultsPosition } = history;
|
||||
|
||||
if (!Array.isArray(currentReverseSearchResults)
|
||||
|| currentReverseSearchResults.length === 0
|
||||
|| !Number.isInteger(currentReverseSearchResultsPosition)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return currentReverseSearchResults[currentReverseSearchResultsPosition];
|
||||
}
|
||||
|
||||
function getReverseSearchResultPosition(state) {
|
||||
const { history } = state;
|
||||
const { currentReverseSearchResultsPosition } = history;
|
||||
if (!Number.isInteger(currentReverseSearchResultsPosition)) {
|
||||
return currentReverseSearchResultsPosition;
|
||||
}
|
||||
|
||||
return currentReverseSearchResultsPosition + 1;
|
||||
}
|
||||
|
||||
function getReverseSearchTotalResults(state) {
|
||||
const { history } = state;
|
||||
const { currentReverseSearchResults } = history;
|
||||
if (!currentReverseSearchResults) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return currentReverseSearchResults.length;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getHistory,
|
||||
getHistoryEntries,
|
||||
getHistoryValue,
|
||||
getReverseSearchResult,
|
||||
getReverseSearchResultPosition,
|
||||
getReverseSearchTotalResults,
|
||||
};
|
||||
|
|
|
@ -49,6 +49,7 @@ function configureStore(hud, options = {}) {
|
|||
|| Math.max(getIntPref("devtools.hud.loglimit"), 1);
|
||||
const sidebarToggle = getBoolPref(PREFS.FEATURES.SIDEBAR_TOGGLE);
|
||||
const jstermCodeMirror = getBoolPref(PREFS.FEATURES.JSTERM_CODE_MIRROR);
|
||||
const jstermReverseSearch = getBoolPref(PREFS.FEATURES.JSTERM_REVERSE_SEARCH);
|
||||
const historyCount = getIntPref(PREFS.UI.INPUT_HISTORY_COUNT);
|
||||
|
||||
const initialState = {
|
||||
|
@ -56,6 +57,7 @@ function configureStore(hud, options = {}) {
|
|||
logLimit,
|
||||
sidebarToggle,
|
||||
jstermCodeMirror,
|
||||
jstermReverseSearch,
|
||||
historyCount,
|
||||
}),
|
||||
filters: FilterState({
|
||||
|
|
|
@ -343,6 +343,10 @@ subsuite = clipboard
|
|||
[browser_webconsole_persist.js]
|
||||
[browser_webconsole_reopen_closed_tab.js]
|
||||
[browser_webconsole_repeat_different_objects.js]
|
||||
[browser_webconsole_reverse_search.js]
|
||||
[browser_webconsole_reverse_search_keyboard_navigation.js]
|
||||
[browser_webconsole_reverse_search_mouse_navigation.js]
|
||||
[browser_webconsole_reverse_search_toggle.js]
|
||||
[browser_webconsole_sandbox_update_after_navigation.js]
|
||||
[browser_webconsole_script_errordoc_urls.js]
|
||||
[browser_webconsole_scroll.js]
|
||||
|
|
|
@ -86,7 +86,7 @@ async function performTests() {
|
|||
info("Test autocomplete inside parens");
|
||||
jsterm.setInputValue("dump()");
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft");
|
||||
const onAutocompleteUpdated = jsterm.once("autocomplete-updated");
|
||||
let onAutocompleteUpdated = jsterm.once("autocomplete-updated");
|
||||
EventUtils.sendString("window.testBugA");
|
||||
await onAutocompleteUpdated;
|
||||
ok(popup.isOpen, "popup is open");
|
||||
|
@ -104,6 +104,39 @@ async function performTests() {
|
|||
EventUtils.synthesizeKey("KEY_Tab");
|
||||
checkJsTermValueAndCursor(jsterm, "dump(window.testBugAA\t|)",
|
||||
"completion was successful after Enter");
|
||||
|
||||
info("Check that we don't show the popup when editing words");
|
||||
await setInputValueForAutocompletion(jsterm, "estBug", 0);
|
||||
onAutocompleteUpdated = jsterm.once("autocomplete-updated");
|
||||
EventUtils.sendString("t");
|
||||
await onAutocompleteUpdated;
|
||||
is(jsterm.getInputValue(), "testBug", "jsterm has expected value");
|
||||
is(popup.isOpen, false, "popup is not open");
|
||||
ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
|
||||
|
||||
await setInputValueForAutocompletion(jsterm, "__foo", 1);
|
||||
onAutocompleteUpdated = jsterm.once("autocomplete-updated");
|
||||
EventUtils.sendString("t");
|
||||
await onAutocompleteUpdated;
|
||||
is(jsterm.getInputValue(), "_t_foo", "jsterm has expected value");
|
||||
is(popup.isOpen, false, "popup is not open");
|
||||
ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
|
||||
|
||||
await setInputValueForAutocompletion(jsterm, "$$bar", 1);
|
||||
onAutocompleteUpdated = jsterm.once("autocomplete-updated");
|
||||
EventUtils.sendString("t");
|
||||
await onAutocompleteUpdated;
|
||||
is(jsterm.getInputValue(), "$t$bar", "jsterm has expected value");
|
||||
is(popup.isOpen, false, "popup is not open");
|
||||
ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
|
||||
|
||||
await setInputValueForAutocompletion(jsterm, "99luftballons", 1);
|
||||
onAutocompleteUpdated = jsterm.once("autocomplete-updated");
|
||||
EventUtils.sendString("t");
|
||||
await onAutocompleteUpdated;
|
||||
is(jsterm.getInputValue(), "9t9luftballons", "jsterm has expected value");
|
||||
is(popup.isOpen, false, "popup is not open");
|
||||
ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
|
||||
}
|
||||
|
||||
async function setInitialState(jsterm) {
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Tests reverse search features.
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = `data:text/html,<meta charset=utf8>Test reverse search`;
|
||||
const isMacOS = AppConstants.platform === "macosx";
|
||||
|
||||
add_task(async function() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
|
||||
const jstermHistory = [
|
||||
`document`,
|
||||
`Dog = "Snoopy"`,
|
||||
`document
|
||||
.querySelectorAll("*")
|
||||
.forEach(console.log)`,
|
||||
`document`,
|
||||
`"😎"`
|
||||
];
|
||||
|
||||
const onLastMessage = waitForMessage(hud, `"😎"`);
|
||||
for (const input of jstermHistory) {
|
||||
await hud.jsterm.execute(input);
|
||||
}
|
||||
await onLastMessage;
|
||||
|
||||
const jstermInitialValue = "initialValue";
|
||||
hud.jsterm.setInputValue(jstermInitialValue);
|
||||
|
||||
info("Check that the reverse search toolbar as the expected initial state");
|
||||
let reverseSearchElement = await openReverseSearch(hud);
|
||||
ok(reverseSearchElement, "Reverse search is displayed with a keyboard shortcut");
|
||||
ok(!getReverseSearchInfoElement(hud),
|
||||
"The result info element is not displayed by default");
|
||||
ok(
|
||||
!reverseSearchElement.querySelector(".search-result-button-prev") &&
|
||||
!reverseSearchElement.querySelector(".search-result-button-next"),
|
||||
"The results navigation buttons are not displayed by default"
|
||||
);
|
||||
is(hud.jsterm.getInputValue(), jstermInitialValue,
|
||||
"The jsterm value is not changed when opening reverse search");
|
||||
is(isReverseSearchInputFocused(hud), true, "reverse search input is focused");
|
||||
|
||||
EventUtils.sendString("d");
|
||||
let infoElement = await waitFor(() => getReverseSearchInfoElement(hud));
|
||||
is(infoElement.textContent, "3 of 3 results", "The reverse info has the expected text "
|
||||
+ "— duplicated results (`document`) are coalesced");
|
||||
|
||||
const previousButton = reverseSearchElement.querySelector(".search-result-button-prev");
|
||||
const nextButton = reverseSearchElement.querySelector(".search-result-button-next");
|
||||
ok(previousButton, "Previous navigation button is now displayed");
|
||||
is(previousButton.title, `Previous result (${isMacOS ? "Ctrl + R" : "F9"})`,
|
||||
"Previous navigation button has expected title");
|
||||
|
||||
ok(nextButton, "Next navigation button is now displayed");
|
||||
is(nextButton.title, `Next result (${isMacOS ? "Ctrl + S" : "Shift + F9"})`,
|
||||
"Next navigation button has expected title");
|
||||
is(hud.jsterm.getInputValue(), "document", "JsTerm has the expected input");
|
||||
is(hud.jsterm.autocompletePopup.isOpen, false,
|
||||
"Setting the input value did not trigger the autocompletion");
|
||||
is(isReverseSearchInputFocused(hud), true, "reverse search input is focused");
|
||||
|
||||
let onJsTermValueChanged = hud.jsterm.once("set-input-value");
|
||||
EventUtils.sendString("og");
|
||||
await onJsTermValueChanged;
|
||||
is(hud.jsterm.getInputValue(), `Dog = "Snoopy"`, "JsTerm input was updated");
|
||||
is(infoElement.textContent, "1 result", "The reverse info has the expected text");
|
||||
ok(
|
||||
!reverseSearchElement.querySelector(".search-result-button-prev") &&
|
||||
!reverseSearchElement.querySelector(".search-result-button-next"),
|
||||
"The results navigation buttons are not displayed when there's only one result"
|
||||
);
|
||||
|
||||
info("Check that the UI and results are updated when typing in the input");
|
||||
onJsTermValueChanged = hud.jsterm.once("set-input-value");
|
||||
EventUtils.sendString("g");
|
||||
await waitFor(() => reverseSearchElement.classList.contains("no-result"));
|
||||
is(hud.jsterm.getInputValue(), `Dog = "Snoopy"`,
|
||||
"JsTerm input was not updated since there's no results");
|
||||
is(infoElement.textContent, "No results", "The reverse info has the expected text");
|
||||
ok(
|
||||
!reverseSearchElement.querySelector(".search-result-button-prev") &&
|
||||
!reverseSearchElement.querySelector(".search-result-button-next"),
|
||||
"The results navigation buttons are not displayed when there's no result"
|
||||
);
|
||||
|
||||
info("Check that Backspace updates the UI");
|
||||
EventUtils.synthesizeKey("KEY_Backspace");
|
||||
await waitFor(() => !reverseSearchElement.classList.contains("no-result"));
|
||||
is(infoElement.textContent, "1 result", "The reverse info has the expected text");
|
||||
is(hud.jsterm.getInputValue(), `Dog = "Snoopy"`, "JsTerm kept its value");
|
||||
|
||||
info("Check that Escape does not affect the jsterm value");
|
||||
EventUtils.synthesizeKey("KEY_Escape");
|
||||
await waitFor(() => !getReverseSearchElement(hud));
|
||||
is(hud.jsterm.getInputValue(), `Dog = "Snoopy"`,
|
||||
"Closing the input did not changed the JsTerm value");
|
||||
is(isJstermFocused(hud.jsterm), true, "JsTerm is focused");
|
||||
|
||||
info("Check that the search works with emojis");
|
||||
reverseSearchElement = await openReverseSearch(hud);
|
||||
onJsTermValueChanged = hud.jsterm.once("set-input-value");
|
||||
EventUtils.sendString("😎");
|
||||
infoElement = await waitFor(() => getReverseSearchInfoElement(hud));
|
||||
is(infoElement.textContent, "1 result", "The reverse info has the expected text");
|
||||
|
||||
info("Check that Enter evaluates the JsTerm and closes the UI");
|
||||
const onMessage = waitForMessage(hud, `"😎"`);
|
||||
const onReverseSearchClose = waitFor(() => !getReverseSearchElement(hud));
|
||||
EventUtils.synthesizeKey("KEY_Enter");
|
||||
await Promise.all([onMessage, onReverseSearchClose]);
|
||||
ok(true, "Enter evaluates what's in the JsTerm and closes the reverse search UI");
|
||||
});
|
|
@ -0,0 +1,122 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Tests reverse search results keyboard navigation.
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = `data:text/html,<meta charset=utf8>Test reverse search`;
|
||||
const isMacOS = AppConstants.platform === "macosx";
|
||||
|
||||
add_task(async function() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
|
||||
const jstermHistory = [
|
||||
`document`,
|
||||
`document
|
||||
.querySelectorAll("*")
|
||||
.forEach(console.log)`,
|
||||
`Dog = "Snoopy"`,
|
||||
];
|
||||
|
||||
const onLastMessage = waitForMessage(hud, `"Snoopy"`);
|
||||
for (const input of jstermHistory) {
|
||||
await hud.jsterm.execute(input);
|
||||
}
|
||||
await onLastMessage;
|
||||
|
||||
await openReverseSearch(hud);
|
||||
EventUtils.sendString("d");
|
||||
const infoElement = await waitFor(() => getReverseSearchInfoElement(hud));
|
||||
is(infoElement.textContent, "3 of 3 results", "The reverse info has the expected text");
|
||||
|
||||
is(hud.jsterm.getInputValue(), jstermHistory[2], "JsTerm has the expected input");
|
||||
is(hud.jsterm.autocompletePopup.isOpen, false,
|
||||
"Setting the input value did not trigger the autocompletion");
|
||||
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "previous",
|
||||
expectedInfoText: "2 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[1]
|
||||
});
|
||||
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "previous",
|
||||
expectedInfoText: "1 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[0]
|
||||
});
|
||||
|
||||
info("Check that we go back to the last matching item if we were at the first");
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "previous",
|
||||
expectedInfoText: "3 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[2]
|
||||
});
|
||||
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "next",
|
||||
expectedInfoText: "1 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[0]
|
||||
});
|
||||
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "next",
|
||||
expectedInfoText: "2 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[1]
|
||||
});
|
||||
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "next",
|
||||
expectedInfoText: "3 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[2]
|
||||
});
|
||||
|
||||
info("Check that trying to navigate when there's only 1 result does not throw");
|
||||
EventUtils.sendString("og");
|
||||
await waitFor(() => getReverseSearchInfoElement(hud).textContent === "1 result");
|
||||
triggerPreviousResultShortcut();
|
||||
triggerNextResultShortcut();
|
||||
|
||||
info("Check that trying to navigate when there's no result does not throw");
|
||||
EventUtils.sendString("g");
|
||||
await waitFor(() => getReverseSearchInfoElement(hud).textContent === "No results");
|
||||
triggerPreviousResultShortcut();
|
||||
triggerNextResultShortcut();
|
||||
});
|
||||
|
||||
async function navigateResultsAndCheckState(hud, {
|
||||
direction,
|
||||
expectedInfoText,
|
||||
expectedJsTermInputValue,
|
||||
}) {
|
||||
const onJsTermValueChanged = hud.jsterm.once("set-input-value");
|
||||
if (direction === "previous") {
|
||||
triggerPreviousResultShortcut();
|
||||
} else {
|
||||
triggerNextResultShortcut();
|
||||
}
|
||||
await onJsTermValueChanged;
|
||||
|
||||
is(hud.jsterm.getInputValue(), expectedJsTermInputValue, "JsTerm has expected value");
|
||||
|
||||
const infoElement = getReverseSearchInfoElement(hud);
|
||||
is(infoElement.textContent, expectedInfoText, "The reverse info has the expected text");
|
||||
is(isReverseSearchInputFocused(hud), true, "reverse search input is still focused");
|
||||
}
|
||||
|
||||
function triggerPreviousResultShortcut() {
|
||||
if (isMacOS) {
|
||||
EventUtils.synthesizeKey("r", {ctrlKey: true});
|
||||
} else {
|
||||
EventUtils.synthesizeKey("VK_F9");
|
||||
}
|
||||
}
|
||||
|
||||
function triggerNextResultShortcut() {
|
||||
if (isMacOS) {
|
||||
EventUtils.synthesizeKey("s", {ctrlKey: true});
|
||||
} else {
|
||||
EventUtils.synthesizeKey("VK_F9", {shiftKey: true});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Tests reverse search results mouse navigation.
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = `data:text/html,<meta charset=utf8>Test reverse search`;
|
||||
|
||||
add_task(async function() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
|
||||
const jstermHistory = [
|
||||
`document`,
|
||||
`document
|
||||
.querySelectorAll("*")
|
||||
.forEach(console.log)`,
|
||||
`Dog = "Snoopy"`,
|
||||
];
|
||||
|
||||
const onLastMessage = waitForMessage(hud, `"Snoopy"`);
|
||||
for (const input of jstermHistory) {
|
||||
await hud.jsterm.execute(input);
|
||||
}
|
||||
await onLastMessage;
|
||||
|
||||
await openReverseSearch(hud);
|
||||
EventUtils.sendString("d");
|
||||
const infoElement = await waitFor(() => getReverseSearchInfoElement(hud));
|
||||
is(infoElement.textContent, "3 of 3 results", "The reverse info has the expected text");
|
||||
|
||||
is(hud.jsterm.getInputValue(), jstermHistory[2], "JsTerm has the expected input");
|
||||
is(hud.jsterm.autocompletePopup.isOpen, false,
|
||||
"Setting the input value did not trigger the autocompletion");
|
||||
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "previous",
|
||||
expectedInfoText: "2 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[1]
|
||||
});
|
||||
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "previous",
|
||||
expectedInfoText: "1 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[0]
|
||||
});
|
||||
|
||||
info("Check that we go back to the last matching item if we were at the first");
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "previous",
|
||||
expectedInfoText: "3 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[2]
|
||||
});
|
||||
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "next",
|
||||
expectedInfoText: "1 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[0]
|
||||
});
|
||||
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "next",
|
||||
expectedInfoText: "2 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[1]
|
||||
});
|
||||
|
||||
await navigateResultsAndCheckState(hud, {
|
||||
direction: "next",
|
||||
expectedInfoText: "3 of 3 results",
|
||||
expectedJsTermInputValue: jstermHistory[2]
|
||||
});
|
||||
});
|
||||
|
||||
async function navigateResultsAndCheckState(hud, {
|
||||
direction,
|
||||
expectedInfoText,
|
||||
expectedJsTermInputValue,
|
||||
}) {
|
||||
const onJsTermValueChanged = hud.jsterm.once("set-input-value");
|
||||
if (direction === "previous") {
|
||||
clickPreviousButton(hud);
|
||||
} else {
|
||||
clickNextButton(hud);
|
||||
}
|
||||
await onJsTermValueChanged;
|
||||
|
||||
is(hud.jsterm.getInputValue(), expectedJsTermInputValue, "JsTerm has expected value");
|
||||
|
||||
const infoElement = getReverseSearchInfoElement(hud);
|
||||
is(infoElement.textContent, expectedInfoText, "The reverse info has the expected text");
|
||||
is(isReverseSearchInputFocused(hud), true, "reverse search input is still focused");
|
||||
}
|
||||
|
||||
function clickPreviousButton(hud) {
|
||||
const reverseSearchElement = getReverseSearchElement(hud);
|
||||
if (!reverseSearchElement) {
|
||||
return;
|
||||
}
|
||||
const button = reverseSearchElement.querySelector(".search-result-button-prev");
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
|
||||
button.click();
|
||||
}
|
||||
|
||||
function clickNextButton(hud) {
|
||||
const reverseSearchElement = getReverseSearchElement(hud);
|
||||
if (!reverseSearchElement) {
|
||||
return;
|
||||
}
|
||||
const button = reverseSearchElement.querySelector(".search-result-button-next");
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
|
||||
button.click();
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Tests showing and hiding the reverse search UI.
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = `data:text/html,<meta charset=utf8>Test reverse search toggle`;
|
||||
const isMacOS = AppConstants.platform === "macosx";
|
||||
|
||||
add_task(async function() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
|
||||
info("Close the reverse search UI with ESC");
|
||||
await openReverseSearch(hud);
|
||||
let onReverseSearchUiClose = waitFor(() => getReverseSearchElement(hud) === null);
|
||||
EventUtils.sendKey("ESCAPE");
|
||||
await onReverseSearchUiClose;
|
||||
ok(true, "Reverse search was closed with the Esc keyboard shortcut");
|
||||
|
||||
if (isMacOS) {
|
||||
info("Close the reverse search UI with Ctrl + C on OSX");
|
||||
await openReverseSearch(hud);
|
||||
onReverseSearchUiClose = waitFor(() => getReverseSearchElement(hud) === null);
|
||||
EventUtils.synthesizeKey("c", {ctrlKey: true});
|
||||
await onReverseSearchUiClose;
|
||||
ok(true, "Reverse search was closed with the Ctrl + C keyboard shortcut");
|
||||
}
|
||||
|
||||
info("Close the reverse search UI with the close button");
|
||||
const reverseSearchElement = await openReverseSearch(hud);
|
||||
const closeButton = reverseSearchElement.querySelector(".reverse-search-close-button");
|
||||
ok(closeButton, "The close button is displayed");
|
||||
is(closeButton.title, `Close (Esc${isMacOS ? " | Ctrl + C" : ""})`,
|
||||
"The close button has the expected tooltip");
|
||||
onReverseSearchUiClose = waitFor(() => getReverseSearchElement(hud) === null);
|
||||
closeButton.click();
|
||||
await onReverseSearchUiClose;
|
||||
ok(true, "Reverse search was closed by clicking on the close button");
|
||||
|
||||
info("Close the reverse search UI by clicking on the output");
|
||||
await openReverseSearch(hud);
|
||||
hud.ui.outputNode.querySelector(".jsterm-input-container").click();
|
||||
ok(true, "Reverse search was closed by clicking in the output");
|
||||
});
|
|
@ -66,7 +66,6 @@ registerCleanupFunction(async function() {
|
|||
async function openNewTabAndConsole(url, clearJstermHistory = true) {
|
||||
const toolbox = await openNewTabAndToolbox(url, "webconsole");
|
||||
const hud = toolbox.getCurrentPanel().hud;
|
||||
hud.jsterm._lazyVariablesView = false;
|
||||
|
||||
if (clearJstermHistory) {
|
||||
// Clearing history that might have been set in previous tests.
|
||||
|
@ -863,3 +862,52 @@ async function resetFilters(hud) {
|
|||
const store = hud.ui.consoleOutput.getStore();
|
||||
store.dispatch(wcActions.filtersClear());
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the reverse search input by simulating the appropriate keyboard shortcut.
|
||||
*
|
||||
* @param {Object} hud
|
||||
* @returns {DOMNode} The reverse search dom node.
|
||||
*/
|
||||
async function openReverseSearch(hud) {
|
||||
info("Open the reverse search UI with a keyboard shortcut");
|
||||
const onReverseSearchUiOpen = waitFor(() => getReverseSearchElement(hud));
|
||||
const isMacOS = AppConstants.platform === "macosx";
|
||||
if (isMacOS) {
|
||||
EventUtils.synthesizeKey("r", {ctrlKey: true});
|
||||
} else {
|
||||
EventUtils.synthesizeKey("VK_F9");
|
||||
}
|
||||
|
||||
const element = await onReverseSearchUiOpen;
|
||||
return element;
|
||||
}
|
||||
|
||||
function getReverseSearchElement(hud) {
|
||||
const {outputNode} = hud.ui;
|
||||
return outputNode.querySelector(".reverse-search");
|
||||
}
|
||||
|
||||
function getReverseSearchInfoElement(hud) {
|
||||
const reverseSearchElement = getReverseSearchElement(hud);
|
||||
if (!reverseSearchElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return reverseSearchElement.querySelector(".reverse-search-info");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating if the reverse search input is focused.
|
||||
*
|
||||
* @param {JsTerm} jsterm
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
function isReverseSearchInputFocused(hud) {
|
||||
const {outputNode} = hud.ui;
|
||||
const document = outputNode.ownerDocument;
|
||||
const documentIsFocused = document.hasFocus();
|
||||
const reverseSearchInput = outputNode.querySelector(".reverse-search-input");
|
||||
|
||||
return document.activeElement == reverseSearchInput && documentIsFocused;
|
||||
}
|
||||
|
|
|
@ -52,43 +52,7 @@ WebConsoleOutputWrapper.prototype = {
|
|||
const attachRefToHud = (id, node) => {
|
||||
this.hud[id] = node;
|
||||
};
|
||||
// Focus the input line whenever the output area is clicked.
|
||||
this.parentNode.addEventListener("click", (event) => {
|
||||
// Do not focus on middle/right-click or 2+ clicks.
|
||||
if (event.detail !== 1 || event.button !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not focus if a link was clicked
|
||||
const target = event.originalTarget || event.target;
|
||||
if (target.closest("a")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not focus if an input field was clicked
|
||||
if (target.closest("input")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not focus if something other than the output region was clicked
|
||||
// (including e.g. the clear messages button in toolbar)
|
||||
if (!target.closest(".webconsole-output-wrapper")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not focus if something is selected
|
||||
const selection = this.document.defaultView.getSelection();
|
||||
if (selection && !selection.isCollapsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.hud && this.hud.jsterm) {
|
||||
this.hud.jsterm.focus();
|
||||
}
|
||||
});
|
||||
|
||||
const { hud } = this;
|
||||
|
||||
const serviceContainer = {
|
||||
attachRefToHud,
|
||||
emitNewMessage: (node, messageId, timeStamp) => {
|
||||
|
@ -246,14 +210,16 @@ WebConsoleOutputWrapper.prototype = {
|
|||
});
|
||||
}
|
||||
|
||||
const {prefs} = store.getState();
|
||||
const app = App({
|
||||
attachRefToHud,
|
||||
serviceContainer,
|
||||
hud,
|
||||
onFirstMeaningfulPaint: resolve,
|
||||
closeSplitConsole: this.closeSplitConsole.bind(this),
|
||||
jstermCodeMirror: store.getState().prefs.jstermCodeMirror
|
||||
jstermCodeMirror: prefs.jstermCodeMirror
|
||||
&& !Services.appinfo.accessibilityEnabled,
|
||||
jstermReverseSearch: prefs.jstermReverseSearch,
|
||||
});
|
||||
|
||||
// Render the root Application component.
|
||||
|
|
|
@ -915,6 +915,7 @@ impl RenderBackend {
|
|||
profile_counters: &mut BackendProfileCounters,
|
||||
has_built_scene: bool,
|
||||
) {
|
||||
let requested_frame = render_frame;
|
||||
self.resource_cache.post_scene_building_update(
|
||||
resource_updates,
|
||||
&mut profile_counters.resources,
|
||||
|
@ -1023,7 +1024,10 @@ impl RenderBackend {
|
|||
self.result_tx.send(msg).unwrap();
|
||||
}
|
||||
|
||||
if render_frame {
|
||||
// Always forward the transaction to the renderer if a frame was requested,
|
||||
// otherwise gecko can get into a state where it waits (forever) for the
|
||||
// transaction to complete before sending new work.
|
||||
if requested_frame {
|
||||
self.notifier.new_frame_ready(document_id, scroll, render_frame, frame_build_time);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,12 @@ def computeVersionCode() {
|
|||
return code;
|
||||
}
|
||||
|
||||
def computeVersionNumber() {
|
||||
def appVersion = getAppVersionWithoutMilestone()
|
||||
def parts = appVersion.split('\\.')
|
||||
return parts[0] + "." + parts[1] + "." + getBuildId()
|
||||
}
|
||||
|
||||
// Mimic Python: open(os.path.join(buildconfig.topobjdir, 'buildid.h')).readline().split()[2]
|
||||
def getBuildId() {
|
||||
return file("${topobjdir}/buildid.h").getText('utf-8').split()[2]
|
||||
|
@ -295,12 +301,7 @@ uploadArchives {
|
|||
repositories.mavenDeployer {
|
||||
pom.groupId = 'org.mozilla.geckoview'
|
||||
pom.artifactId = "geckoview-${mozconfig.substs.MOZ_UPDATE_CHANNEL}-${mozconfig.substs.ANDROID_CPU_ARCH}"
|
||||
|
||||
if (mozconfig.substs.RELEASE_OR_BETA == 'true') {
|
||||
pom.version = mozconfig.substs.MOZ_APP_VERSION
|
||||
} else {
|
||||
pom.version = getAppVersionWithoutMilestone() + "." + getBuildId()
|
||||
}
|
||||
pom.version = computeVersionNumber()
|
||||
|
||||
pom.project {
|
||||
licenses {
|
||||
|
|
|
@ -207,7 +207,7 @@ nsDataHandler::ParsePathWithoutRef(
|
|||
// is ok as well (this deals with *broken* data URIs, see bug
|
||||
// 781693 for an example). Anything after "base64" in the non-data
|
||||
// part will be discarded in this case, however.
|
||||
if (offset == mediaType.Length() || mediaType[offset] == ';') {
|
||||
if (offset == mediaType.Length() || mediaType[offset] == ';' || mediaType[offset] == ' ') {
|
||||
MOZ_DIAGNOSTIC_ASSERT(base64 > 0, "Did someone remove the check?");
|
||||
// Index is on the first character of matched "base64" so we
|
||||
// move to the preceding character
|
||||
|
|
|
@ -1174,4 +1174,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
|||
|
||||
static const int32_t kUnknownId = -1;
|
||||
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1544702357386000);
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1545047791319000);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -18,31 +18,31 @@
|
|||
"default": {
|
||||
"aiohttp": {
|
||||
"hashes": [
|
||||
"sha256:04087c38e45da5aa1a8b2345441b821bf270436f7954eba1a7e36cc55fed81f8",
|
||||
"sha256:07f025ea9fbc904f46cde7ba1e16c4085687cf8b6cabb6b815a8b5962605a743",
|
||||
"sha256:0fae84267df30e27b072da1a09835616e6872f7cc82cfc3eb260a52e9b6de340",
|
||||
"sha256:17b105bfeefe7c1d122d5948f7fe20adb5eae83cbbf6c7b5a787176c883fc0ea",
|
||||
"sha256:21ec794275615fcf9b0715266ce6709eb40045560c75431a1439fb1ed0fb0241",
|
||||
"sha256:2421ca89978a037f0ed1cc77fc5678561cc416c2047aad2e1dd8259bce1192b3",
|
||||
"sha256:26e996559c8f723c19a638f5c315716c258d9e2e2e5fa31ef76cc62a4d676c99",
|
||||
"sha256:540c02599fb3f913121fe5767506f2ce36d0ff9bda6f0cf3f4fe978d68f9a8f8",
|
||||
"sha256:5e452185e23f4a30208b057932b4ca5d528f4c4fdcc58028809e9f763fa52f36",
|
||||
"sha256:613bc9d4513df36f76faf19f1010430c0cea45cc9db4af0df96d237e5fd42800",
|
||||
"sha256:6f35399afb09427523f97d6a6a000fb6562e9ed2d3560c2fdfb9d874beb46ecf",
|
||||
"sha256:72f9ba7f4767a5e75aeb68f0441ddd3856f7129cbd0d188420e770d17e3b100a",
|
||||
"sha256:74dc560e074a8a56ef3722bd87fc06acc38eaccba6b35afc39345782eeb41a42",
|
||||
"sha256:8de492b8c8d5acb60c30cf2275f36d0fb21d71e0a462bbed61f099a98264c635",
|
||||
"sha256:97e3f198da96d5833200d814812ee03dbf1b2ba5a85ea4751e5da1360fe9a7cd",
|
||||
"sha256:bb2af48882b6d351ffe17423d19a1a51f0850ead5b7e7237b663a4e880e8d5b7",
|
||||
"sha256:d50047664a199eab5e596e4a18f09781fcdc1ad43b3203c5585dc65cf4c57592",
|
||||
"sha256:d65a3942bce7717a1dc730927f583308e100a94375ed81fa06bcb02127e4c3ae",
|
||||
"sha256:e59bcc461b6523b8c9105032f7664bd918f9c3be5f96462b814e6bf1c915c32e",
|
||||
"sha256:f1958340035221643c0c27326fecf24e49265ba21c709e42163bc8b16cb2e0c7",
|
||||
"sha256:f4cba665391bd31b3807277de3c73fd80cc17a0d280f11485fe9e58e228b6c5c",
|
||||
"sha256:f54001b0504f808a88aa786749af6c52e6ca00b5b7350fbe84d6274e537e7485"
|
||||
"sha256:0419705a36b43c0ac6f15469f9c2a08cad5c939d78bd12a5c23ea167c8253b2b",
|
||||
"sha256:1812fc4bc6ac1bde007daa05d2d0f61199324e0cc893b11523e646595047ca08",
|
||||
"sha256:2214b5c0153f45256d5d52d1e0cafe53f9905ed035a142191727a5fb620c03dd",
|
||||
"sha256:275909137f0c92c61ba6bb1af856a522d5546f1de8ea01e4e726321c697754ac",
|
||||
"sha256:3983611922b561868428ea1e7269e757803713f55b53502423decc509fef1650",
|
||||
"sha256:51afec6ffa50a9da4cdef188971a802beb1ca8e8edb40fa429e5e529db3475fa",
|
||||
"sha256:589f2ec8a101a0f340453ee6945bdfea8e1cd84c8d88e5be08716c34c0799d95",
|
||||
"sha256:789820ddc65e1f5e71516adaca2e9022498fa5a837c79ba9c692a9f8f916c330",
|
||||
"sha256:7a968a0bdaaf9abacc260911775611c9a602214a23aeb846f2eb2eeaa350c4dc",
|
||||
"sha256:7aeefbed253f59ea39e70c5848de42ed85cb941165357fc7e87ab5d8f1f9592b",
|
||||
"sha256:7b2eb55c66512405103485bd7d285a839d53e7fdc261ab20e5bcc51d7aaff5de",
|
||||
"sha256:87bc95d3d333bb689c8d755b4a9d7095a2356108002149523dfc8e607d5d32a4",
|
||||
"sha256:9d80e40db208e29168d3723d1440ecbb06054d349c5ece6a2c5a611490830dd7",
|
||||
"sha256:a1b442195c2a77d33e4dbee67c9877ccbdd3a1f686f91eb479a9577ed8cc326b",
|
||||
"sha256:ab3d769413b322d6092f169f316f7b21cd261a7589f7e31db779d5731b0480d8",
|
||||
"sha256:b066d3dec5d0f5aee6e34e5765095dc3d6d78ef9839640141a2b20816a0642bd",
|
||||
"sha256:b24e7845ae8de3e388ef4bcfcf7f96b05f52c8e633b33cf8003a6b1d726fc7c2",
|
||||
"sha256:c59a953c3f8524a7c86eaeaef5bf702555be12f5668f6384149fe4bb75c52698",
|
||||
"sha256:cf2cc6c2c10d242790412bea7ccf73726a9a44b4c4b073d2699ef3b48971fd95",
|
||||
"sha256:e0c9c8d4150ae904f308ff27b35446990d2b1dfc944702a21925937e937394c6",
|
||||
"sha256:f1839db4c2b08a9c8f9788112644f8a8557e8e0ecc77b07091afabb941dc55d0",
|
||||
"sha256:f3df52362be39908f9c028a65490fae0475e4898b43a03d8aa29d1e765b45e07"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.4.2"
|
||||
"version": "==3.4.4"
|
||||
},
|
||||
"arrow": {
|
||||
"hashes": [
|
||||
|
@ -229,11 +229,11 @@
|
|||
},
|
||||
"mar": {
|
||||
"hashes": [
|
||||
"sha256:1e7b2fbd0714d90587caabe156a63baf73462fca7622b12784559b5a38993695",
|
||||
"sha256:f81306bc55fb31ec06c93a1383e40198952781deacda67068a4a73e904971128"
|
||||
"sha256:516f840c63bf6769b76f928d0823c07ef9a836e8c2e988dd05eba92fc26e78ab",
|
||||
"sha256:9699bd97eede5e289b16d174fa12b51977c89cd673ead5d44ff89d6d27f3ea58"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.3.0"
|
||||
"version": "==3.0.0"
|
||||
},
|
||||
"mohawk": {
|
||||
"hashes": [
|
||||
|
@ -244,22 +244,38 @@
|
|||
},
|
||||
"multidict": {
|
||||
"hashes": [
|
||||
"sha256:1a1d76374a1e7fe93acef96b354a03c1d7f83e7512e225a527d283da0d7ba5e0",
|
||||
"sha256:1d6e191965505652f194bc4c40270a842922685918a4f45e6936a6b15cc5816d",
|
||||
"sha256:295961a6a88f1199e19968e15d9b42f3a191c89ec13034dbc212bf9c394c3c82",
|
||||
"sha256:2be5af084de6c3b8e20d6421cb0346378a9c867dcf7c86030d6b0b550f9888e4",
|
||||
"sha256:2eb99617c7a0e9f2b90b64bc1fb742611718618572747d6f3d6532b7b78755ab",
|
||||
"sha256:4ba654c6b5ad1ae4a4d792abeb695b29ce981bb0f157a41d0fd227b385f2bef0",
|
||||
"sha256:5ba766433c30d703f6b2c17eb0b6826c6f898e5f58d89373e235f07764952314",
|
||||
"sha256:a59d58ee85b11f337b54933e8d758b2356fcdcc493248e004c9c5e5d11eedbe4",
|
||||
"sha256:a6e35d28900cf87bcc11e6ca9e474db0099b78f0be0a41d95bef02d49101b5b2",
|
||||
"sha256:b4df7ca9c01018a51e43937eaa41f2f5dce17a6382fda0086403bcb1f5c2cf8e",
|
||||
"sha256:bbd5a6bffd3ba8bfe75b16b5e28af15265538e8be011b0b9fddc7d86a453fd4a",
|
||||
"sha256:d870f399fcd58a1889e93008762a3b9a27cf7ea512818fc6e689f59495648355",
|
||||
"sha256:e9404e2e19e901121c3c5c6cffd5a8ae0d1d67919c970e3b3262231175713068"
|
||||
"sha256:112eeeddd226af681dc82b756ed34aa7b6d98f9c4a15760050298c21d715473d",
|
||||
"sha256:13b64ecb692effcabc5e29569ba9b5eb69c35112f990a16d6833ec3a9d9f8ec0",
|
||||
"sha256:1725373fb8f18c2166f8e0e5789851ccf98453c849b403945fa4ef59a16ca44e",
|
||||
"sha256:2061a50b7cae60a1f987503a995b2fc38e47027a937a355a124306ed9c629041",
|
||||
"sha256:35b062288a9a478f627c520fd27983160fc97591017d170f966805b428d17e07",
|
||||
"sha256:467b134bcc227b91b8e2ef8d2931f28b50bf7eb7a04c0403d102ded22e66dbfc",
|
||||
"sha256:475a3ece8bb450e49385414ebfae7f8fdb33f62f1ac0c12935c1cfb1b7c1076a",
|
||||
"sha256:49b885287e227a24545a1126d9ac17ae43138610713dc6219b781cc0ad5c6dfc",
|
||||
"sha256:4c95b2725592adb5c46642be2875c1234c32af841732c5504c17726b92082021",
|
||||
"sha256:4ea7ed00f4be0f7335c9a2713a65ac3d986be789ce5ebc10821da9664cbe6b85",
|
||||
"sha256:5e2d5e1d999e941b4a626aea46bdc4206877cf727107fdaa9d46a8a773a6e49b",
|
||||
"sha256:8039c520ef7bb9ec7c3db3df14c570be6362f43c200ae9854d2422d4ffe175a4",
|
||||
"sha256:81459a0ebcca09c1fcb8fe887ed13cf267d9b60fe33718fc5fd1a2a1ab49470a",
|
||||
"sha256:847c3b7b9ca3268e883685dc1347a4d09f84de7bd7597310044d847590447492",
|
||||
"sha256:8551d1db45f0ca4e8ec99130767009a29a4e0dc6558a4a6808491bcd3472d325",
|
||||
"sha256:8fa7679ffe615e0c1c7b80946ab4194669be74848719adf2d7867b5e861eb073",
|
||||
"sha256:a42a36f09f0f907579ff0fde547f2fde8a739a69efe4a2728835979d2bb5e17b",
|
||||
"sha256:a5fcad0070685c5b2d04b468bf5f4c735f5c176432f495ad055fcc4bc0a79b23",
|
||||
"sha256:ae22195b2a7494619b73c01129ddcddc0dfaa9e42727404b1d9a77253da3f420",
|
||||
"sha256:b360e82bdbbd862e1ce2a41cc3bbd0ab614350e813ca74801b34aac0f73465aa",
|
||||
"sha256:b96417899344c5e96bef757f4963a72d02e52653a4e0f99bbea3a531cedac59f",
|
||||
"sha256:b9e921140b797093edfc13ac08dc2a4fd016dd711dc42bb0e1aaf180e48425a7",
|
||||
"sha256:c5022b94fc330e6d177f3eb38097fb52c7df96ca0e04842c068cf0d9fc38b1e6",
|
||||
"sha256:cf2b117f2a8d951638efc7592fb72d3eeb2d38cc2194c26ba7f00e7190451d92",
|
||||
"sha256:d79620b542d9d0e23ae9790ca2fe44f1af40ffad9936efa37bd14954bc3e2818",
|
||||
"sha256:e2860691c11d10dac7c91bddae44f6211b3da4122d9a2ebb509c2247674d6070",
|
||||
"sha256:e3a293553715afecf7e10ea02da40593f9d7f48fe48a74fc5dd3ce08a0c46188",
|
||||
"sha256:e465be3fe7e992e5a6e16731afa6f41cb6ca53afccb4f28ea2fa6457783edf15",
|
||||
"sha256:e6d27895ef922bc859d969452f247bfbe5345d9aba69b9c8dbe1ea7704f0c5d9"
|
||||
],
|
||||
"markers": "python_version >= '3.4.1'",
|
||||
"version": "==4.3.1"
|
||||
"version": "==4.4.0"
|
||||
},
|
||||
"pexpect": {
|
||||
"hashes": [
|
||||
|
@ -328,11 +344,11 @@
|
|||
},
|
||||
"scriptworker": {
|
||||
"hashes": [
|
||||
"sha256:063b0442bdbde23afbd2828408c43cdc0f411c9250ea8571655ccba6d2f8d61c",
|
||||
"sha256:a940358870f5423ba07051ec696a8347c6d5459ad6b2c5823d3fd44a8449d1c0"
|
||||
"sha256:403e1627856a80d6467da21b187962f9a1e9f9640c069447d904c0377635872d",
|
||||
"sha256:e6e1e53ecc3f74446b53ba148a4451ef0cfb1046d60c0143b67874f70fa3d089"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==15.0.2"
|
||||
"version": "==15.0.3"
|
||||
},
|
||||
"sh": {
|
||||
"hashes": [
|
||||
|
@ -386,7 +402,7 @@
|
|||
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
|
||||
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
|
||||
],
|
||||
"markers": "python_version != '3.2.*' and python_version != '3.1.*' and python_version >= '2.6' and python_version < '4' and python_version != '3.0.*' and python_version != '3.3.*'",
|
||||
"markers": "python_version < '4' and python_version != '3.2.*' and python_version >= '2.6' and python_version != '3.0.*' and python_version != '3.3.*' and python_version != '3.1.*'",
|
||||
"version": "==1.23"
|
||||
},
|
||||
"virtualenv": {
|
||||
|
@ -394,7 +410,7 @@
|
|||
"sha256:2ce32cd126117ce2c539f0134eb89de91a8413a29baac49cbab3eb50e2026669",
|
||||
"sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752"
|
||||
],
|
||||
"markers": "python_version != '3.1.*' and python_version != '3.0.*' and python_version >= '2.7' and python_version != '3.2.*'",
|
||||
"markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.2.*'",
|
||||
"version": "==16.0.0"
|
||||
},
|
||||
"yarl": {
|
||||
|
|
|
@ -53,32 +53,27 @@ async function showAndHideAutoCompletePopup(jsterm) {
|
|||
|
||||
async function triggerAutocompletePopup(jsterm) {
|
||||
const onPopupOpened = jsterm.autocompletePopup.once("popup-opened");
|
||||
jsterm.setInputValue("window.autocompleteTest.");
|
||||
if (!jsterm.editor) {
|
||||
// setInputValue does not trigger the autocompletion in the old jsterm;
|
||||
// we need to call `updateAutocompletion` in order to display the popup. And since
|
||||
// setInputValue sets lastInputValue and updateAutocompletion checks it to trigger
|
||||
// the autocompletion request, we reset it.
|
||||
jsterm.lastInputValue = null;
|
||||
jsterm.updateAutocompletion();
|
||||
}
|
||||
setJsTermValueForCompletion(jsterm, "window.autocompleteTest.");
|
||||
await onPopupOpened;
|
||||
|
||||
const onPopupUpdated = jsterm.once("autocomplete-updated");
|
||||
jsterm.setInputValue("window.autocompleteTest.item9");
|
||||
if (!jsterm.editor) {
|
||||
jsterm.lastInputValue = null;
|
||||
jsterm.updateAutocompletion();
|
||||
}
|
||||
setJsTermValueForCompletion(jsterm, "window.autocompleteTest.item9");
|
||||
await onPopupUpdated;
|
||||
}
|
||||
|
||||
function hideAutocompletePopup(jsterm) {
|
||||
let onPopUpClosed = jsterm.autocompletePopup.once("popup-closed");
|
||||
jsterm.setInputValue("");
|
||||
if (!jsterm.editor) {
|
||||
jsterm.lastInputValue = null;
|
||||
jsterm.updateAutocompletion();
|
||||
}
|
||||
setJsTermValueForCompletion(jsterm, "");
|
||||
return onPopUpClosed;
|
||||
}
|
||||
|
||||
function setJsTermValueForCompletion(jsterm, value) {
|
||||
// setInputValue does not trigger the autocompletion;
|
||||
// we need to call `updateAutocompletion` in order to display the popup. And since
|
||||
// setInputValue sets lastInputValue and updateAutocompletion checks it to trigger
|
||||
// the autocompletion request, we reset it.
|
||||
jsterm.setInputValue(value);
|
||||
jsterm.lastInputValue = null;
|
||||
jsterm.updateAutocompletion();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,12 +29,6 @@
|
|||
["data:;base64;,WA"]
|
||||
expected: FAIL
|
||||
|
||||
["data:;base64 ,WA"]
|
||||
expected: FAIL
|
||||
|
||||
["data:;base64 ,WA"]
|
||||
expected: FAIL
|
||||
|
||||
["data:application/javascript,X X"]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -70,12 +64,6 @@
|
|||
["data:;base64;,WA"]
|
||||
expected: FAIL
|
||||
|
||||
["data:;base64 ,WA"]
|
||||
expected: FAIL
|
||||
|
||||
["data:;base64 ,WA"]
|
||||
expected: FAIL
|
||||
|
||||
["data:application/javascript,X X"]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче