Bug 1554877 - Make JsTerm editor resizable. r=Honza.

We add a GridElementWidthResizer to handle the editor width.
The width is then persisted in a pref.
A test is added to ensure this works as expected.

Differential Revision: https://phabricator.services.mozilla.com/D37687

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nicolas Chevobbe 2019-07-18 05:51:44 +00:00
parent 5642141d9f
commit 73adf5f4f8
12 changed files with 176 additions and 4 deletions

View File

@ -290,6 +290,10 @@ pref("devtools.webconsole.features.editor", false);
// Saved editor mode state in the console.
pref("devtools.webconsole.input.editor", false);
// Editor width for webconsole and browserconsole
pref("devtools.webconsole.input.editorWidth", 0);
pref("devtools.browserconsole.input.editorWidth", 0);
// Disable the new performance recording panel by default
pref("devtools.performance.new-panel-enabled", false);

View File

@ -23,6 +23,7 @@ const {
WARNING_GROUPS_TOGGLE,
FILTERBAR_DISPLAY_MODE_SET,
EDITOR_TOGGLE,
EDITOR_SET_WIDTH,
} = require("devtools/client/webconsole/constants");
function persistToggle() {
@ -98,6 +99,16 @@ function editorToggle() {
};
}
function setEditorWidth(width) {
return ({ dispatch, prefsService }) => {
dispatch({
type: EDITOR_SET_WIDTH,
width,
});
prefsService.setIntPref(PREFS.UI.EDITOR_WIDTH, width);
};
}
/**
* Dispatches a SHOW_OBJECT_IN_SIDEBAR action, with a grip property corresponding to the
* {actor} parameter in the {messageId} message.
@ -148,6 +159,7 @@ module.exports = {
persistToggle,
reverseSearchInputToggle,
selectNetworkMessageTab,
setEditorWidth,
showMessageObjectInSidebar,
showObjectInSidebar,
sidebarClose,

View File

@ -46,6 +46,9 @@ const ConfirmDialog = createFactory(
const NotificationBox = createFactory(
require("devtools/client/shared/components/NotificationBox").NotificationBox
);
const GridElementWidthResizer = createFactory(
require("devtools/client/shared/components/splitter/GridElementWidthResizer")
);
const l10n = require("devtools/client/webconsole/webconsole-l10n");
const { Utils: WebConsoleUtils } = require("devtools/client/webconsole/utils");
@ -82,6 +85,7 @@ class App extends Component {
reverseSearchInputVisible: PropTypes.bool,
reverseSearchInitialValue: PropTypes.string,
editorMode: PropTypes.bool,
editorWidth: PropTypes.number,
hideShowContentMessagesCheckbox: PropTypes.bool,
sidebarVisible: PropTypes.bool.isRequired,
filterBarDisplayMode: PropTypes.oneOf([
@ -265,6 +269,7 @@ class App extends Component {
jstermCodeMirror,
autocomplete,
editorMode,
editorWidth,
} = this.props;
return JSTerm({
@ -275,6 +280,7 @@ class App extends Component {
codeMirrorEnabled: jstermCodeMirror,
autocomplete,
editorMode,
editorWidth,
});
}
@ -292,7 +298,6 @@ class App extends Component {
renderSideBar() {
const { serviceContainer, sidebarVisible } = this.props;
return SideBar({
key: "sidebar",
serviceContainer,
@ -349,7 +354,7 @@ class App extends Component {
}
render() {
const { webConsoleUI, editorMode } = this.props;
const { webConsoleUI, editorMode, dispatch } = this.props;
const filterBar = this.renderFilterBar();
const consoleOutput = this.renderConsoleOutput();
@ -373,6 +378,13 @@ class App extends Component {
notificationBox,
jsterm
),
GridElementWidthResizer({
enabled: editorMode,
position: "end",
className: "editor-resizer",
getControlledElementNode: () => webConsoleUI.jsterm.node,
onResizeEnd: width => dispatch(actions.setEditorWidth(width)),
}),
reverseSearch,
sidebar,
confirmDialog,
@ -385,6 +397,7 @@ const mapStateToProps = state => ({
reverseSearchInputVisible: state.ui.reverseSearchInputVisible,
reverseSearchInitialValue: state.ui.reverseSearchInitialValue,
editorMode: state.ui.editor,
editorWidth: state.ui.editorWidth,
sidebarVisible: state.ui.sidebarVisible,
filterBarDisplayMode: state.ui.filterBarDisplayMode,
});

View File

@ -114,6 +114,7 @@ class JSTerm extends Component {
autocompleteData: PropTypes.object.isRequired,
// Is the input in editor mode.
editorMode: PropTypes.bool,
editorWidth: PropTypes.number,
autocomplete: PropTypes.bool,
};
}
@ -154,6 +155,10 @@ class JSTerm extends Component {
}
componentDidMount() {
if (this.props.editorMode) {
this.setEditorWidth(this.props.editorWidth);
}
const autocompleteOptions = {
onSelect: this.onAutocompleteSelect.bind(this),
onClick: this.acceptProposedCompletion.bind(this),
@ -539,8 +544,33 @@ class JSTerm extends Component {
this.updateAutocompletionPopup(nextProps.autocompleteData);
}
if (this.editor && nextProps.editorMode !== this.props.editorMode) {
this.editor.setOption("lineNumbers", nextProps.editorMode);
if (nextProps.editorMode !== this.props.editorMode) {
if (this.editor) {
this.editor.setOption("lineNumbers", nextProps.editorMode);
}
if (nextProps.editorMode && nextProps.editorWidth) {
this.setEditorWidth(nextProps.editorWidth);
} else {
this.setEditorWidth(null);
}
}
}
/**
*
* @param {Number|null} editorWidth: The width to set the node to. If null, removes any
* `width` property on node style.
*/
setEditorWidth(editorWidth) {
if (!this.node) {
return;
}
if (editorWidth) {
this.node.style.width = `${editorWidth}px`;
} else {
this.node.style.removeProperty("width");
}
}
@ -1795,6 +1825,9 @@ class JSTerm extends Component {
key: "jsterm-container",
style: { direction: "ltr" },
"aria-live": "off",
ref: node => {
this.node = node;
},
},
dom.textarea({
className: "jsterm-complete-node devtools-monospace",

View File

@ -47,6 +47,7 @@ const actionTypes = {
PAUSED_EXCECUTION_POINT: "PAUSED_EXCECUTION_POINT",
WARNING_GROUPS_TOGGLE: "WARNING_GROUPS_TOGGLE",
WILL_NAVIGATE: "WILL_NAVIGATE",
EDITOR_SET_WIDTH: "EDITOR_SET_WIDTH",
};
const prefs = {
@ -74,6 +75,8 @@ const prefs = {
CONTENT_MESSAGES: "devtools.browserconsole.contentMessages",
// Display timestamp in messages.
MESSAGE_TIMESTAMP: "devtools.webconsole.timestampMessages",
// Store the editor width.
EDITOR_WIDTH: "input.editorWidth",
},
FEATURES: {
// We use the same pref to enable the sidebar on webconsole and browser console.

View File

@ -19,6 +19,7 @@ const {
FILTERBAR_DISPLAY_MODE_SET,
FILTERBAR_DISPLAY_MODES,
EDITOR_TOGGLE,
EDITOR_SET_WIDTH,
} = require("devtools/client/webconsole/constants");
const { PANELS } = require("devtools/client/netmonitor/src/constants");
@ -38,6 +39,7 @@ const UiState = overrides =>
reverseSearchInputVisible: false,
reverseSearchInitialValue: "",
editor: false,
editorWidth: null,
filterBarDisplayMode: FILTERBAR_DISPLAY_MODES.WIDE,
},
overrides
@ -87,6 +89,11 @@ function ui(state = UiState(), action) {
...state,
editor: !state.editor,
};
case EDITOR_SET_WIDTH:
return {
...state,
editorWidth: action.width,
};
}
return state;

View File

@ -78,6 +78,7 @@ function configureStore(webConsoleUI, options = {}) {
? getBoolPref(PREFS.UI.CONTENT_MESSAGES)
: true,
editor: getBoolPref(PREFS.UI.EDITOR),
editorWidth: getIntPref(PREFS.UI.EDITOR_WIDTH),
timestampsVisible: getBoolPref(PREFS.UI.MESSAGE_TIMESTAMP),
}),
};

View File

@ -29,6 +29,7 @@ pref("devtools.webconsole.input.editor", false);
pref("devtools.webconsole.input.autocomplete", true);
pref("devtools.browserconsole.contentMessages", true);
pref("devtools.webconsole.features.editor", true);
pref("devtools.webconsole.input.editorWidth", 800);
global.loader = {
lazyServiceGetter: () => {},

View File

@ -216,6 +216,7 @@ skip-if = os != 'mac' # The tested ctrl+key shortcuts are OSX only
[browser_jsterm_editor_execute.js]
[browser_jsterm_editor_gutter.js]
[browser_jsterm_editor_toggle_keyboard_shortcut.js]
[browser_jsterm_editor_resize.js]
[browser_jsterm_editor_toolbar.js]
[browser_jsterm_error_docs.js]
[browser_jsterm_error_outside_valid_range.js]

View File

@ -0,0 +1,88 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that the editor can be resized and that its width is persisted.
"use strict";
const TEST_URI =
"data:text/html;charset=utf-8,Web Console test for editor resize";
add_task(async function() {
await pushPref("devtools.webconsole.features.editor", true);
await pushPref("devtools.webconsole.input.editor", true);
// 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() {
// Reset editorWidth pref so we have steady results when running multiple times.
await pushPref("devtools.webconsole.input.editorWidth", null);
let hud = await openNewTabAndConsole(TEST_URI);
const getEditorEl = () =>
hud.ui.outputNode.querySelector(".jsterm-input-container");
const resizerEl = hud.ui.outputNode.querySelector(".editor-resizer");
const editorBoundingRect = getEditorEl().getBoundingClientRect();
const delta = 100;
const originalWidth = editorBoundingRect.width;
const clientX = editorBoundingRect.right + delta;
await resize(resizerEl, clientX);
const newWidth = Math.floor(originalWidth + delta);
is(
Math.floor(getEditorEl().getBoundingClientRect().width),
newWidth,
"The editor element was resized as expected"
);
info("Close and re-open the console to check if editor width was persisted");
await closeConsole();
hud = await openConsole();
is(
Math.floor(getEditorEl().getBoundingClientRect().width),
newWidth,
"The editor element width was persisted"
);
await toggleLayout(hud);
ok(!getEditorEl().style.width, "The width isn't applied in in-line layout");
await toggleLayout(hud);
is(
getEditorEl().style.width,
`${newWidth}px`,
"The width is applied again when switching back to editor"
);
}
async function resize(resizer, clientX) {
const doc = resizer.ownerDocument;
const win = doc.defaultView;
info("Mouse down to start dragging");
EventUtils.synthesizeMouseAtCenter(
resizer,
{ button: 0, type: "mousedown" },
win
);
await waitFor(() => doc.querySelector(".dragging"));
const event = new MouseEvent("mousemove", { clientX });
resizer.ownerDocument.dispatchEvent(event);
info("Mouse up to stop resizing");
EventUtils.synthesizeMouseAtCenter(
doc.body,
{ button: 0, type: "mouseup" },
win
);
await waitFor(() => !doc.querySelector(".dragging"));
}

View File

@ -29,24 +29,31 @@ async function performTest() {
await pushPref(EDITOR_PREF, false);
let hud = await openNewTabAndConsole(TEST_URI);
const INPUT_VALUE = "hello";
setInputValue(hud, INPUT_VALUE);
is(isEditorModeEnabled(hud), false, "The console isn't in editor mode");
info("Enable the editor mode");
await toggleLayout(hud);
is(isEditorModeEnabled(hud), true, "Editor mode is enabled");
is(getInputValue(hud), INPUT_VALUE, "The input value wasn't cleared");
info("Close the console and reopen it");
await closeConsole();
hud = await openConsole();
is(isEditorModeEnabled(hud), true, "Editor mode is still enabled");
setInputValue(hud, INPUT_VALUE);
info("Disable the editor mode");
await toggleLayout(hud);
is(isEditorModeEnabled(hud), false, "Editor was disabled");
is(getInputValue(hud), INPUT_VALUE, "The input value wasn't cleared");
info("Enable the editor mode again");
await toggleLayout(hud);
is(isEditorModeEnabled(hud), true, "Editor mode was enabled again");
is(getInputValue(hud), INPUT_VALUE, "The input value wasn't cleared");
Services.prefs.clearUserPref(EDITOR_PREF);
}

View File

@ -35,6 +35,8 @@ function getPrefsService(hud) {
Services.prefs.getIntPref(getPrefName(pref), deflt),
setBoolPref: (pref, value) =>
Services.prefs.setBoolPref(getPrefName(pref), value),
setIntPref: (pref, value) =>
Services.prefs.setIntPref(getPrefName(pref), value),
clearUserPref: pref => Services.prefs.clearUserPref(getPrefName(pref)),
getPrefName,
};