import React, { PropTypes } from 'react'; import Editor from '../components/Editor'; import Sidebar from '../components/Sidebar'; import PreviewFrame from '../components/PreviewFrame'; import Toolbar from '../components/Toolbar'; import TextOutput from '../components/TextOutput'; import Preferences from '../components/Preferences'; import NewFileModal from '../components/NewFileModal'; import NewFolderModal from '../components/NewFolderModal'; import ShareModal from '../components/ShareModal'; import KeyboardShortcutModal from '../components/KeyboardShortcutModal'; import ForceAuthentication from '../components/ForceAuthentication'; import AuthenticationError from '../components/AuthenticationError'; import Nav from '../../../components/Nav'; import Console from '../components/Console'; import Toast from '../components/Toast'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { withRouter } from 'react-router'; import * as FileActions from '../actions/files'; import * as IDEActions from '../actions/ide'; import * as ProjectActions from '../actions/project'; import * as EditorAccessibilityActions from '../actions/editorAccessibility'; import * as PreferencesActions from '../actions/preferences'; import * as UserActions from '../../User/actions'; import * as ToastActions from '../actions/toast'; import * as ConsoleActions from '../actions/console'; import { getHTMLFile } from '../reducers/files'; import SplitPane from 'react-split-pane'; import Overlay from '../../App/components/Overlay'; import SketchList from '../components/SketchList'; import About from '../components/About'; class IDEView extends React.Component { constructor(props) { super(props); this._handleConsolePaneOnDragFinished = this._handleConsolePaneOnDragFinished.bind(this); this._handleSidebarPaneOnDragFinished = this._handleSidebarPaneOnDragFinished.bind(this); this.handleGlobalKeydown = this.handleGlobalKeydown.bind(this); this.warnIfUnsavedChanges = this.warnIfUnsavedChanges.bind(this); } componentDidMount() { this.props.stopSketch(); if (this.props.params.project_id) { const id = this.props.params.project_id; if (id !== this.props.project.id) { this.props.getProject(id); } // if autosave is on and the user is the owner of the project // if (this.props.preferences.autosave // && this.isUserOwner()) { // this.autosaveInterval = setInterval(this.props.autosaveProject, 30000); // } } this.consoleSize = this.props.ide.consoleIsExpanded ? 150 : 29; this.sidebarSize = this.props.ide.sidebarIsExpanded ? 160 : 20; this.forceUpdate(); this.isMac = navigator.userAgent.toLowerCase().indexOf('mac') !== -1; document.addEventListener('keydown', this.handleGlobalKeydown, false); this.props.router.setRouteLeaveHook(this.props.route, (route) => this.warnIfUnsavedChanges(route)); window.onbeforeunload = () => this.warnIfUnsavedChanges(); document.body.className = this.props.preferences.theme; } componentWillReceiveProps(nextProps) { if (nextProps.location !== this.props.location) { this.props.setPreviousPath(this.props.location.pathname); } } componentWillUpdate(nextProps) { if (this.props.ide.consoleIsExpanded !== nextProps.ide.consoleIsExpanded) { this.consoleSize = nextProps.ide.consoleIsExpanded ? 150 : 29; } if (this.props.ide.sidebarIsExpanded !== nextProps.ide.sidebarIsExpanded) { this.sidebarSize = nextProps.ide.sidebarIsExpanded ? 160 : 20; } if (nextProps.params.project_id && !this.props.params.project_id) { if (nextProps.params.project_id !== nextProps.project.id) { this.props.getProject(nextProps.params.project_id); } } if (nextProps.preferences.theme !== this.props.preferences.theme) { document.body.className = nextProps.preferences.theme; } } componentDidUpdate(prevProps) { if (this.isUserOwner() && this.props.project.id) { if (this.props.preferences.autosave && this.props.ide.unsavedChanges && !prevProps.ide.unsavedChanges) { this.autosaveInterval = setTimeout(this.props.autosaveProject, 30000); } else if (this.autosaveInterval && !this.props.preferences.autosave && prevProps.preferences.autosave) { clearTimeout(this.autosaveInterval); this.autosaveInterval = null; } } else if (this.autosaveInterval) { clearTimeout(this.autosaveInterval); this.autosaveInterval = null; } // // if user is the owner of the project // if (this.isUserOwner()) { // // 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.autosaveProject, 30000); // // if user turns off autosave preference // } else if (this.autosaveInterval && !this.props.preferences.autosave && prevProps.preferences.autosave) { // clearInterval(this.autosaveInterval); // this.autosaveInterval = null; // } // } // if (this.autosaveInterval && (!this.props.project.id || !this.isUserOwner())) { // clearInterval(this.autosaveInterval); // this.autosaveInterval = null; // } if (this.props.route.path !== prevProps.route.path) { this.props.router.setRouteLeaveHook(this.props.route, (route) => this.warnIfUnsavedChanges(route)); } } componentWillUnmount() { clearTimeout(this.autosaveInterval); this.autosaveInterval = null; this.consoleSize = undefined; this.sidebarSize = undefined; } isUserOwner() { return this.props.project.owner && this.props.project.owner.id === this.props.user.id; } _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 }); } handleGlobalKeydown(e) { // 83 === s if (e.keyCode === 83 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac))) { e.preventDefault(); e.stopPropagation(); if (this.isUserOwner() || this.props.user.authenticated && !this.props.project.owner) { this.props.saveProject(); } // 13 === enter } else if (e.keyCode === 13 && e.shiftKey && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac))) { e.preventDefault(); e.stopPropagation(); this.props.stopSketch(); } else if (e.keyCode === 13 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac))) { e.preventDefault(); e.stopPropagation(); this.props.startSketchAndRefresh(); } else if (e.keyCode === 50 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac)) && e.shiftKey) { e.preventDefault(); this.props.setTextOutput(0); } else if (e.keyCode === 49 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac)) && e.shiftKey) { e.preventDefault(); if (this.props.preferences.textOutput === 3) { this.props.preferences.textOutput = 1; } else { this.props.preferences.textOutput += 1; } this.props.setTextOutput(this.props.preferences.textOutput); } } 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) { if (!window.confirm('Are you sure you want to leave this page? You have unsaved changes.')) { return false; } this.props.setUnsavedChanges(false); return true; } } render() { return (