Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
255 changes: 121 additions & 134 deletions src/components/Output/Output.js
Original file line number Diff line number Diff line change
@@ -1,156 +1,143 @@
import { faPlay, faTerminal } from '@fortawesome/free-solid-svg-icons';

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React from 'react';
import React, { useState, useEffect } from 'react';
import { Button } from 'reactstrap';
import { OUTPUT_ONLY } from '../../constants';
import OpenPanelButtonContainer from '../common/containers/OpenPanelButtonContainer.js';
import ViewportAwareButton from '../common/ViewportAwareButton.js';
import EditorRadio from '../TextEditor/components/EditorRadio.js';
import OpenPanelButtonContainer from '../common/containers/OpenPanelButtonContainer';
import ViewportAwareButton from '../common/ViewportAwareButton';
import EditorRadio from '../TextEditor/components/EditorRadio';

/** --------Props--------
* None
*/

class Output extends React.Component {
constructor(props) {
super(props);
this.state = {
// used for the refresh button
counter: 0,
run: 0,
showConsole: true,
};
this.firstLoad = true;
const compareProps = (prevProps, nextProps) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true should be returned when the component should not update; you reversed it

if (prevProps.mostRecentProgram !== nextProps.mostRecentProgram) {
return true;
}

//= =============React Lifecycle Functions===================//
shouldComponentUpdate = (nextProps, nextState) => {
if (this.state.showConsole !== nextState.showConsole) {
return true;
}

if (this.props.mostRecentProgram !== nextProps.mostRecentProgram) {
this.firstLoad = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This functionality is not preserved

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setFirstLoad should be called when mostRecentProgram changes

return true;
}

if (this.props.isSmall !== nextProps.isSmall) {
return true;
}

if (
this.state.run !== nextState.run
|| this.state.counter !== nextState.counter
|| this.state.showConsole !== nextState.showConsole
) {
this.firstLoad = false;
return true;
}
return false;
};

renderOpenPanelButton = () => this.props.viewMode === OUTPUT_ONLY && <OpenPanelButtonContainer />;

renderIframe = (getSrcDoc) => {
// check if getsrcdoc is a function
if (!getSrcDoc && {}.toString.call(getSrcDoc) === '[object Function]') {
console.log('Null src doc function found');
return null;
}
if (prevProps.isSmall !== nextProps.isSmall) {
return true;
}

return (
<iframe
id={`${this.state.counter} ${this.state.run}`}
key={`${this.state.counter} ${this.state.run}`}
className="editor-output-iframe"
style={{ height: `${this.props.screenHeight - 61}px` }}
srcDoc={getSrcDoc()}
src=""
title="output-iframe"
onLoad={() => {}}
/>
return false;
};

const Output = React.memo(
({
viewMode,
viewOnly,
screenHeight,
vLanguage,
language,
code,
runResult,
updateViewMode,
isSmall,
}) => {
const counter = 0;
const [run, setRun] = useState(0);
const [showConsole, setShowConsole] = useState(true);
const [firstLoad, setFirstLoad] = useState(true);

useEffect(() => {
setFirstLoad(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the shouldComponentUpdate function was refactored correctly. You should pass in a second argument to react memo. Additionally, the useEffect dependency array should correspond to line 43-45 in the old file.

}, [run, counter, showConsole]);

const renderOpenPanelButton = () => viewMode === OUTPUT_ONLY && <OpenPanelButtonContainer />;

const renderIframe = (getSrcDoc) => {
// check if getsrcdoc is a function
if (!getSrcDoc && {}.toString.call(getSrcDoc) === '[object Function]') {
// console.log('Null src doc function found');
return null;
}

return (
<iframe
id={`${counter} ${run}`}
key={`${counter} ${run}`}
className="editor-output-iframe"
style={{ height: `${screenHeight - 61}px` }}
srcDoc={getSrcDoc()}
src=""
title="output-iframe"
onLoad={() => {}}
/>
);
};

const renderOutput = () => {
const lang = viewOnly ? vLanguage : language;
const runRes = viewOnly ? code : runResult;

if (firstLoad) {
return null;
}

// if there's nothing to run, don't render an output
if (!runRes || !runRes.length) {
return null;
}

const srcDocFunc = () => lang.render(runRes, showConsole);
return renderIframe(srcDocFunc);
};

const renderRadio = () => viewMode === OUTPUT_ONLY && (
<div style={{ marginLeft: 'auto' }}>
<EditorRadio viewMode={viewMode} updateViewMode={updateViewMode} isSmall={isSmall} />
</div>
);
};

renderOutput = () => {
const language = this.props.viewOnly ? this.props.vLanguage : this.props.language;
const runResult = this.props.viewOnly ? this.props.code : this.props.runResult;
const { showConsole } = this.state;

if (this.firstLoad) {
return null;
}

// if there's nothing to run, don't render an output
if (!runResult || !runResult.length) {
return null;
}

const srcDocFunc = () => language.render(runResult, showConsole);
return this.renderIframe(srcDocFunc);
};

renderRadio = () => this.props.viewMode === OUTPUT_ONLY && (
<div style={{ marginLeft: 'auto' }}>
<EditorRadio
viewMode={this.props.viewMode}
updateViewMode={this.props.updateViewMode}
isSmall={this.props.isSmall}
/>
</div>
);

toggleConsole = () => {
this.setState((prevState) => ({ showConsole: !prevState.showConsole }));
};

renderConsoleButton = () => (
<Button
className="mx-2"
color={this.state.showConsole ? 'danger' : 'primary'}
onClick={this.toggleConsole}
title={this.state.showConsole ? 'Hide Console' : 'Show Console'}
size="lg"
>
<FontAwesomeIcon icon={faTerminal} />
</Button>
);

renderBanner = () => (
<div className="editor-output-banner">
{this.renderOpenPanelButton()}
<div style={{ flex: '1 1 auto' }}> </div>
{' '}
{/* whitespace */}
{this.renderRadio()}
{this.renderConsoleButton()}
<ViewportAwareButton

const toggleConsole = () => {
setShowConsole(!showConsole);
};

const renderConsoleButton = () => (
<Button
className="mx-2"
color="primary"
color={showConsole ? 'danger' : 'primary'}
onClick={toggleConsole}
title={showConsole ? 'Hide Console' : 'Show Console'}
size="lg"
onClick={this.runCode}
isSmall={this.props.isSmall}
icon={<FontAwesomeIcon icon={faPlay} />}
text="Run"
/>
</div>
);

runCode = () => {
this.setState((prevState) => ({
run: prevState.run + 1,
}));
};

render() {
>
<FontAwesomeIcon icon={faTerminal} />
</Button>
);

const runCode = () => {
setRun((prevRun) => prevRun + 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should just be the run state, instead of this function

};

const renderBanner = () => (
<div className="editor-output-banner">
{renderOpenPanelButton()}
<div style={{ flex: '1 1 auto' }}> </div>
{/* whitespace */}
{renderRadio()}
{renderConsoleButton()}
<ViewportAwareButton
className="mx-2"
color="primary"
size="lg"
onClick={runCode}
isSmall={isSmall}
icon={<FontAwesomeIcon icon={faPlay} />}
text="Run"
/>
</div>
);

return (
<div className="editor-output">
{this.renderBanner()}
<div>{this.renderOutput()}</div>
{renderBanner()}
<div>{renderOutput()}</div>
</div>
);
}
}
},
compareProps,
);

export default Output;