p5.js-web-editor/client/modules/IDE/pages/IDEView.js

445 lines
17 KiB
JavaScript
Raw Normal View History

2016-06-27 21:34:58 +02:00
import React, { PropTypes } from 'react';
2016-06-24 00:29:55 +02:00
import Editor from '../components/Editor';
import Sidebar from '../components/Sidebar';
2016-06-24 00:29:55 +02:00
import PreviewFrame from '../components/PreviewFrame';
import Toolbar from '../components/Toolbar';
2016-08-15 18:12:25 +02:00
import TextOutput from '../components/TextOutput';
2016-06-24 00:29:55 +02:00
import Preferences from '../components/Preferences';
import NewFileModal from '../components/NewFileModal';
2016-08-30 05:23:10 +02:00
import NewFolderModal from '../components/NewFolderModal';
2016-09-07 04:37:29 +02:00
import ShareModal from '../components/ShareModal';
2016-06-24 00:29:55 +02:00
import Nav from '../../../components/Nav';
import Console from '../components/Console';
2016-06-24 00:29:55 +02:00
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as FileActions from '../actions/files';
import * as IDEActions from '../actions/ide';
import * as ProjectActions from '../actions/project';
2016-08-11 19:29:30 +02:00
import * as EditorAccessibilityActions from '../actions/editorAccessibility';
import * as PreferencesActions from '../actions/preferences';
2016-08-28 02:46:20 +02:00
import * as UserActions from '../../User/actions';
2016-08-24 19:09:48 +02:00
import { getHTMLFile, getJSFiles, getCSSFiles } from '../reducers/files';
2016-08-11 21:41:13 +02:00
import SplitPane from 'react-split-pane';
import Overlay from '../../App/components/Overlay';
import SketchList from '../components/SketchList';
2016-08-22 18:35:59 +02:00
import About from '../components/About';
2016-06-24 00:29:55 +02:00
class IDEView extends React.Component {
constructor(props) {
super(props);
this._handleConsolePaneOnDragFinished = this._handleConsolePaneOnDragFinished.bind(this);
this._handleSidebarPaneOnDragFinished = this._handleSidebarPaneOnDragFinished.bind(this);
}
2016-06-24 00:29:55 +02:00
componentDidMount() {
2016-08-28 03:52:00 +02:00
this.props.stopSketch();
2016-06-24 00:29:55 +02:00
if (this.props.params.project_id) {
const id = this.props.params.project_id;
this.props.getProject(id);
2016-08-04 01:03:01 +02:00
// if autosave is on and the user is the owner of the project
if (this.props.preferences.autosave
&& this.props.project.owner
&& this.props.project.owner.id === this.props.user.id) {
this.autosaveInterval = setInterval(this.props.saveProject, 30000);
}
2016-06-24 00:29:55 +02:00
}
this.consoleSize = this.props.ide.consoleIsExpanded ? 180 : 29;
2016-09-04 02:29:18 +02:00
this.sidebarSize = this.props.ide.sidebarIsExpanded ? 200 : 20;
this.forceUpdate();
}
componentWillUpdate(nextProps) {
if (this.props.ide.consoleIsExpanded !== nextProps.ide.consoleIsExpanded) {
this.consoleSize = nextProps.ide.consoleIsExpanded ? 180 : 29;
}
if (this.props.ide.sidebarIsExpanded !== nextProps.ide.sidebarIsExpanded) {
2016-09-04 02:29:18 +02:00
this.sidebarSize = nextProps.ide.sidebarIsExpanded ? 200 : 20;
}
if (nextProps.params.project_id && !this.props.params.project_id) {
this.props.getProject(nextProps.params.project_id);
}
2016-06-24 00:29:55 +02:00
}
componentDidUpdate(prevProps) {
// if user is the owner of the project
if (this.props.project.owner && this.props.project.owner.id === this.props.user.id) {
// if the user turns on autosave
// or the user saves the project for the first time
if (!this.autosaveInterval &&
((this.props.preferences.autosave && !prevProps.preferences.autosave) ||
(this.props.project.id && !prevProps.project.id))) {
this.autosaveInterval = setInterval(this.props.saveProject, 30000);
// if user turns off autosave preference
} else if (this.autosaveInterval && !this.props.preferences.autosave && prevProps.preferences.autosave) {
clearInterval(this.autosaveInterval);
this.autosaveInterval = null;
}
2016-06-24 00:29:55 +02:00
}
if (this.autosaveInterval && !this.props.project.id) {
clearInterval(this.autosaveInterval);
this.autosaveInterval = null;
}
2016-06-24 00:29:55 +02:00
}
2016-08-04 01:03:01 +02:00
componentWillUnmount() {
clearInterval(this.autosaveInterval);
this.autosaveInterval = null;
this.consoleSize = undefined;
this.sidebarSize = undefined;
2016-08-04 01:03:01 +02:00
}
_handleConsolePaneOnDragFinished() {
this.consoleSize = this.refs.consolePane.state.draggedSize;
this.refs.consolePane.setState({
resized: false,
draggedSize: undefined,
});
}
_handleSidebarPaneOnDragFinished() {
console.log('setting sidebar size');
this.sidebarSize = this.refs.sidebarPane.state.draggedSize;
this.refs.sidebarPane.setState({
resized: false,
draggedSize: undefined
});
}
2016-06-24 00:29:55 +02:00
render() {
return (
<div className="ide">
<Nav
user={this.props.user}
newProject={this.props.newProject}
2016-06-24 00:29:55 +02:00
saveProject={this.props.saveProject}
2016-07-15 19:11:50 +02:00
exportProjectAsZip={this.props.exportProjectAsZip}
2016-07-15 19:36:33 +02:00
cloneProject={this.props.cloneProject}
2016-08-18 00:35:15 +02:00
project={this.props.project}
2016-08-28 02:46:20 +02:00
logoutUser={this.props.logoutUser}
2016-08-28 03:52:00 +02:00
stopSketch={this.props.stopSketch}
2016-09-07 04:37:29 +02:00
showShareModal={this.props.showShareModal}
2016-06-24 00:29:55 +02:00
/>
<Toolbar
className="Toolbar"
isPlaying={this.props.ide.isPlaying}
startSketch={this.props.startSketch}
stopSketch={this.props.stopSketch}
startTextOutput={this.props.startTextOutput}
stopTextOutput={this.props.stopTextOutput}
2016-06-24 00:29:55 +02:00
projectName={this.props.project.name}
setProjectName={this.props.setProjectName}
showEditProjectName={this.props.showEditProjectName}
hideEditProjectName={this.props.hideEditProjectName}
2016-06-24 00:29:55 +02:00
openPreferences={this.props.openPreferences}
preferencesIsVisible={this.props.ide.preferencesIsVisible}
setTextOutput={this.props.setTextOutput}
2016-07-15 17:54:47 +02:00
owner={this.props.project.owner}
project={this.props.project}
2016-06-24 00:29:55 +02:00
/>
<Preferences
isVisible={this.props.ide.preferencesIsVisible}
2016-06-24 00:29:55 +02:00
closePreferences={this.props.closePreferences}
fontSize={this.props.preferences.fontSize}
indentationAmount={this.props.preferences.indentationAmount}
setIndentation={this.props.setIndentation}
indentWithSpace={this.props.indentWithSpace}
indentWithTab={this.props.indentWithTab}
isTabIndent={this.props.preferences.isTabIndent}
setFontSize={this.props.setFontSize}
2016-08-09 22:15:28 +02:00
autosave={this.props.preferences.autosave}
setAutosave={this.props.setAutosave}
2016-08-11 20:09:59 +02:00
lintWarning={this.props.preferences.lintWarning}
setLintWarning={this.props.setLintWarning}
2016-08-12 21:50:33 +02:00
textOutput={this.props.preferences.textOutput}
setTextOutput={this.props.setTextOutput}
2016-06-24 00:29:55 +02:00
/>
2016-07-21 06:05:47 +02:00
<div className="editor-preview-container">
<SplitPane
split="vertical"
defaultSize={this.sidebarSize}
ref="sidebarPane"
onDragFinished={this._handleSidebarPaneOnDragFinished}
allowResize={this.props.ide.sidebarIsExpanded}
minSize={20}
>
2016-08-11 21:41:13 +02:00
<Sidebar
2016-07-21 06:05:47 +02:00
files={this.props.files}
2016-08-11 21:41:13 +02:00
setSelectedFile={this.props.setSelectedFile}
newFile={this.props.newFile}
isExpanded={this.props.ide.sidebarIsExpanded}
expandSidebar={this.props.expandSidebar}
collapseSidebar={this.props.collapseSidebar}
showFileOptions={this.props.showFileOptions}
hideFileOptions={this.props.hideFileOptions}
deleteFile={this.props.deleteFile}
showEditFileName={this.props.showEditFileName}
hideEditFileName={this.props.hideEditFileName}
updateFileName={this.props.updateFileName}
2016-08-30 05:23:10 +02:00
projectOptionsVisible={this.props.ide.projectOptionsVisible}
openProjectOptions={this.props.openProjectOptions}
closeProjectOptions={this.props.closeProjectOptions}
newFolder={this.props.newFolder}
2016-07-21 06:05:47 +02:00
/>
2016-08-11 21:41:13 +02:00
<SplitPane
split="vertical"
defaultSize={'50%'}
onChange={() => (this.refs.overlay.style.display = 'block')}
onDragFinished={() => (this.refs.overlay.style.display = 'none')}
>
<SplitPane
split="horizontal"
primary="second"
defaultSize={this.consoleSize}
minSize={29}
ref="consolePane"
onDragFinished={this._handleConsolePaneOnDragFinished}
allowResize={this.props.ide.consoleIsExpanded}
>
2016-08-11 21:41:13 +02:00
<Editor
2016-08-12 02:59:01 +02:00
lintWarning={this.props.preferences.lintWarning}
lintMessages={this.props.editorAccessibility.lintMessages}
updateLineNumber={this.props.updateLineNumber}
updateLintMessage={this.props.updateLintMessage}
clearLintMessage={this.props.clearLintMessage}
2016-08-11 21:41:13 +02:00
file={this.props.selectedFile}
updateFileContent={this.props.updateFileContent}
fontSize={this.props.preferences.fontSize}
indentationAmount={this.props.preferences.indentationAmount}
isTabIndent={this.props.preferences.isTabIndent}
2016-08-12 03:29:43 +02:00
files={this.props.files}
2016-08-12 02:59:01 +02:00
lintMessages={this.props.editorAccessibility.lintMessages}
2016-08-12 20:23:34 +02:00
lineNumber={this.props.editorAccessibility.lineNumber}
2016-08-11 21:41:13 +02:00
/>
<Console
consoleEvent={this.props.ide.consoleEvent}
isPlaying={this.props.ide.isPlaying}
isExpanded={this.props.ide.consoleIsExpanded}
expandConsole={this.props.expandConsole}
collapseConsole={this.props.collapseConsole}
/>
</SplitPane>
<div>
<div className="preview-frame-overlay" ref="overlay">
</div>
2016-08-16 00:06:09 +02:00
<div>
2016-08-15 18:12:25 +02:00
{(() => {
2016-08-19 18:44:44 +02:00
if ((this.props.preferences.textOutput && this.props.ide.isPlaying) || this.props.ide.isTextOutputPlaying) {
2016-08-15 18:12:25 +02:00
return (
<TextOutput />
);
}
return '';
})()}
2016-08-16 00:06:09 +02:00
</div>
2016-08-11 21:41:13 +02:00
<PreviewFrame
htmlFile={this.props.htmlFile}
jsFiles={this.props.jsFiles}
cssFiles={this.props.cssFiles}
files={this.props.files}
content={this.props.selectedFile.content}
head={
<link type="text/css" rel="stylesheet" href="/preview-styles.css" />
}
isPlaying={this.props.ide.isPlaying}
isTextOutputPlaying={this.props.ide.isTextOutputPlaying}
2016-08-12 21:50:33 +02:00
textOutput={this.props.preferences.textOutput}
2016-08-11 21:41:13 +02:00
dispatchConsoleEvent={this.props.dispatchConsoleEvent}
/>
</div>
</SplitPane>
</SplitPane>
2016-07-21 06:05:47 +02:00
</div>
2016-07-21 00:37:49 +02:00
{(() => {
if (this.props.ide.modalIsVisible) {
return (
<NewFileModal
2016-07-21 04:18:20 +02:00
canUploadMedia={this.props.user.authenticated}
2016-07-21 00:37:49 +02:00
closeModal={this.props.closeNewFileModal}
2016-08-30 20:39:37 +02:00
createFile={this.props.createFile}
2016-07-21 00:37:49 +02:00
/>
);
}
return '';
})()}
2016-08-30 05:23:10 +02:00
{(() => {
if (this.props.ide.newFolderModalVisible) {
return (
<NewFolderModal
closeModal={this.props.closeNewFolderModal}
createFolder={this.props.createFolder}
/>
);
}
return '';
})()}
{(() => { // eslint-disable-line
if (this.props.location.pathname.match(/sketches$/)) {
return (
<Overlay>
<SketchList username={this.props.params.username} />
</Overlay>
);
}
})()}
2016-08-22 18:35:59 +02:00
{(() => { // eslint-disable-line
if (this.props.location.pathname === '/about') {
return (
<Overlay>
<About />
</Overlay>
);
}
})()}
2016-09-07 04:37:29 +02:00
{(() => { // eslint-disable-line
if (this.props.ide.shareModalVisible) {
return (
<Overlay>
<ShareModal
projectId={this.props.project.id}
closeShareModal={this.props.closeShareModal}
/>
</Overlay>
);
}
})()}
2016-06-24 00:29:55 +02:00
</div>
2016-06-24 00:29:55 +02:00
);
}
}
2016-06-27 21:34:58 +02:00
IDEView.propTypes = {
params: PropTypes.shape({
project_id: PropTypes.string,
username: PropTypes.string
2016-06-27 21:34:58 +02:00
}),
location: PropTypes.shape({
pathname: PropTypes.string
}),
2016-06-27 21:34:58 +02:00
getProject: PropTypes.func.isRequired,
2016-07-21 04:18:20 +02:00
user: PropTypes.shape({
authenticated: PropTypes.bool.isRequired,
id: PropTypes.string
2016-07-21 04:18:20 +02:00
}).isRequired,
newProject: PropTypes.func.isRequired,
2016-06-27 21:34:58 +02:00
saveProject: PropTypes.func.isRequired,
ide: PropTypes.shape({
isPlaying: PropTypes.bool.isRequired,
isTextOutputPlaying: PropTypes.bool.isRequired,
2016-07-18 01:15:13 +02:00
consoleEvent: PropTypes.object,
2016-07-14 18:47:54 +02:00
modalIsVisible: PropTypes.bool.isRequired,
sidebarIsExpanded: PropTypes.bool.isRequired,
consoleIsExpanded: PropTypes.bool.isRequired,
2016-08-30 05:23:10 +02:00
preferencesIsVisible: PropTypes.bool.isRequired,
projectOptionsVisible: PropTypes.bool.isRequired,
2016-09-07 04:37:29 +02:00
newFolderModalVisible: PropTypes.bool.isRequired,
shareModalVisible: PropTypes.bool.isRequired
2016-06-27 21:34:58 +02:00
}).isRequired,
startSketch: PropTypes.func.isRequired,
stopSketch: PropTypes.func.isRequired,
startTextOutput: PropTypes.func.isRequired,
stopTextOutput: PropTypes.func.isRequired,
2016-06-27 21:34:58 +02:00
project: PropTypes.shape({
id: PropTypes.string,
2016-07-15 17:54:47 +02:00
name: PropTypes.string.isRequired,
owner: PropTypes.shape({
username: PropTypes.string,
id: PropTypes.string
2016-07-15 17:54:47 +02:00
})
2016-06-27 21:34:58 +02:00
}).isRequired,
setProjectName: PropTypes.func.isRequired,
openPreferences: PropTypes.func.isRequired,
2016-08-11 19:29:30 +02:00
editorAccessibility: PropTypes.shape({
2016-08-11 19:24:02 +02:00
lintMessages: PropTypes.array.isRequired,
2016-08-12 20:23:34 +02:00
lineNumber: PropTypes.string.isRequired
}).isRequired,
2016-08-11 19:24:02 +02:00
updateLintMessage: PropTypes.func.isRequired,
clearLintMessage: PropTypes.func.isRequired,
updateLineNumber: PropTypes.func.isRequired,
2016-06-27 21:34:58 +02:00
preferences: PropTypes.shape({
2016-07-06 17:27:39 +02:00
fontSize: PropTypes.number.isRequired,
2016-07-11 04:52:48 +02:00
indentationAmount: PropTypes.number.isRequired,
2016-08-09 22:15:28 +02:00
isTabIndent: PropTypes.bool.isRequired,
2016-08-11 20:09:59 +02:00
autosave: PropTypes.bool.isRequired,
2016-08-12 21:50:33 +02:00
lintWarning: PropTypes.bool.isRequired,
textOutput: PropTypes.bool.isRequired
2016-06-27 21:34:58 +02:00
}).isRequired,
closePreferences: PropTypes.func.isRequired,
setFontSize: PropTypes.func.isRequired,
setIndentation: PropTypes.func.isRequired,
indentWithTab: PropTypes.func.isRequired,
indentWithSpace: PropTypes.func.isRequired,
2016-08-09 22:15:28 +02:00
setAutosave: PropTypes.func.isRequired,
2016-08-11 20:09:59 +02:00
setLintWarning: PropTypes.func.isRequired,
2016-08-12 21:50:33 +02:00
setTextOutput: PropTypes.func.isRequired,
files: PropTypes.array.isRequired,
2016-07-08 20:57:22 +02:00
updateFileContent: PropTypes.func.isRequired,
selectedFile: PropTypes.shape({
id: PropTypes.string.isRequired,
2016-06-27 21:34:58 +02:00
content: PropTypes.string.isRequired
}),
2016-07-11 21:22:29 +02:00
setSelectedFile: PropTypes.func.isRequired,
htmlFile: PropTypes.object.isRequired,
2016-07-12 03:54:08 +02:00
jsFiles: PropTypes.array.isRequired,
cssFiles: PropTypes.array.isRequired,
2016-07-18 01:15:13 +02:00
dispatchConsoleEvent: PropTypes.func.isRequired,
newFile: PropTypes.func.isRequired,
2016-07-14 18:47:54 +02:00
closeNewFileModal: PropTypes.func.isRequired,
expandSidebar: PropTypes.func.isRequired,
2016-07-15 19:11:50 +02:00
collapseSidebar: PropTypes.func.isRequired,
2016-07-15 19:36:33 +02:00
exportProjectAsZip: PropTypes.func.isRequired,
cloneProject: PropTypes.func.isRequired,
expandConsole: PropTypes.func.isRequired,
collapseConsole: PropTypes.func.isRequired,
2016-08-03 21:11:59 +02:00
showFileOptions: PropTypes.func.isRequired,
hideFileOptions: PropTypes.func.isRequired,
2016-08-03 23:10:03 +02:00
deleteFile: PropTypes.func.isRequired,
showEditFileName: PropTypes.func.isRequired,
hideEditFileName: PropTypes.func.isRequired,
updateFileName: PropTypes.func.isRequired,
showEditProjectName: PropTypes.func.isRequired,
2016-08-28 02:46:20 +02:00
hideEditProjectName: PropTypes.func.isRequired,
2016-08-30 05:23:10 +02:00
logoutUser: PropTypes.func.isRequired,
openProjectOptions: PropTypes.func.isRequired,
closeProjectOptions: PropTypes.func.isRequired,
newFolder: PropTypes.func.isRequired,
closeNewFolderModal: PropTypes.func.isRequired,
2016-08-30 20:39:37 +02:00
createFolder: PropTypes.func.isRequired,
createFile: PropTypes.func.isRequired,
2016-09-07 04:37:29 +02:00
showShareModal: PropTypes.func.isRequired,
closeShareModal: PropTypes.func.isRequired
2016-06-27 21:34:58 +02:00
};
2016-06-24 00:29:55 +02:00
function mapStateToProps(state) {
return {
2016-08-24 19:09:48 +02:00
files: state.files,
selectedFile: state.files.filter(file => file.isSelected)[0],
2016-07-11 21:22:29 +02:00
htmlFile: getHTMLFile(state.files),
jsFiles: getJSFiles(state.files),
2016-07-12 03:54:08 +02:00
cssFiles: getCSSFiles(state.files),
2016-08-24 19:09:48 +02:00
ide: state.ide,
2016-06-24 00:29:55 +02:00
preferences: state.preferences,
2016-08-11 19:29:30 +02:00
editorAccessibility: state.editorAccessibility,
2016-06-24 00:29:55 +02:00
user: state.user,
project: state.project
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(Object.assign({},
2016-08-11 19:29:30 +02:00
EditorAccessibilityActions,
2016-06-24 00:29:55 +02:00
FileActions,
ProjectActions,
IDEActions,
2016-08-28 02:46:20 +02:00
PreferencesActions,
UserActions),
2016-06-24 00:29:55 +02:00
dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(IDEView);