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

634 lines
24 KiB
React
Raw Normal View History

import PropTypes from 'prop-types';
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import { Helmet } from 'react-helmet';
import SplitPane from 'react-split-pane';
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';
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-09-07 23:47:22 +02:00
import KeyboardShortcutModal from '../components/KeyboardShortcutModal';
import ErrorModal from '../components/ErrorModal';
2017-09-14 20:51:36 +02:00
import HTTPSModal from '../components/HTTPSModal';
2016-06-24 00:29:55 +02:00
import Nav from '../../../components/Nav';
import Console from '../components/Console';
import Toast from '../components/Toast';
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';
import * as PreferencesActions from '../actions/preferences';
2016-08-28 02:46:20 +02:00
import * as UserActions from '../../User/actions';
import * as ToastActions from '../actions/toast';
import * as ConsoleActions from '../actions/console';
cool to share some of this code between client and server Squashed commit of the following: commit fb5e82cea930b011792983c7d1cc9f6ecacc7dd4 Author: Cassie Tarakajian <ctarakajian@gmail.com> Date: Wed Nov 16 12:28:10 2016 -0500 add server side rendering, untested commit 5c60fb30c46ea49a8d9a0ecb56f39ec778464a8b Author: Cassie Tarakajian <ctarakajian@gmail.com> Date: Tue Nov 15 18:26:06 2016 -0500 add redux-form bandage post react update, should probably update to redux-form 6 at some point commit 057b5871e7137179abc93f7821a9690f0ea52c92 Author: Cassie Tarakajian <ctarakajian@gmail.com> Date: Tue Nov 15 16:30:09 2016 -0500 remove passing jsFiles and cssFiles to PreviewFrame, fix rendering bug commit 88c56fd36d3a8d88902c79642171988ce37825f2 Author: Cassie Tarakajian <ctarakajian@gmail.com> Date: Tue Nov 15 16:21:59 2016 -0500 code cleanup, untested commit 82e5dcf8bca461892f1daf06d38f1eaebe72983f Author: Cassie Tarakajian <ctarakajian@gmail.com> Date: Tue Nov 15 15:53:50 2016 -0500 update react and react router, fix a few bugs in rendering code, add ability to parse inline js and css commit e02f4b67803ea45328eff4e53659222f3149964c Author: Cassie Tarakajian <ctarakajian@gmail.com> Date: Tue Nov 15 14:43:38 2016 -0500 add almost full code to create preview html correctly, untested commit 12f61b2a1aed4607fab24d01572b647ca6210262 Author: Cassie Tarakajian <ctarakajian@gmail.com> Date: Wed Nov 2 17:09:26 2016 -0400 refactor some of the preview html generation code commit 111825846703d5c8959cb18795a3aadb7ebe505c Author: Cassie Tarakajian <ctarakajian@gmail.com> Date: Wed Nov 2 11:06:36 2016 -0400 add comments as plan of action commit 1cc2cf5203674732b4057382f1937de38b687078 Author: Cassie Tarakajian <ctarakajian@gmail.com> Date: Thu Oct 27 19:34:55 2016 -0400 add href parsing commit e67189298cda9b70645f454ecd541a363980f0e4 Author: Cassie Tarakajian <ctarakajian@gmail.com> Date: Thu Oct 27 10:48:36 2016 -0400 continue parsing html commit 1458fb940a15a3dc5d74890211a3073e920b84b8 Author: Cassie Tarakajian <ctarakajian@gmail.com> Date: Wed Oct 26 17:40:31 2016 -0400 start to add html parsing
2016-11-16 19:12:36 +01:00
import { getHTMLFile } from '../reducers/files';
import Overlay from '../../App/components/Overlay';
import SketchList from '../components/SketchList';
import AssetList from '../components/AssetList';
2016-08-22 18:35:59 +02:00
import About from '../components/About';
2018-02-09 22:32:06 +01:00
import Feedback from '../components/Feedback';
2016-06-24 00:29:55 +02:00
class IDEView extends React.Component {
constructor(props) {
super(props);
this.handleGlobalKeydown = this.handleGlobalKeydown.bind(this);
this.warnIfUnsavedChanges = this.warnIfUnsavedChanges.bind(this);
2019-03-05 22:25:34 +01:00
this.state = {
consoleSize: props.ide.consoleIsExpanded ? 150 : 29,
sidebarSize: props.ide.sidebarIsExpanded ? 160 : 20
};
}
2016-06-24 00:29:55 +02:00
componentDidMount() {
// If page doesn't reload after Sign In then we need
// to force cleared state to be cleared
this.props.clearPersistedState();
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-06-24 00:29:55 +02:00
}
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();
2016-09-22 00:52:44 +02:00
document.body.className = this.props.preferences.theme;
this.autosaveInterval = null;
}
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) {
this.props.setPreviousPath(this.props.location.pathname);
}
if (this.props.ide.consoleIsExpanded !== nextProps.ide.consoleIsExpanded) {
2019-03-05 22:25:34 +01:00
this.setState({ consoleSize: nextProps.ide.consoleIsExpanded ? 150 : 29 });
}
if (this.props.ide.sidebarIsExpanded !== nextProps.ide.sidebarIsExpanded) {
2019-03-05 22:25:34 +01:00
this.setState({ sidebarSize: nextProps.ide.sidebarIsExpanded ? 160 : 20 });
}
2019-03-05 22:25:34 +01:00
}
2019-03-05 22:25:34 +01:00
componentWillUpdate(nextProps) {
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);
}
}
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
}
componentDidUpdate(prevProps) {
2017-01-18 22:43:41 +01:00
if (this.isUserOwner() && this.props.project.id) {
if (this.props.preferences.autosave && this.props.ide.unsavedChanges && !this.props.ide.justOpenedProject) {
2017-06-06 04:33:32 +02:00
if (
this.props.selectedFile.name === prevProps.selectedFile.name &&
this.props.selectedFile.content !== prevProps.selectedFile.content) {
if (this.autosaveInterval) {
clearTimeout(this.autosaveInterval);
}
console.log('will save project in 20 seconds');
this.autosaveInterval = setTimeout(this.props.autosaveProject, 20000);
}
} else if (this.autosaveInterval && !this.props.preferences.autosave) {
2017-01-18 22:43:41 +01:00
clearTimeout(this.autosaveInterval);
this.autosaveInterval = null;
}
2017-01-18 22:43:41 +01:00
} else if (this.autosaveInterval) {
clearTimeout(this.autosaveInterval);
this.autosaveInterval = null;
}
if (this.props.route.path !== prevProps.route.path) {
this.props.router.setRouteLeaveHook(this.props.route, route => this.warnIfUnsavedChanges(route));
}
2016-06-24 00:29:55 +02:00
}
2016-08-04 01:03:01 +02:00
componentWillUnmount() {
2018-03-02 18:26:20 +01:00
document.removeEventListener('keydown', this.handleGlobalKeydown, false);
2017-01-18 22:43:41 +01:00
clearTimeout(this.autosaveInterval);
2016-08-04 01:03:01 +02:00
this.autosaveInterval = null;
}
2016-12-09 20:33:21 +01:00
isUserOwner() {
return this.props.project.owner && this.props.project.owner.id === this.props.user.id;
}
handleGlobalKeydown(e) {
2016-10-20 00:35:59 +02:00
// 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(this.cmController.getContent());
} else if (this.props.user.authenticated) {
this.props.cloneProject();
} else {
this.props.showErrorModal('forceAuthentication');
}
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))) {
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))) {
e.preventDefault();
e.stopPropagation();
this.props.startSketch();
// 50 === 2
} else if (e.keyCode === 50 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac)) && e.shiftKey) {
e.preventDefault();
this.props.setAllAccessibleOutput(false);
// 49 === 1
} else if (e.keyCode === 49 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac)) && e.shiftKey) {
e.preventDefault();
this.props.setAllAccessibleOutput(true);
}
}
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
this.props.persistState();
window.onbeforeunload = null;
} else if (route && (this.props.location.pathname === '/login' || this.props.location.pathname === '/signup')) {
2016-11-11 00:49:42 +01:00
// don't warn
this.props.persistState();
window.onbeforeunload = null;
2016-11-11 00:49:42 +01:00
} 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);
2017-01-05 21:27:57 +01:00
return true;
}
}
2016-06-24 00:29:55 +02:00
render() {
return (
<div className="ide">
<Helmet>
<title>p5.js Web Editor | {this.props.project.name}</title>
</Helmet>
{this.props.toast.isVisible && <Toast />}
2016-06-24 00:29:55 +02:00
<Nav
2017-01-05 21:27:57 +01:00
warnIfUnsavedChanges={this.warnIfUnsavedChanges}
2017-09-01 18:40:15 +02:00
cmController={this.cmController}
2016-06-24 00:29:55 +02:00
/>
<Toolbar />
2017-11-14 01:09:08 +01:00
{this.props.ide.preferencesIsVisible &&
<Overlay
title="Settings"
ariaLabel="settings"
closeOverlay={this.props.closePreferences}
>
<Preferences
fontSize={this.props.preferences.fontSize}
setFontSize={this.props.setFontSize}
autosave={this.props.preferences.autosave}
linewrap={this.props.preferences.linewrap}
2017-11-14 01:09:08 +01:00
setAutosave={this.props.setAutosave}
setLinewrap={this.props.setLinewrap}
2017-11-14 01:09:08 +01:00
lintWarning={this.props.preferences.lintWarning}
setLintWarning={this.props.setLintWarning}
textOutput={this.props.preferences.textOutput}
gridOutput={this.props.preferences.gridOutput}
soundOutput={this.props.preferences.soundOutput}
setTextOutput={this.props.setTextOutput}
setGridOutput={this.props.setGridOutput}
setSoundOutput={this.props.setSoundOutput}
theme={this.props.preferences.theme}
setTheme={this.props.setTheme}
/>
</Overlay>
}
2016-07-21 06:05:47 +02:00
<div className="editor-preview-container">
<SplitPane
split="vertical"
2019-03-05 22:25:34 +01:00
size={this.state.sidebarSize}
onChange={size => this.setState({ sidebarSize: size })}
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}
deleteFile={this.props.deleteFile}
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}
user={this.props.user}
owner={this.props.project.owner}
2016-07-21 06:05:47 +02:00
/>
2016-08-11 21:41:13 +02:00
<SplitPane
split="vertical"
2018-05-05 02:22:39 +02:00
defaultSize="50%"
onChange={() => { this.overlay.style.display = 'block'; }}
onDragFinished={() => { this.overlay.style.display = 'none'; }}
resizerStyle={{
borderLeftWidth: '2px', borderRightWidth: '2px', width: '2px', margin: '0px 0px'
}}
2016-08-11 21:41:13 +02:00
>
<SplitPane
split="horizontal"
primary="second"
2019-03-05 22:25:34 +01:00
size={this.state.consoleSize}
minSize={29}
2019-03-05 22:25:34 +01:00
onChange={size => this.setState({ consoleSize: size })}
allowResize={this.props.ide.consoleIsExpanded}
className="editor-preview-subpanel"
>
2016-08-11 21:41:13 +02:00
<Editor
2016-08-12 02:59:01 +02:00
lintWarning={this.props.preferences.lintWarning}
linewrap={this.props.preferences.linewrap}
2016-08-12 02:59:01 +02:00
lintMessages={this.props.editorAccessibility.lintMessages}
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}
2016-08-12 03:29:43 +02:00
files={this.props.files}
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}
setUnsavedChanges={this.props.setUnsavedChanges}
isPlaying={this.props.ide.isPlaying}
2016-09-22 00:52:44 +02:00
theme={this.props.preferences.theme}
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}
projectSavedTime={this.props.project.updatedAt}
isExpanded={this.props.ide.sidebarIsExpanded}
expandSidebar={this.props.expandSidebar}
collapseSidebar={this.props.collapseSidebar}
isUserOwner={this.isUserOwner()}
clearConsole={this.props.clearConsole}
2017-07-17 23:27:21 +02:00
consoleEvents={this.props.console}
showRuntimeErrorWarning={this.props.showRuntimeErrorWarning}
hideRuntimeErrorWarning={this.props.hideRuntimeErrorWarning}
runtimeErrorWarningVisible={this.props.ide.runtimeErrorWarningVisible}
2017-09-01 18:40:15 +02:00
provideController={(ctl) => { this.cmController = ctl; }}
2016-08-11 21:41:13 +02:00
/>
<Console
2018-09-13 04:00:19 +02:00
fontSize={this.props.preferences.fontSize}
consoleEvents={this.props.console}
2016-08-11 21:41:13 +02:00
isExpanded={this.props.ide.consoleIsExpanded}
expandConsole={this.props.expandConsole}
collapseConsole={this.props.collapseConsole}
clearConsole={this.props.clearConsole}
dispatchConsoleEvent={this.props.dispatchConsoleEvent}
theme={this.props.preferences.theme}
2016-08-11 21:41:13 +02:00
/>
</SplitPane>
<div className="preview-frame-holder">
2017-03-02 21:01:33 +01:00
<header className="preview-frame__header">
<h2 className="preview-frame__title">Preview</h2>
</header>
<div className="preview-frame__content">
<div className="preview-frame-overlay" ref={(element) => { this.overlay = element; }}>
</div>
<div>
{(
(
(this.props.preferences.textOutput ||
this.props.preferences.gridOutput ||
this.props.preferences.soundOutput
) &&
this.props.ide.isPlaying
) ||
this.props.ide.isAccessibleOutputPlaying
)
}
</div>
<PreviewFrame
htmlFile={this.props.htmlFile}
files={this.props.files}
content={this.props.selectedFile.content}
isPlaying={this.props.ide.isPlaying}
isAccessibleOutputPlaying={this.props.ide.isAccessibleOutputPlaying}
textOutput={this.props.preferences.textOutput}
gridOutput={this.props.preferences.gridOutput}
soundOutput={this.props.preferences.soundOutput}
setTextOutput={this.props.setTextOutput}
setGridOutput={this.props.setGridOutput}
setSoundOutput={this.props.setSoundOutput}
dispatchConsoleEvent={this.props.dispatchConsoleEvent}
autorefresh={this.props.preferences.autorefresh}
previewIsRefreshing={this.props.ide.previewIsRefreshing}
endSketchRefresh={this.props.endSketchRefresh}
stopSketch={this.props.stopSketch}
setBlobUrl={this.props.setBlobUrl}
expandConsole={this.props.expandConsole}
2019-04-30 23:44:41 +02:00
clearConsole={this.props.clearConsole}
cmController={this.cmController}
/>
2016-08-11 21:41:13 +02:00
</div>
</div>
</SplitPane>
</SplitPane>
2016-07-21 06:05:47 +02:00
</div>
2017-11-13 20:44:23 +01:00
{ this.props.ide.modalIsVisible &&
<NewFileModal
canUploadMedia={this.props.user.authenticated}
closeModal={this.props.closeNewFileModal}
createFile={this.props.createFile}
/>
}
{ this.props.ide.newFolderModalVisible &&
<NewFolderModal
closeModal={this.props.closeNewFolderModal}
createFolder={this.props.createFolder}
/>
}
{ this.props.location.pathname.match(/sketches$/) &&
<Overlay
ariaLabel="project list"
title="Open a Sketch"
previousPath={this.props.ide.previousPath}
>
<SketchList
username={this.props.params.username}
user={this.props.user}
/>
</Overlay>
}
{ this.props.location.pathname.match(/assets$/) &&
<Overlay
title="Assets"
ariaLabel="asset list"
previousPath={this.props.ide.previousPath}
>
<AssetList
username={this.props.params.username}
user={this.props.user}
/>
</Overlay>
}
{ this.props.location.pathname === '/about' &&
<Overlay
previousPath={this.props.ide.previousPath}
title="Welcome"
ariaLabel="about"
>
<About previousPath={this.props.ide.previousPath} />
</Overlay>
}
2018-02-09 22:32:06 +01:00
{ this.props.location.pathname === '/feedback' &&
<Overlay
previousPath={this.props.ide.previousPath}
title="Submit Feedback"
ariaLabel="submit-feedback"
>
<Feedback previousPath={this.props.ide.previousPath} />
</Overlay>
}
2017-11-13 20:44:23 +01:00
{ this.props.ide.shareModalVisible &&
<Overlay
title="Share This Sketch"
ariaLabel="share"
closeOverlay={this.props.closeShareModal}
>
<ShareModal
projectId={this.props.project.id}
projectName={this.props.project.name}
ownerUsername={this.props.project.owner.username}
/>
</Overlay>
}
{ this.props.ide.keyboardShortcutVisible &&
<Overlay
title="Keyboard Shortcuts"
ariaLabel="keyboard shortcuts"
closeOverlay={this.props.closeKeyboardShortcutModal}
>
<KeyboardShortcutModal />
</Overlay>
}
{ this.props.ide.errorType &&
<Overlay
title="Error"
ariaLabel="error"
2018-03-02 18:26:20 +01:00
closeOverlay={this.props.hideErrorModal}
2017-11-13 20:44:23 +01:00
>
<ErrorModal
type={this.props.ide.errorType}
closeModal={this.props.hideErrorModal}
2017-11-13 20:44:23 +01:00
/>
</Overlay>
}
{ this.props.ide.helpType &&
<Overlay
title="Serve over HTTPS"
closeOverlay={this.props.hideHelpModal}
>
<HTTPSModal />
</Overlay>
}
2016-06-24 00:29:55 +02:00
</div>
);
}
}
2016-06-27 21:34:58 +02:00
IDEView.propTypes = {
params: PropTypes.shape({
project_id: PropTypes.string,
username: PropTypes.string,
reset_password_token: PropTypes.string,
}).isRequired,
location: PropTypes.shape({
pathname: PropTypes.string
}).isRequired,
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,
2016-11-04 23:54:14 +01:00
id: PropTypes.string,
username: PropTypes.string
2016-07-21 04:18:20 +02:00
}).isRequired,
2016-06-27 21:34:58 +02:00
saveProject: PropTypes.func.isRequired,
ide: PropTypes.shape({
isPlaying: PropTypes.bool.isRequired,
isAccessibleOutputPlaying: PropTypes.bool.isRequired,
consoleEvent: PropTypes.array,
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,
2016-09-07 22:33:01 +02:00
shareModalVisible: PropTypes.bool.isRequired,
2016-09-07 23:47:22 +02:00
editorOptionsVisible: PropTypes.bool.isRequired,
keyboardShortcutVisible: PropTypes.bool.isRequired,
2016-09-21 00:32:26 +02:00
unsavedChanges: PropTypes.bool.isRequired,
infiniteLoop: PropTypes.bool.isRequired,
previewIsRefreshing: PropTypes.bool.isRequired,
infiniteLoopMessage: PropTypes.string.isRequired,
projectSavedTime: PropTypes.string,
previousPath: PropTypes.string.isRequired,
justOpenedProject: PropTypes.bool.isRequired,
errorType: PropTypes.string,
helpType: PropTypes.string,
runtimeErrorWarningVisible: PropTypes.bool.isRequired,
2016-06-27 21:34:58 +02:00
}).isRequired,
stopSketch: PropTypes.func.isRequired,
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
}),
updatedAt: PropTypes.string
2016-06-27 21:34:58 +02:00
}).isRequired,
2016-08-11 19:29:30 +02:00
editorAccessibility: PropTypes.shape({
2016-08-11 19:24:02 +02:00
lintMessages: PropTypes.array.isRequired,
}).isRequired,
2016-08-11 19:24:02 +02:00
updateLintMessage: PropTypes.func.isRequired,
clearLintMessage: 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-08-11 20:09:59 +02:00
autosave: PropTypes.bool.isRequired,
linewrap: PropTypes.bool.isRequired,
2016-08-12 21:50:33 +02:00
lintWarning: PropTypes.bool.isRequired,
textOutput: PropTypes.bool.isRequired,
gridOutput: PropTypes.bool.isRequired,
soundOutput: PropTypes.bool.isRequired,
theme: PropTypes.string.isRequired,
autorefresh: PropTypes.bool.isRequired
2016-06-27 21:34:58 +02:00
}).isRequired,
closePreferences: PropTypes.func.isRequired,
setFontSize: PropTypes.func.isRequired,
2016-08-09 22:15:28 +02:00
setAutosave: PropTypes.func.isRequired,
setLinewrap: 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,
setGridOutput: PropTypes.func.isRequired,
setSoundOutput: PropTypes.func.isRequired,
setAllAccessibleOutput: PropTypes.func.isRequired,
files: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
content: PropTypes.string.isRequired
})).isRequired,
2016-07-08 20:57:22 +02:00
updateFileContent: PropTypes.func.isRequired,
selectedFile: PropTypes.shape({
id: PropTypes.string.isRequired,
content: PropTypes.string.isRequired,
name: PropTypes.string.isRequired
}).isRequired,
2016-07-11 21:22:29 +02:00
setSelectedFile: PropTypes.func.isRequired,
htmlFile: PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
content: PropTypes.string.isRequired
}).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,
cloneProject: PropTypes.func.isRequired,
expandConsole: PropTypes.func.isRequired,
collapseConsole: PropTypes.func.isRequired,
2016-08-03 23:10:03 +02:00
deleteFile: PropTypes.func.isRequired,
updateFileName: PropTypes.func.isRequired,
2016-08-30 05:23:10 +02:00
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 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,
closeKeyboardShortcutModal: PropTypes.func.isRequired,
toast: PropTypes.shape({
isVisible: PropTypes.bool.isRequired
}).isRequired,
autosaveProject: PropTypes.func.isRequired,
router: PropTypes.shape({
setRouteLeaveHook: PropTypes.func
}).isRequired,
route: PropTypes.oneOfType([PropTypes.object, PropTypes.element]).isRequired,
setUnsavedChanges: PropTypes.func.isRequired,
setTheme: PropTypes.func.isRequired,
2016-09-29 00:05:14 +02:00
endSketchRefresh: PropTypes.func.isRequired,
startRefreshSketch: PropTypes.func.isRequired,
setBlobUrl: PropTypes.func.isRequired,
2016-11-11 00:49:42 +01:00
setPreviousPath: PropTypes.func.isRequired,
console: PropTypes.arrayOf(PropTypes.shape({
method: PropTypes.string.isRequired,
args: PropTypes.arrayOf(PropTypes.string)
})).isRequired,
clearConsole: PropTypes.func.isRequired,
showErrorModal: PropTypes.func.isRequired,
hideErrorModal: PropTypes.func.isRequired,
clearPersistedState: PropTypes.func.isRequired,
persistState: PropTypes.func.isRequired,
hideHelpModal: PropTypes.func.isRequired,
showRuntimeErrorWarning: PropTypes.func.isRequired,
2017-10-12 21:38:02 +02:00
hideRuntimeErrorWarning: PropTypes.func.isRequired,
startSketch: 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,
2018-11-27 00:08:24 +01:00
selectedFile: state.files.find(file => file.isSelectedFile) ||
state.files.find(file => file.name === 'sketch.js') ||
state.files.find(file => file.name !== 'root'),
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,
project: state.project,
toast: state.toast,
console: state.console
2016-06-24 00:29:55 +02:00
};
}
function mapDispatchToProps(dispatch) {
2018-05-05 02:22:39 +02:00
return bindActionCreators(
Object.assign(
{},
EditorAccessibilityActions,
FileActions,
ProjectActions,
IDEActions,
PreferencesActions,
UserActions,
ToastActions,
ConsoleActions
),
dispatch
);
2016-06-24 00:29:55 +02:00
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(IDEView));