зеркало из 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 {
|
return {
|
||||||
type: REVERSE_SEARCH_INPUT_TOGGLE,
|
type: REVERSE_SEARCH_INPUT_TOGGLE,
|
||||||
|
initialValue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ class App extends Component {
|
||||||
jstermCodeMirror: PropTypes.bool,
|
jstermCodeMirror: PropTypes.bool,
|
||||||
currentReverseSearchEntry: PropTypes.string,
|
currentReverseSearchEntry: PropTypes.string,
|
||||||
reverseSearchInputVisible: PropTypes.bool,
|
reverseSearchInputVisible: PropTypes.bool,
|
||||||
|
reverseSearchInitialValue: PropTypes.string,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,13 +64,15 @@ class App extends Component {
|
||||||
onKeyDown(event) {
|
onKeyDown(event) {
|
||||||
const {
|
const {
|
||||||
dispatch,
|
dispatch,
|
||||||
|
hud,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(!isMacOS && event.key === "F9") ||
|
(!isMacOS && event.key === "F9") ||
|
||||||
(isMacOS && event.key === "r" && event.ctrlKey === true)
|
(isMacOS && event.key === "r" && event.ctrlKey === true)
|
||||||
) {
|
) {
|
||||||
dispatch(actions.reverseSearchInputToggle());
|
const initialValue = hud.jsterm && hud.jsterm.getSelectedText();
|
||||||
|
dispatch(actions.reverseSearchInputToggle({initialValue}));
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,6 +199,7 @@ class App extends Component {
|
||||||
serviceContainer,
|
serviceContainer,
|
||||||
closeSplitConsole,
|
closeSplitConsole,
|
||||||
jstermCodeMirror,
|
jstermCodeMirror,
|
||||||
|
reverseSearchInitialValue,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const classNames = ["webconsole-output-wrapper"];
|
const classNames = ["webconsole-output-wrapper"];
|
||||||
|
@ -243,6 +247,7 @@ class App extends Component {
|
||||||
}),
|
}),
|
||||||
ReverseSearchInput({
|
ReverseSearchInput({
|
||||||
hud,
|
hud,
|
||||||
|
initialValue: reverseSearchInitialValue,
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
SideBar({
|
SideBar({
|
||||||
|
@ -261,6 +266,7 @@ class App extends Component {
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
notifications: getAllNotifications(state),
|
notifications: getAllNotifications(state),
|
||||||
reverseSearchInputVisible: state.ui.reverseSearchInputVisible,
|
reverseSearchInputVisible: state.ui.reverseSearchInputVisible,
|
||||||
|
reverseSearchInitialValue: state.ui.reverseSearchInitialValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
|
|
@ -734,6 +734,14 @@ class JSTerm extends Component {
|
||||||
return this.inputNode ? this.inputNode.selectionStart : null;
|
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
|
* 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.
|
* when codeMirror is about to make a change to its DOM representation.
|
||||||
|
|
|
@ -33,6 +33,7 @@ class ReverseSearchInput extends Component {
|
||||||
reverseSearchTotalResults: PropTypes.number,
|
reverseSearchTotalResults: PropTypes.number,
|
||||||
reverseSearchResultPosition: PropTypes.number,
|
reverseSearchResultPosition: PropTypes.number,
|
||||||
visible: PropTypes.bool,
|
visible: PropTypes.bool,
|
||||||
|
initialValue: PropTypes.string,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +56,14 @@ class ReverseSearchInput extends Component {
|
||||||
if (prevProps.visible === true && this.props.visible === false) {
|
if (prevProps.visible === true && this.props.visible === false) {
|
||||||
jsterm.focus();
|
jsterm.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
prevProps.visible === false &&
|
||||||
|
this.props.visible === true &&
|
||||||
|
this.props.initialValue
|
||||||
|
) {
|
||||||
|
this.inputNode.value = this.props.initialValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onInputKeyDown(event) {
|
onInputKeyDown(event) {
|
||||||
|
|
|
@ -54,7 +54,7 @@ function history(state = getInitialState(), action, prefsState) {
|
||||||
case UPDATE_HISTORY_POSITION:
|
case UPDATE_HISTORY_POSITION:
|
||||||
return updateHistoryPosition(state, action.direction, action.expression);
|
return updateHistoryPosition(state, action.direction, action.expression);
|
||||||
case REVERSE_SEARCH_INPUT_TOGGLE:
|
case REVERSE_SEARCH_INPUT_TOGGLE:
|
||||||
return reverseSearchInputToggle(state);
|
return reverseSearchInputToggle(state, action);
|
||||||
case REVERSE_SEARCH_INPUT_CHANGE:
|
case REVERSE_SEARCH_INPUT_CHANGE:
|
||||||
return reverseSearchInputChange(state, action.value);
|
return reverseSearchInputChange(state, action.value);
|
||||||
case REVERSE_SEARCH_BACK:
|
case REVERSE_SEARCH_BACK:
|
||||||
|
@ -143,14 +143,23 @@ function updateHistoryPosition(state, direction, expression) {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
function reverseSearchInputToggle(state) {
|
function reverseSearchInputToggle(state, action) {
|
||||||
return {
|
const { initialValue = "" } = action;
|
||||||
...state,
|
|
||||||
reverseSearchEnabled: !state.reverseSearchEnabled,
|
// We're going to close the reverse search, let's clean the state
|
||||||
position: state.reverseSearchEnabled === true ? state.entries.length : undefined,
|
if (state.reverseSearchEnabled) {
|
||||||
currentReverseSearchResults: null,
|
return {
|
||||||
currentReverseSearchResultsPosition: null,
|
...state,
|
||||||
};
|
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) {
|
function reverseSearchInputChange(state, searchString) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ const UiState = (overrides) => Object.freeze(Object.assign({
|
||||||
gripInSidebar: null,
|
gripInSidebar: null,
|
||||||
closeButtonVisible: false,
|
closeButtonVisible: false,
|
||||||
reverseSearchInputVisible: false,
|
reverseSearchInputVisible: false,
|
||||||
|
reverseSearchInitialValue: "",
|
||||||
}, overrides));
|
}, overrides));
|
||||||
|
|
||||||
function ui(state = UiState(), action) {
|
function ui(state = UiState(), action) {
|
||||||
|
@ -61,7 +62,11 @@ function ui(state = UiState(), action) {
|
||||||
case SPLIT_CONSOLE_CLOSE_BUTTON_TOGGLE:
|
case SPLIT_CONSOLE_CLOSE_BUTTON_TOGGLE:
|
||||||
return Object.assign({}, state, {closeButtonVisible: action.shouldDisplayButton});
|
return Object.assign({}, state, {closeButtonVisible: action.shouldDisplayButton});
|
||||||
case REVERSE_SEARCH_INPUT_TOGGLE:
|
case REVERSE_SEARCH_INPUT_TOGGLE:
|
||||||
return {...state, reverseSearchInputVisible: !state.reverseSearchInputVisible};
|
return {
|
||||||
|
...state,
|
||||||
|
reverseSearchInputVisible: !state.reverseSearchInputVisible,
|
||||||
|
reverseSearchInitialValue: action.initialValue || "",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
|
|
@ -374,6 +374,7 @@ subsuite = clipboard
|
||||||
[browser_webconsole_reopen_closed_tab.js]
|
[browser_webconsole_reopen_closed_tab.js]
|
||||||
[browser_webconsole_repeat_different_objects.js]
|
[browser_webconsole_repeat_different_objects.js]
|
||||||
[browser_webconsole_reverse_search.js]
|
[browser_webconsole_reverse_search.js]
|
||||||
|
[browser_webconsole_reverse_search_initial_value.js]
|
||||||
[browser_webconsole_reverse_search_keyboard_navigation.js]
|
[browser_webconsole_reverse_search_keyboard_navigation.js]
|
||||||
[browser_webconsole_reverse_search_mouse_navigation.js]
|
[browser_webconsole_reverse_search_mouse_navigation.js]
|
||||||
[browser_webconsole_reverse_search_toggle.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");
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче