Merge mozilla-central to mozilla-inbound

This commit is contained in:
Daniel Varga 2018-09-10 19:23:14 +03:00
Родитель 4d15d8f78a 9e7995b3c3
Коммит 67945694c1
45 изменённых файлов: 1377 добавлений и 620 удалений

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

@ -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