зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1024913 - Enable reverse search in jsterm; r=bgrins,flod.
Differential Revision: https://phabricator.services.mozilla.com/D3114 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
b31b75d4af
Коммит
d006e653e5
|
@ -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)
|
||||
|
|
|
@ -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,6 +46,9 @@ class App extends Component {
|
|||
serviceContainer: PropTypes.object.isRequired,
|
||||
closeSplitConsole: PropTypes.func.isRequired,
|
||||
jstermCodeMirror: PropTypes.bool,
|
||||
jstermReverseSearch: PropTypes.bool,
|
||||
currentReverseSearchEntry: PropTypes.string,
|
||||
reverseSearchInputVisible: PropTypes.bool,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -52,14 +57,41 @@ class App extends Component {
|
|||
|
||||
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;
|
||||
|
@ -74,6 +106,12 @@ class App extends Component {
|
|||
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")) {
|
||||
|
@ -161,6 +199,7 @@ class App extends Component {
|
|||
serviceContainer,
|
||||
closeSplitConsole,
|
||||
jstermCodeMirror,
|
||||
jstermReverseSearch,
|
||||
} = this.props;
|
||||
|
||||
const classNames = ["webconsole-output-wrapper"];
|
||||
|
@ -172,12 +211,14 @@ 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;
|
||||
|
@ -204,6 +245,11 @@ class App extends Component {
|
|||
onPaste: this.onPaste,
|
||||
codeMirrorEnabled: jstermCodeMirror,
|
||||
}),
|
||||
jstermReverseSearch
|
||||
? ReverseSearchInput({
|
||||
hud,
|
||||
})
|
||||
: null
|
||||
),
|
||||
SideBar({
|
||||
serviceContainer,
|
||||
|
@ -215,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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче