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';
|
2016-07-06 21:09:05 +02:00
|
|
|
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';
|
2016-07-13 22:13:28 +02:00
|
|
|
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-09-07 23:47:22 +02:00
|
|
|
import KeyboardShortcutModal from '../components/KeyboardShortcutModal';
|
2016-11-29 21:51:16 +01:00
|
|
|
import ForceAuthentication from '../components/ForceAuthentication';
|
2016-06-24 00:29:55 +02:00
|
|
|
import Nav from '../../../components/Nav';
|
2016-07-18 01:06:43 +02:00
|
|
|
import Console from '../components/Console';
|
2016-09-08 01:00:52 +02:00
|
|
|
import Toast from '../components/Toast';
|
2016-06-24 00:29:55 +02:00
|
|
|
import { bindActionCreators } from 'redux';
|
|
|
|
import { connect } from 'react-redux';
|
2016-09-21 00:27:10 +02:00
|
|
|
import { withRouter } from 'react-router';
|
2016-06-24 00:29:55 +02:00
|
|
|
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';
|
2016-08-05 03:43:13 +02:00
|
|
|
import * as PreferencesActions from '../actions/preferences';
|
2016-08-28 02:46:20 +02:00
|
|
|
import * as UserActions from '../../User/actions';
|
2016-09-08 01:00:52 +02:00
|
|
|
import * as ToastActions from '../actions/toast';
|
2016-11-16 19:12:36 +01:00
|
|
|
import { getHTMLFile } from '../reducers/files';
|
2016-08-11 21:41:13 +02:00
|
|
|
import SplitPane from 'react-split-pane';
|
2016-08-15 23:06:12 +02:00
|
|
|
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-10-09 00:03:39 +02:00
|
|
|
import LoginView from '../components/LoginView';
|
|
|
|
import SignupView from '../components/SignupView';
|
2016-10-12 18:02:46 +02:00
|
|
|
import ResetPasswordView from '../components/ResetPasswordView';
|
2016-10-18 22:07:25 +02:00
|
|
|
import NewPasswordView from '../components/NewPasswordView';
|
2016-06-24 00:29:55 +02:00
|
|
|
|
|
|
|
class IDEView extends React.Component {
|
2016-08-11 22:50:31 +02:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this._handleConsolePaneOnDragFinished = this._handleConsolePaneOnDragFinished.bind(this);
|
|
|
|
this._handleSidebarPaneOnDragFinished = this._handleSidebarPaneOnDragFinished.bind(this);
|
2016-09-08 03:48:45 +02:00
|
|
|
this.handleGlobalKeydown = this.handleGlobalKeydown.bind(this);
|
2016-09-21 00:27:10 +02:00
|
|
|
this.warnIfUnsavedChanges = this.warnIfUnsavedChanges.bind(this);
|
2016-08-11 22:50:31 +02:00
|
|
|
}
|
|
|
|
|
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;
|
2016-11-11 00:49:42 +01:00
|
|
|
if (id !== this.props.project.id) {
|
|
|
|
this.props.getProject(id);
|
|
|
|
}
|
2016-08-04 01:03:01 +02:00
|
|
|
|
2016-08-10 00:45:59 +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) {
|
2016-09-08 04:20:42 +02:00
|
|
|
this.autosaveInterval = setInterval(this.props.autosaveProject, 30000);
|
2016-08-09 23:50:45 +02:00
|
|
|
}
|
2016-06-24 00:29:55 +02:00
|
|
|
}
|
2016-08-11 22:50:31 +02:00
|
|
|
|
|
|
|
this.consoleSize = this.props.ide.consoleIsExpanded ? 180 : 29;
|
2016-09-08 04:49:29 +02:00
|
|
|
this.sidebarSize = this.props.ide.sidebarIsExpanded ? 200 : 25;
|
2016-08-12 18:45:26 +02:00
|
|
|
this.forceUpdate();
|
2016-09-08 03:48:45 +02:00
|
|
|
|
|
|
|
this.isMac = navigator.userAgent.toLowerCase().indexOf('mac') !== -1;
|
|
|
|
document.addEventListener('keydown', this.handleGlobalKeydown, false);
|
2016-09-21 00:27:10 +02:00
|
|
|
|
2016-11-11 00:49:42 +01:00
|
|
|
this.props.router.setRouteLeaveHook(this.props.route, (route) => this.warnIfUnsavedChanges(route));
|
2016-09-21 00:27:10 +02:00
|
|
|
|
|
|
|
window.onbeforeunload = () => this.warnIfUnsavedChanges();
|
2016-09-22 00:52:44 +02:00
|
|
|
|
|
|
|
document.body.className = this.props.preferences.theme;
|
2016-08-11 22:50:31 +02:00
|
|
|
}
|
|
|
|
|
2016-11-10 22:13:00 +01:00
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
|
if (nextProps.location !== this.props.location) {
|
|
|
|
this.props.setPreviousPath(this.props.location.pathname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-11 22:50:31 +02:00
|
|
|
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-08 04:49:29 +02:00
|
|
|
this.sidebarSize = nextProps.ide.sidebarIsExpanded ? 200 : 25;
|
2016-08-11 22:50:31 +02:00
|
|
|
}
|
2016-08-15 23:06:12 +02:00
|
|
|
|
|
|
|
if (nextProps.params.project_id && !this.props.params.project_id) {
|
2016-11-11 00:49:42 +01:00
|
|
|
if (nextProps.params.project_id !== nextProps.project.id) {
|
|
|
|
this.props.getProject(nextProps.params.project_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nextProps.params.project_id && this.props.params.project_id) {
|
|
|
|
this.props.resetProject();
|
2016-08-15 23:06:12 +02:00
|
|
|
}
|
2016-09-22 00:52:44 +02:00
|
|
|
|
|
|
|
if (nextProps.preferences.theme !== this.props.preferences.theme) {
|
|
|
|
document.body.className = nextProps.preferences.theme;
|
|
|
|
}
|
2016-06-24 00:29:55 +02:00
|
|
|
}
|
|
|
|
|
2016-08-04 03:47:24 +02:00
|
|
|
componentDidUpdate(prevProps) {
|
2016-08-10 00:45:59 +02:00
|
|
|
// 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))) {
|
2016-09-08 04:20:42 +02:00
|
|
|
this.autosaveInterval = setInterval(this.props.autosaveProject, 30000);
|
2016-08-10 00:45:59 +02:00
|
|
|
// 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
|
|
|
}
|
2016-08-12 18:45:26 +02:00
|
|
|
|
|
|
|
if (this.autosaveInterval && !this.props.project.id) {
|
|
|
|
clearInterval(this.autosaveInterval);
|
|
|
|
this.autosaveInterval = null;
|
|
|
|
}
|
2016-09-21 00:27:10 +02:00
|
|
|
|
|
|
|
if (this.props.route.path !== prevProps.route.path) {
|
2016-11-11 00:49:42 +01:00
|
|
|
this.props.router.setRouteLeaveHook(this.props.route, (route) => this.warnIfUnsavedChanges(route));
|
2016-09-21 00:27:10 +02:00
|
|
|
}
|
2016-06-24 00:29:55 +02:00
|
|
|
}
|
|
|
|
|
2016-08-04 01:03:01 +02:00
|
|
|
componentWillUnmount() {
|
|
|
|
clearInterval(this.autosaveInterval);
|
|
|
|
this.autosaveInterval = null;
|
2016-08-12 18:45:26 +02:00
|
|
|
this.consoleSize = undefined;
|
|
|
|
this.sidebarSize = undefined;
|
2016-08-04 01:03:01 +02:00
|
|
|
}
|
|
|
|
|
2016-08-11 22:50:31 +02:00
|
|
|
_handleConsolePaneOnDragFinished() {
|
|
|
|
this.consoleSize = this.refs.consolePane.state.draggedSize;
|
|
|
|
this.refs.consolePane.setState({
|
|
|
|
resized: false,
|
|
|
|
draggedSize: undefined,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
_handleSidebarPaneOnDragFinished() {
|
|
|
|
this.sidebarSize = this.refs.sidebarPane.state.draggedSize;
|
|
|
|
this.refs.sidebarPane.setState({
|
|
|
|
resized: false,
|
|
|
|
draggedSize: undefined
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-09-08 03:48:45 +02:00
|
|
|
handleGlobalKeydown(e) {
|
2016-10-20 00:35:59 +02:00
|
|
|
// 83 === s
|
|
|
|
if (e.keyCode === 83 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac))) {
|
2016-09-08 03:48:45 +02:00
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
2016-11-03 03:19:05 +01:00
|
|
|
if (this.props.project.owner && this.props.project.owner.id === this.props.user.id) {
|
|
|
|
this.props.saveProject();
|
|
|
|
}
|
2016-10-20 00:35:59 +02:00
|
|
|
// 13 === enter
|
|
|
|
} else if (e.keyCode === 13 && e.shiftKey && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac))) {
|
2016-09-14 06:10:01 +02:00
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
this.props.stopSketch();
|
2016-10-20 00:35:59 +02:00
|
|
|
} else if (e.keyCode === 13 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac))) {
|
2016-09-14 06:10:01 +02:00
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
2016-09-29 06:54:35 +02:00
|
|
|
this.props.startSketchAndRefresh();
|
2016-11-08 18:39:46 +01:00
|
|
|
} else if (e.keyCode === 50 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac)) && e.shiftKey) {
|
|
|
|
e.preventDefault();
|
2016-11-12 17:53:02 +01:00
|
|
|
this.props.setTextOutput(0);
|
2016-11-08 18:39:46 +01:00
|
|
|
} else if (e.keyCode === 49 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac)) && e.shiftKey) {
|
|
|
|
e.preventDefault();
|
2016-11-12 17:53:02 +01:00
|
|
|
if (this.props.preferences.textOutput === 3) {
|
|
|
|
this.props.preferences.textOutput = 1;
|
|
|
|
} else {
|
|
|
|
this.props.preferences.textOutput += 1;
|
|
|
|
}
|
|
|
|
this.props.setTextOutput(this.props.preferences.textOutput);
|
2016-09-08 03:48:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-11 00:49:42 +01:00
|
|
|
warnIfUnsavedChanges(route) { // eslint-disable-line
|
|
|
|
if (route && (route.action === 'PUSH' && (route.pathname === '/login' || route.pathname === '/signup'))) {
|
|
|
|
// don't warn
|
|
|
|
} else if (route && this.props.location.pathname === '/login' || this.props.location.pathname === '/signup') {
|
|
|
|
// don't warn
|
|
|
|
} else if (this.props.ide.unsavedChanges) {
|
2016-09-21 00:27:10 +02:00
|
|
|
if (!window.confirm('Are you sure you want to leave this page? You have unsaved changes.')) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
this.props.setUnsavedChanges(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-24 00:29:55 +02:00
|
|
|
render() {
|
|
|
|
return (
|
|
|
|
<div className="ide">
|
2016-09-08 01:00:52 +02:00
|
|
|
{this.props.toast.isVisible && <Toast />}
|
2016-06-24 00:29:55 +02:00
|
|
|
<Nav
|
|
|
|
user={this.props.user}
|
2016-08-12 18:45:26 +02:00
|
|
|
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-11-29 21:51:16 +01:00
|
|
|
openForceAuthentication={this.props.openForceAuthentication}
|
2016-06-24 00:29:55 +02:00
|
|
|
/>
|
|
|
|
<Toolbar
|
|
|
|
className="Toolbar"
|
|
|
|
isPlaying={this.props.ide.isPlaying}
|
|
|
|
startSketch={this.props.startSketch}
|
|
|
|
stopSketch={this.props.stopSketch}
|
2016-08-12 22:37:38 +02:00
|
|
|
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}
|
2016-08-15 18:42:13 +02:00
|
|
|
showEditProjectName={this.props.showEditProjectName}
|
|
|
|
hideEditProjectName={this.props.hideEditProjectName}
|
2016-06-24 00:29:55 +02:00
|
|
|
openPreferences={this.props.openPreferences}
|
2016-08-01 19:55:49 +02:00
|
|
|
preferencesIsVisible={this.props.ide.preferencesIsVisible}
|
2016-08-12 22:37:38 +02:00
|
|
|
setTextOutput={this.props.setTextOutput}
|
2016-07-15 17:54:47 +02:00
|
|
|
owner={this.props.project.owner}
|
2016-08-15 18:42:13 +02:00
|
|
|
project={this.props.project}
|
2016-09-24 06:46:06 +02:00
|
|
|
infiniteLoop={this.props.ide.infiniteLoop}
|
2016-09-28 20:12:01 +02:00
|
|
|
autorefresh={this.props.preferences.autorefresh}
|
|
|
|
setAutorefresh={this.props.setAutorefresh}
|
2016-09-29 06:54:35 +02:00
|
|
|
startSketchAndRefresh={this.props.startSketchAndRefresh}
|
2016-10-19 17:47:58 +02:00
|
|
|
saveProject={this.props.saveProject}
|
2016-11-04 23:54:14 +01:00
|
|
|
currentUser={this.props.user.username}
|
2016-06-24 00:29:55 +02:00
|
|
|
/>
|
|
|
|
<Preferences
|
2016-08-01 19:55:49 +02:00
|
|
|
isVisible={this.props.ide.preferencesIsVisible}
|
2016-06-24 00:29:55 +02:00
|
|
|
closePreferences={this.props.closePreferences}
|
2016-08-05 03:43:13 +02:00
|
|
|
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-09-22 00:52:44 +02:00
|
|
|
theme={this.props.preferences.theme}
|
|
|
|
setTheme={this.props.setTheme}
|
2016-06-24 00:29:55 +02:00
|
|
|
/>
|
2016-07-21 06:05:47 +02:00
|
|
|
<div className="editor-preview-container">
|
2016-08-11 22:50:31 +02:00
|
|
|
<SplitPane
|
|
|
|
split="vertical"
|
|
|
|
defaultSize={this.sidebarSize}
|
|
|
|
ref="sidebarPane"
|
|
|
|
onDragFinished={this._handleSidebarPaneOnDragFinished}
|
|
|
|
allowResize={this.props.ide.sidebarIsExpanded}
|
2016-08-12 18:45:26 +02:00
|
|
|
minSize={20}
|
2016-08-11 22:50:31 +02:00
|
|
|
>
|
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')}
|
|
|
|
>
|
2016-08-11 22:50:31 +02:00
|
|
|
<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-09-07 22:33:01 +02:00
|
|
|
editorOptionsVisible={this.props.ide.editorOptionsVisible}
|
|
|
|
showEditorOptions={this.props.showEditorOptions}
|
|
|
|
closeEditorOptions={this.props.closeEditorOptions}
|
2016-09-07 23:47:22 +02:00
|
|
|
showKeyboardShortcutModal={this.props.showKeyboardShortcutModal}
|
2016-09-21 00:27:10 +02:00
|
|
|
setUnsavedChanges={this.props.setUnsavedChanges}
|
2016-09-12 07:31:30 +02:00
|
|
|
isPlaying={this.props.ide.isPlaying}
|
2016-09-22 00:52:44 +02:00
|
|
|
theme={this.props.preferences.theme}
|
2016-09-29 06:54:35 +02:00
|
|
|
startRefreshSketch={this.props.startRefreshSketch}
|
|
|
|
stopSketch={this.props.stopSketch}
|
|
|
|
autorefresh={this.props.preferences.autorefresh}
|
2016-11-08 19:30:41 +01:00
|
|
|
unsavedChanges={this.props.ide.unsavedChanges}
|
2016-11-09 18:52:14 +01:00
|
|
|
projectSavedTime={this.props.ide.projectSavedTime}
|
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}
|
2016-10-06 19:01:48 +02:00
|
|
|
stopSketch={this.props.stopSketch}
|
2016-08-11 21:41:13 +02:00
|
|
|
/>
|
|
|
|
</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}
|
|
|
|
files={this.props.files}
|
|
|
|
content={this.props.selectedFile.content}
|
|
|
|
isPlaying={this.props.ide.isPlaying}
|
2016-08-12 22:37:38 +02:00
|
|
|
isTextOutputPlaying={this.props.ide.isTextOutputPlaying}
|
2016-08-12 21:50:33 +02:00
|
|
|
textOutput={this.props.preferences.textOutput}
|
2016-11-23 19:35:12 +01:00
|
|
|
setTextOutput={this.props.setTextOutput}
|
2016-08-11 21:41:13 +02:00
|
|
|
dispatchConsoleEvent={this.props.dispatchConsoleEvent}
|
2016-09-28 21:20:54 +02:00
|
|
|
autorefresh={this.props.preferences.autorefresh}
|
2016-09-29 00:05:14 +02:00
|
|
|
previewIsRefreshing={this.props.ide.previewIsRefreshing}
|
|
|
|
endSketchRefresh={this.props.endSketchRefresh}
|
2016-10-06 19:01:48 +02:00
|
|
|
stopSketch={this.props.stopSketch}
|
2016-10-22 22:42:43 +02:00
|
|
|
setBlobUrl={this.props.setBlobUrl}
|
2016-08-11 21:41:13 +02:00
|
|
|
/>
|
|
|
|
</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 '';
|
|
|
|
})()}
|
2016-08-15 23:06:12 +02:00
|
|
|
{(() => { // eslint-disable-line
|
2016-08-17 21:53:25 +02:00
|
|
|
if (this.props.location.pathname.match(/sketches$/)) {
|
2016-08-15 23:06:12 +02:00
|
|
|
return (
|
|
|
|
<Overlay>
|
2016-11-10 22:13:00 +01:00
|
|
|
<SketchList
|
|
|
|
username={this.props.params.username}
|
|
|
|
previousPath={this.props.ide.previousPath}
|
|
|
|
/>
|
2016-08-15 23:06:12 +02:00
|
|
|
</Overlay>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
})()}
|
2016-08-22 18:35:59 +02:00
|
|
|
{(() => { // eslint-disable-line
|
|
|
|
if (this.props.location.pathname === '/about') {
|
|
|
|
return (
|
|
|
|
<Overlay>
|
2016-11-10 22:13:00 +01:00
|
|
|
<About previousPath={this.props.ide.previousPath} />
|
2016-08-22 18:35:59 +02:00
|
|
|
</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-09-07 23:47:22 +02:00
|
|
|
{(() => { // eslint-disable-line
|
|
|
|
if (this.props.ide.keyboardShortcutVisible) {
|
|
|
|
return (
|
|
|
|
<Overlay>
|
|
|
|
<KeyboardShortcutModal
|
|
|
|
closeModal={this.props.closeKeyboardShortcutModal}
|
|
|
|
/>
|
|
|
|
</Overlay>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
})()}
|
2016-10-09 00:03:39 +02:00
|
|
|
{(() => { // eslint-disable-line
|
|
|
|
if (this.props.location.pathname === '/login') {
|
|
|
|
return (
|
|
|
|
<Overlay>
|
2016-11-10 22:13:00 +01:00
|
|
|
<LoginView previousPath={this.props.ide.previousPath} />
|
2016-10-09 00:03:39 +02:00
|
|
|
</Overlay>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
})()}
|
|
|
|
{(() => { // eslint-disable-line
|
|
|
|
if (this.props.location.pathname === '/signup') {
|
|
|
|
return (
|
|
|
|
<Overlay>
|
2016-11-10 22:13:00 +01:00
|
|
|
<SignupView previousPath={this.props.ide.previousPath} />
|
2016-10-09 00:03:39 +02:00
|
|
|
</Overlay>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
})()}
|
2016-10-12 18:02:46 +02:00
|
|
|
{(() => { // eslint-disable-line
|
|
|
|
if (this.props.location.pathname === '/reset-password') {
|
|
|
|
return (
|
|
|
|
<Overlay>
|
|
|
|
<ResetPasswordView />
|
|
|
|
</Overlay>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
})()}
|
2016-10-18 22:07:25 +02:00
|
|
|
{(() => { // eslint-disable-line
|
2016-10-18 23:06:53 +02:00
|
|
|
if (this.props.location.pathname.match(/\/reset-password\/[a-fA-F0-9]+/)) {
|
2016-10-18 22:07:25 +02:00
|
|
|
return (
|
|
|
|
<Overlay>
|
2016-11-10 22:13:00 +01:00
|
|
|
<NewPasswordView
|
|
|
|
token={this.props.params.reset_password_token}
|
|
|
|
/>
|
2016-10-18 22:07:25 +02:00
|
|
|
</Overlay>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
})()}
|
2016-11-29 21:51:16 +01:00
|
|
|
{(() => { // eslint-disable-line
|
|
|
|
if (this.props.ide.forceAuthenticationVisible) {
|
|
|
|
return (
|
|
|
|
<Overlay>
|
|
|
|
<ForceAuthentication
|
|
|
|
closeModal={this.props.closeForceAuthentication}
|
|
|
|
/>
|
|
|
|
</Overlay>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
})()}
|
2016-06-24 00:29:55 +02:00
|
|
|
</div>
|
2016-07-18 01:06:43 +02:00
|
|
|
|
2016-06-24 00:29:55 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-27 21:34:58 +02:00
|
|
|
IDEView.propTypes = {
|
|
|
|
params: PropTypes.shape({
|
2016-08-17 21:53:25 +02:00
|
|
|
project_id: PropTypes.string,
|
2016-10-18 22:07:25 +02:00
|
|
|
username: PropTypes.string,
|
|
|
|
reset_password_token: PropTypes.string,
|
2016-06-27 21:34:58 +02:00
|
|
|
}),
|
2016-08-15 23:06:12 +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({
|
2016-08-10 00:45:59 +02:00
|
|
|
authenticated: PropTypes.bool.isRequired,
|
2016-11-04 23:54:14 +01:00
|
|
|
id: PropTypes.string,
|
|
|
|
username: PropTypes.string
|
2016-07-21 04:18:20 +02:00
|
|
|
}).isRequired,
|
2016-08-12 18:45:26 +02:00
|
|
|
newProject: PropTypes.func.isRequired,
|
2016-06-27 21:34:58 +02:00
|
|
|
saveProject: PropTypes.func.isRequired,
|
|
|
|
ide: PropTypes.shape({
|
2016-07-13 22:13:28 +02:00
|
|
|
isPlaying: PropTypes.bool.isRequired,
|
2016-08-12 22:37:38 +02:00
|
|
|
isTextOutputPlaying: PropTypes.bool.isRequired,
|
2016-10-06 22:58:14 +02:00
|
|
|
consoleEvent: PropTypes.array,
|
2016-07-14 18:47:54 +02:00
|
|
|
modalIsVisible: PropTypes.bool.isRequired,
|
2016-07-21 06:33:41 +02:00
|
|
|
sidebarIsExpanded: PropTypes.bool.isRequired,
|
2016-08-01 19:55:49 +02:00
|
|
|
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,
|
2016-09-07 22:33:01 +02:00
|
|
|
shareModalVisible: PropTypes.bool.isRequired,
|
2016-09-07 23:47:22 +02:00
|
|
|
editorOptionsVisible: PropTypes.bool.isRequired,
|
2016-09-21 00:27:10 +02:00
|
|
|
keyboardShortcutVisible: PropTypes.bool.isRequired,
|
2016-09-21 00:32:26 +02:00
|
|
|
unsavedChanges: PropTypes.bool.isRequired,
|
|
|
|
infiniteLoop: PropTypes.bool.isRequired,
|
2016-10-06 21:45:26 +02:00
|
|
|
previewIsRefreshing: PropTypes.bool.isRequired,
|
2016-11-09 18:52:14 +01:00
|
|
|
infiniteLoopMessage: PropTypes.string.isRequired,
|
2016-11-10 22:13:00 +01:00
|
|
|
projectSavedTime: PropTypes.string.isRequired,
|
2016-11-29 21:51:16 +01:00
|
|
|
previousPath: PropTypes.string.isRequired,
|
|
|
|
forceAuthenticationVisible: PropTypes.bool.isRequired
|
2016-06-27 21:34:58 +02:00
|
|
|
}).isRequired,
|
|
|
|
startSketch: PropTypes.func.isRequired,
|
|
|
|
stopSketch: PropTypes.func.isRequired,
|
2016-08-12 22:37:38 +02:00
|
|
|
startTextOutput: PropTypes.func.isRequired,
|
|
|
|
stopTextOutput: PropTypes.func.isRequired,
|
2016-09-12 07:31:30 +02:00
|
|
|
detectInfiniteLoops: PropTypes.func.isRequired,
|
|
|
|
resetInfiniteLoops: PropTypes.func.isRequired,
|
2016-06-27 21:34:58 +02:00
|
|
|
project: PropTypes.shape({
|
2016-08-04 03:47:24 +02:00
|
|
|
id: PropTypes.string,
|
2016-07-15 17:54:47 +02:00
|
|
|
name: PropTypes.string.isRequired,
|
|
|
|
owner: PropTypes.shape({
|
2016-08-10 00:45:59 +02:00
|
|
|
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
|
2016-08-10 17:13:17 +02:00
|
|
|
}).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,
|
2016-11-12 17:53:02 +01:00
|
|
|
textOutput: PropTypes.number.isRequired,
|
2016-09-28 20:12:01 +02:00
|
|
|
theme: PropTypes.string.isRequired,
|
|
|
|
autorefresh: PropTypes.bool.isRequired
|
2016-06-27 21:34:58 +02:00
|
|
|
}).isRequired,
|
|
|
|
closePreferences: PropTypes.func.isRequired,
|
2016-08-05 03:43:13 +02:00
|
|
|
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,
|
2016-07-06 21:09:05 +02:00
|
|
|
files: PropTypes.array.isRequired,
|
2016-07-08 20:57:22 +02:00
|
|
|
updateFileContent: PropTypes.func.isRequired,
|
|
|
|
selectedFile: PropTypes.shape({
|
2016-07-08 21:58:49 +02:00
|
|
|
id: PropTypes.string.isRequired,
|
2016-06-27 21:34:58 +02:00
|
|
|
content: PropTypes.string.isRequired
|
2016-07-08 21:58:49 +02:00
|
|
|
}),
|
2016-07-11 21:22:29 +02:00
|
|
|
setSelectedFile: PropTypes.func.isRequired,
|
|
|
|
htmlFile: PropTypes.object.isRequired,
|
2016-07-18 01:15:13 +02:00
|
|
|
dispatchConsoleEvent: PropTypes.func.isRequired,
|
2016-07-13 22:13:28 +02:00
|
|
|
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,
|
2016-07-21 06:33:41 +02:00
|
|
|
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,
|
2016-08-15 18:42:13 +02:00
|
|
|
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,
|
2016-09-07 22:33:01 +02:00
|
|
|
closeShareModal: PropTypes.func.isRequired,
|
|
|
|
showEditorOptions: PropTypes.func.isRequired,
|
2016-09-07 23:47:22 +02:00
|
|
|
closeEditorOptions: PropTypes.func.isRequired,
|
|
|
|
showKeyboardShortcutModal: PropTypes.func.isRequired,
|
2016-09-08 01:00:52 +02:00
|
|
|
closeKeyboardShortcutModal: PropTypes.func.isRequired,
|
|
|
|
toast: PropTypes.shape({
|
|
|
|
isVisible: PropTypes.bool.isRequired
|
|
|
|
}).isRequired,
|
2016-09-08 04:20:42 +02:00
|
|
|
showToast: PropTypes.func.isRequired,
|
|
|
|
setToastText: PropTypes.func.isRequired,
|
2016-09-21 00:27:10 +02:00
|
|
|
autosaveProject: PropTypes.func.isRequired,
|
|
|
|
router: PropTypes.shape({
|
|
|
|
setRouteLeaveHook: PropTypes.func
|
|
|
|
}).isRequired,
|
|
|
|
route: PropTypes.object.isRequired,
|
2016-09-13 20:15:46 +02:00
|
|
|
setUnsavedChanges: PropTypes.func.isRequired,
|
|
|
|
setTheme: PropTypes.func.isRequired,
|
2016-09-29 00:05:14 +02:00
|
|
|
setAutorefresh: PropTypes.func.isRequired,
|
2016-09-29 06:54:35 +02:00
|
|
|
startSketchAndRefresh: PropTypes.func.isRequired,
|
2016-09-29 00:05:14 +02:00
|
|
|
endSketchRefresh: PropTypes.func.isRequired,
|
2016-10-22 22:42:43 +02:00
|
|
|
startRefreshSketch: PropTypes.func.isRequired,
|
2016-11-10 22:13:00 +01:00
|
|
|
setBlobUrl: PropTypes.func.isRequired,
|
2016-11-11 00:49:42 +01:00
|
|
|
setPreviousPath: PropTypes.func.isRequired,
|
2016-11-29 21:51:16 +01:00
|
|
|
resetProject: PropTypes.func.isRequired,
|
|
|
|
closeForceAuthentication: PropTypes.func.isRequired,
|
|
|
|
openForceAuthentication: 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,
|
2016-09-14 22:41:36 +02:00
|
|
|
selectedFile: state.files.find(file => file.isSelectedFile),
|
2016-07-11 21:22:29 +02:00
|
|
|
htmlFile: getHTMLFile(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,
|
2016-09-08 01:00:52 +02:00
|
|
|
project: state.project,
|
|
|
|
toast: state.toast
|
2016-06-24 00:29:55 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2016-08-05 03:43:13 +02:00
|
|
|
IDEActions,
|
2016-08-28 02:46:20 +02:00
|
|
|
PreferencesActions,
|
2016-09-08 01:00:52 +02:00
|
|
|
UserActions,
|
|
|
|
ToastActions),
|
2016-06-24 00:29:55 +02:00
|
|
|
dispatch);
|
|
|
|
}
|
|
|
|
|
2016-09-21 00:27:10 +02:00
|
|
|
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(IDEView));
|