From 2c8bf5ba4e88ffee38fb56f80701b17127d5fce9 Mon Sep 17 00:00:00 2001 From: Jason Laster Date: Thu, 8 Nov 2018 11:47:46 -0500 Subject: [PATCH] Revert "Backed out changeset 6439938f550c (bug 1504057) for ESlint failure on WebReplayPlayer.js. CLOSED TREE" This reverts commit 2347809c10e196d1372508067d6e7b300724f21a. --- .../framework/components/ToolboxToolbar.js | 2 +- devtools/client/themes/toolbox.css | 13 ++ .../webreplay/components/WebReplayPlayer.js | 145 +++++++++++++++--- 3 files changed, 134 insertions(+), 26 deletions(-) diff --git a/devtools/client/framework/components/ToolboxToolbar.js b/devtools/client/framework/components/ToolboxToolbar.js index 495446eb35c6..9e6069e364fc 100644 --- a/devtools/client/framework/components/ToolboxToolbar.js +++ b/devtools/client/framework/components/ToolboxToolbar.js @@ -444,7 +444,7 @@ class ToolboxToolbar extends Component { return div( {}, WebReplayPlayer({ - threadClient: toolbox.threadClient, + toolbox: toolbox, }), toolbar, ); diff --git a/devtools/client/themes/toolbox.css b/devtools/client/themes/toolbox.css index ed4f4ae90f25..0c12531e3e83 100644 --- a/devtools/client/themes/toolbox.css +++ b/devtools/client/themes/toolbox.css @@ -455,6 +455,18 @@ background: #B7B6B6; } +.webreplay-player .message { + position: absolute; + height: 100%; + width: 2px; + background: var(--blue-50); +} + +.webreplay-player .message:hover { + background: var(--blue-40); + cursor: pointer; +} + .webreplay-player .commands { display: flex; } @@ -493,3 +505,4 @@ margin-left: 5px; margin-right: 10px; } + diff --git a/devtools/client/webreplay/components/WebReplayPlayer.js b/devtools/client/webreplay/components/WebReplayPlayer.js index 74054ab8eed9..3ec5a01b662c 100644 --- a/devtools/client/webreplay/components/WebReplayPlayer.js +++ b/devtools/client/webreplay/components/WebReplayPlayer.js @@ -11,44 +11,112 @@ const { div } = dom; class WebReplayPlayer extends Component { static get propTypes() { return { - threadClient: PropTypes.object, + toolbox: PropTypes.object, }; } constructor(props) { super(props); - this.state = { progress: 0 }; + this.state = { + executionPoint: null, + recordingEndpoint: null, + seeking: false, + messages: [], + }; } componentDidMount() { - this.props.threadClient.addListener("paused", this.dispatchPaused.bind(this)); - this.props.threadClient.addListener("resumed", this.dispatchResumed.bind(this)); + this.threadClient.addListener("paused", this.onPaused.bind(this)); + this.threadClient.addListener("resumed", this.onResumed.bind(this)); + this.activeConsole._client.addListener( + "consoleAPICall", + this.onMessage.bind(this) + ); } - dispatchPaused(_, packet) { - if (packet && packet.recordingProgress) { - this.setState({ progress: packet.recordingProgress }); + get threadClient() { + return this.props.toolbox.threadClient; + } + + get activeConsole() { + return this.props.toolbox.target.activeConsole; + } + + isPaused() { + const { executionPoint, seeking } = this.state; + return !!executionPoint || !!seeking; + } + + onPaused(_, packet) { + if (packet && packet.recordingEndpoint) { + const { executionPoint, recordingEndpoint } = packet; + this.setState({ executionPoint, recordingEndpoint, seeking: false }); } } - dispatchResumed(_, packet) { - this.setState({ progress: 0 }); + onResumed(_, packet) { + this.setState({ executionPoint: null }); + } + + onMessage(_, packet) { + this.setState({ messages: this.state.messages.concat(packet.message) }); + } + + seek(executionPoint) { + if (!executionPoint) { + return null; + } + + // set seeking to the current execution point to avoid a progress bar jump + this.setState({ seeking: this.state.executionPoint }); + return this.threadClient.timeWarp(executionPoint); + } + + next(ev) { + if (!ev.metaKey) { + return this.threadClient.resume(); + } + + const { messages, executionPoint } = this.state; + const seekPoint = messages + .map(m => m.executionPoint) + .filter(point => point.progress > executionPoint.progress) + .slice(0)[0]; + + return this.seek(seekPoint); + } + + previous(ev) { + if (!ev.metaKey) { + return this.threadClient.rewind(); + } + + const { messages, executionPoint } = this.state; + + const seekPoint = messages + .map(m => m.executionPoint) + .filter(point => point.progress < executionPoint.progress) + .slice(-1)[0]; + + return this.seek(seekPoint); } renderCommands() { - const { progress } = this.state; - const { threadClient } = this.props; - const paused = progress !== 0; - - if (paused) { + if (this.isPaused()) { return [ div( { className: "command-button" }, - div({ className: "rewind-button btn", onClick: () => threadClient.rewind() }) + div({ + className: "rewind-button btn", + onClick: ev => this.previous(ev), + }) ), div( { className: "command-button" }, - div({ className: "play-button btn", onClick: () => threadClient.resume() }) + div({ + className: "play-button btn", + onClick: ev => this.next(ev), + }) ), ]; } @@ -56,30 +124,57 @@ class WebReplayPlayer extends Component { return [ div( { className: "command-button" }, - div({ className: "pause-button btn", onClick: () => threadClient.interrupt() }) + div({ + className: "pause-button btn", + onClick: () => this.threadClient.interrupt(), + }) ), ]; } - render() { - const { progress } = this.state; + renderMessages() { + const messages = this.state.messages; + return messages.map((message, index) => + dom.div({ + className: "message", + style: { + left: `${this.getPercent(message.executionPoint)}%`, + }, + onClick: () => this.seek(message.executionPoint), + }) + ); + } + + getPercent(executionPoint) { + if (!executionPoint || !this.state.recordingEndpoint) { + return 0; + } + + const ratio = + executionPoint.progress / this.state.recordingEndpoint.progress; + return Math.round(ratio * 100); + } + + render() { return div( { className: "webreplay-player" }, div( { id: "overlay", className: "paused" }, div( { className: "overlay-container " }, - div( - { className: "commands" }, - ...this.renderCommands() - ), + div({ className: "commands" }, ...this.renderCommands()), div( { className: "progressBar" }, div({ className: "progress", - style: { width: `${(Math.round((progress || 0) * 10000) / 100) + "%"}` }, - }) + style: { + width: `${this.getPercent( + this.state.executionPoint || this.state.seeking + )}%`, + }, + }), + ...this.renderMessages() ) ) )