зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1489491 - Populate reverse search with input text selection; r=bgrins.
If the user selected some text in the console input and opens the reverse search UI, we populate the reverse search input with the selected text and do a reverse search with this text. A test is added to ensure this works as expected. Differential Revision: https://phabricator.services.mozilla.com/D16843 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
88fc8a5784
Коммит
1128d243c6
|
@ -103,9 +103,10 @@ function showObjectInSidebar(grip) {
|
|||
};
|
||||
}
|
||||
|
||||
function reverseSearchInputToggle() {
|
||||
function reverseSearchInputToggle({initialValue} = {}) {
|
||||
return {
|
||||
type: REVERSE_SEARCH_INPUT_TOGGLE,
|
||||
initialValue,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ class App extends Component {
|
|||
jstermCodeMirror: PropTypes.bool,
|
||||
currentReverseSearchEntry: PropTypes.string,
|
||||
reverseSearchInputVisible: PropTypes.bool,
|
||||
reverseSearchInitialValue: PropTypes.string,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -63,13 +64,15 @@ class App extends Component {
|
|||
onKeyDown(event) {
|
||||
const {
|
||||
dispatch,
|
||||
hud,
|
||||
} = this.props;
|
||||
|
||||
if (
|
||||
(!isMacOS && event.key === "F9") ||
|
||||
(isMacOS && event.key === "r" && event.ctrlKey === true)
|
||||
) {
|
||||
dispatch(actions.reverseSearchInputToggle());
|
||||
const initialValue = hud.jsterm && hud.jsterm.getSelectedText();
|
||||
dispatch(actions.reverseSearchInputToggle({initialValue}));
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
@ -196,6 +199,7 @@ class App extends Component {
|
|||
serviceContainer,
|
||||
closeSplitConsole,
|
||||
jstermCodeMirror,
|
||||
reverseSearchInitialValue,
|
||||
} = this.props;
|
||||
|
||||
const classNames = ["webconsole-output-wrapper"];
|
||||
|
@ -243,6 +247,7 @@ class App extends Component {
|
|||
}),
|
||||
ReverseSearchInput({
|
||||
hud,
|
||||
initialValue: reverseSearchInitialValue,
|
||||
})
|
||||
),
|
||||
SideBar({
|
||||
|
@ -261,6 +266,7 @@ class App extends Component {
|
|||
const mapStateToProps = state => ({
|
||||
notifications: getAllNotifications(state),
|
||||
reverseSearchInputVisible: state.ui.reverseSearchInputVisible,
|
||||
reverseSearchInitialValue: state.ui.reverseSearchInitialValue,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
|
|
@ -734,6 +734,14 @@ class JSTerm extends Component {
|
|||
return this.inputNode ? this.inputNode.selectionStart : null;
|
||||
}
|
||||
|
||||
getSelectedText() {
|
||||
if (this.inputNode) {
|
||||
return this.inputNode.value.substring(
|
||||
this.inputNode.selectionStart, this.inputNode.selectionEnd);
|
||||
}
|
||||
return this.editor.getSelection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Even handler for the "beforeChange" event fired by codeMirror. This event is fired
|
||||
* when codeMirror is about to make a change to its DOM representation.
|
||||
|
|
|
@ -33,6 +33,7 @@ class ReverseSearchInput extends Component {
|
|||
reverseSearchTotalResults: PropTypes.number,
|
||||
reverseSearchResultPosition: PropTypes.number,
|
||||
visible: PropTypes.bool,
|
||||
initialValue: PropTypes.string,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -55,6 +56,14 @@ class ReverseSearchInput extends Component {
|
|||
if (prevProps.visible === true && this.props.visible === false) {
|
||||
jsterm.focus();
|
||||
}
|
||||
|
||||
if (
|
||||
prevProps.visible === false &&
|
||||
this.props.visible === true &&
|
||||
this.props.initialValue
|
||||
) {
|
||||
this.inputNode.value = this.props.initialValue;
|
||||
}
|
||||
}
|
||||
|
||||
onInputKeyDown(event) {
|
||||
|
|
|
@ -54,7 +54,7 @@ function history(state = getInitialState(), action, prefsState) {
|
|||
case UPDATE_HISTORY_POSITION:
|
||||
return updateHistoryPosition(state, action.direction, action.expression);
|
||||
case REVERSE_SEARCH_INPUT_TOGGLE:
|
||||
return reverseSearchInputToggle(state);
|
||||
return reverseSearchInputToggle(state, action);
|
||||
case REVERSE_SEARCH_INPUT_CHANGE:
|
||||
return reverseSearchInputChange(state, action.value);
|
||||
case REVERSE_SEARCH_BACK:
|
||||
|
@ -143,16 +143,25 @@ function updateHistoryPosition(state, direction, expression) {
|
|||
return state;
|
||||
}
|
||||
|
||||
function reverseSearchInputToggle(state) {
|
||||
function reverseSearchInputToggle(state, action) {
|
||||
const { initialValue = "" } = action;
|
||||
|
||||
// We're going to close the reverse search, let's clean the state
|
||||
if (state.reverseSearchEnabled) {
|
||||
return {
|
||||
...state,
|
||||
reverseSearchEnabled: !state.reverseSearchEnabled,
|
||||
position: state.reverseSearchEnabled === true ? state.entries.length : undefined,
|
||||
reverseSearchEnabled: false,
|
||||
position: undefined,
|
||||
currentReverseSearchResults: null,
|
||||
currentReverseSearchResultsPosition: null,
|
||||
};
|
||||
}
|
||||
|
||||
// If we're enabling the reverse search, we treat it as a reverse search input change,
|
||||
// since we can have an initial value.
|
||||
return reverseSearchInputChange(state, initialValue);
|
||||
}
|
||||
|
||||
function reverseSearchInputChange(state, searchString) {
|
||||
if (searchString === "") {
|
||||
return {
|
||||
|
|
|
@ -32,6 +32,7 @@ const UiState = (overrides) => Object.freeze(Object.assign({
|
|||
gripInSidebar: null,
|
||||
closeButtonVisible: false,
|
||||
reverseSearchInputVisible: false,
|
||||
reverseSearchInitialValue: "",
|
||||
}, overrides));
|
||||
|
||||
function ui(state = UiState(), action) {
|
||||
|
@ -61,7 +62,11 @@ function ui(state = UiState(), action) {
|
|||
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,
|
||||
reverseSearchInputVisible: !state.reverseSearchInputVisible,
|
||||
reverseSearchInitialValue: action.initialValue || "",
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
|
|
|
@ -374,6 +374,7 @@ subsuite = clipboard
|
|||
[browser_webconsole_reopen_closed_tab.js]
|
||||
[browser_webconsole_repeat_different_objects.js]
|
||||
[browser_webconsole_reverse_search.js]
|
||||
[browser_webconsole_reverse_search_initial_value.js]
|
||||
[browser_webconsole_reverse_search_keyboard_navigation.js]
|
||||
[browser_webconsole_reverse_search_mouse_navigation.js]
|
||||
[browser_webconsole_reverse_search_toggle.js]
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/* 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 initial value`;
|
||||
|
||||
add_task(async function() {
|
||||
// Run test with legacy JsTerm
|
||||
await pushPref("devtools.webconsole.jsterm.codeMirror", false);
|
||||
await performTests();
|
||||
// And then run it with the CodeMirror-powered one.
|
||||
await pushPref("devtools.webconsole.jsterm.codeMirror", true);
|
||||
await performTests();
|
||||
});
|
||||
|
||||
async function performTests() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
const { jsterm } = hud;
|
||||
|
||||
const jstermHistory = [
|
||||
`Dog = "Snoopy"`,
|
||||
`document
|
||||
.querySelectorAll("*")
|
||||
.forEach(console.log)`,
|
||||
`document`,
|
||||
`"😎"`,
|
||||
];
|
||||
|
||||
const onLastMessage = waitForMessage(hud, `"😎"`);
|
||||
for (const input of jstermHistory) {
|
||||
await jsterm.execute(input);
|
||||
}
|
||||
await onLastMessage;
|
||||
|
||||
const jstermInitialValue = "ado";
|
||||
jsterm.setInputValue(jstermInitialValue);
|
||||
|
||||
info(`Select 2 chars ("do") from the input`);
|
||||
if (jsterm.inputNode) {
|
||||
jsterm.inputNode.selectionStart = 1;
|
||||
jsterm.inputNode.selectionEnd = 3;
|
||||
} else {
|
||||
jsterm.editor.setSelection({line: 0, ch: 1}, {line: 0, ch: 3});
|
||||
}
|
||||
|
||||
info("Check that the reverse search toolbar as the expected initial state");
|
||||
let reverseSearchElement = await openReverseSearch(hud);
|
||||
is(reverseSearchElement.querySelector("input").value, "do",
|
||||
`Reverse search input has expected "do" value`);
|
||||
is(isReverseSearchInputFocused(hud), true, "reverse search input is focused");
|
||||
ok(reverseSearchElement, "Reverse search is displayed with a keyboard shortcut");
|
||||
const infoElement = getReverseSearchInfoElement(hud);
|
||||
is(infoElement.textContent, "3 of 3 results", "The reverse info has the expected text");
|
||||
|
||||
const previousButton = reverseSearchElement.querySelector(".search-result-button-prev");
|
||||
const nextButton = reverseSearchElement.querySelector(".search-result-button-next");
|
||||
ok(previousButton, "Previous navigation button is displayed");
|
||||
ok(nextButton, "Next navigation button is displayed");
|
||||
|
||||
is(jsterm.getInputValue(), "document", "JsTerm has the expected input");
|
||||
is(jsterm.autocompletePopup.isOpen, false,
|
||||
"Setting the input value did not trigger the autocompletion");
|
||||
|
||||
const onJsTermValueChanged = jsterm.once("set-input-value");
|
||||
EventUtils.sendString("g");
|
||||
await onJsTermValueChanged;
|
||||
is(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 there's no initial value when no text is selected");
|
||||
EventUtils.synthesizeKey("KEY_Escape");
|
||||
await waitFor(() => !getReverseSearchElement(hud));
|
||||
|
||||
info("Check that opening the reverse search input is empty after opening it again");
|
||||
reverseSearchElement = await openReverseSearch(hud);
|
||||
is(reverseSearchElement.querySelector("input").value, "",
|
||||
"Reverse search input is empty");
|
||||
}
|
Загрузка…
Ссылка в новой задаче