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:
Nicolas Chevobbe 2018-09-10 10:24:40 +00:00
Родитель b31b75d4af
Коммит d006e653e5
15 изменённых файлов: 588 добавлений и 49 удалений

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

@ -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();
}