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

654 lines
26 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 { withTranslation } from 'react-i18next';
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';
import UploadFileModal from '../components/UploadFileModal';
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';
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';
2016-08-22 18:35:59 +02:00
import About from '../components/About';
2019-11-25 21:19:22 +01:00
import AddToCollectionList from '../components/AddToCollectionList';
2018-02-09 22:32:06 +01:00
import Feedback from '../components/Feedback';
import { CollectionSearchbar } from '../components/Searchbar';
2016-06-24 00:29:55 +02:00
2020-06-29 22:27:31 +02:00
function getTitle(props) {
const { id } = props.project;
return id ? `p5.js Web Editor | ${props.project.name}` : 'p5.js Web Editor';
2020-06-29 22:27:31 +02:00
}
2020-06-29 22:27:31 +02:00
function isUserOwner(props) {
return props.project.owner && props.project.owner.id === props.user.id;
}
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 { project_id: id, username } = this.props.params;
2016-11-11 00:49:42 +01:00
if (id !== this.props.project.id) {
this.props.getProject(id, username);
2016-11-11 00:49:42 +01:00
}
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
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-06-24 00:29:55 +02:00
}
componentDidUpdate(prevProps) {
if (isUserOwner(this.props) && 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;
}
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 (isUserOwner(this.props) || (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);
2020-02-23 19:48:16 +01:00
} else if (e.keyCode === 66 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac))) {
e.preventDefault();
if (!this.props.ide.sidebarIsExpanded) {
this.props.expandSidebar();
} else {
this.props.collapseSidebar();
}
} else if (e.keyCode === 192 && e.ctrlKey) {
2020-02-24 20:43:57 +01:00
e.preventDefault();
if (this.props.ide.consoleIsExpanded) {
this.props.collapseConsole();
} else {
this.props.expandConsole();
}
2020-04-23 20:59:33 +02:00
} else if (e.keyCode === 27) {
if (this.props.ide.newFolderModalVisible) {
this.props.closeNewFolderModal();
} else if (this.props.ide.uploadFileModalVisible) {
this.props.closeUploadFileModal();
} else if (this.props.ide.modalIsVisible) {
this.props.closeNewFileModal();
}
}
}
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(this.props.t('WarningUnsavedChanges'))) {
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>{getTitle(this.props)}</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 key={this.props.project.id} />
2017-11-14 01:09:08 +01:00
{this.props.ide.preferencesIsVisible &&
<Overlay
title={this.props.t('Settings')}
2017-11-14 01:09:08 +01:00
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}
lineNumbers={this.props.preferences.lineNumbers}
setLineNumbers={this.props.setLineNumbers}
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>
}
<main 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}
openUploadFileModal={this.props.openUploadFileModal}
closeUploadFileModal={this.props.closeUploadFileModal}
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}
lineNumbers={this.props.preferences.lineNumbers}
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={isUserOwner(this.props)}
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>
<section className="preview-frame-holder">
2017-03-02 21:01:33 +01:00
<header className="preview-frame__header">
<h2 className="preview-frame__title">{this.props.t('Preview')}</h2>
2017-03-02 21:01:33 +01:00
</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>
</section>
2016-08-11 21:41:13 +02:00
</SplitPane>
</SplitPane>
</main>
{ this.props.ide.modalIsVisible &&
<NewFileModal />
2017-11-13 20:44:23 +01:00
}
{this.props.ide.newFolderModalVisible &&
2017-11-13 20:44:23 +01:00
<NewFolderModal
closeModal={this.props.closeNewFolderModal}
createFolder={this.props.createFolder}
/>
}
{this.props.ide.uploadFileModalVisible &&
<UploadFileModal
closeModal={this.props.closeUploadFileModal}
/>
}
2017-11-13 20:44:23 +01:00
{ this.props.location.pathname === '/about' &&
<Overlay
title={this.props.t('About')}
2017-11-13 20:44:23 +01:00
previousPath={this.props.ide.previousPath}
ariaLabel="about"
>
<About previousPath={this.props.ide.previousPath} />
</Overlay>
}
{this.props.location.pathname === '/feedback' &&
2018-02-09 22:32:06 +01:00
<Overlay
title="Submit Feedback"
2018-02-09 22:32:06 +01:00
previousPath={this.props.ide.previousPath}
ariaLabel="submit-feedback"
>
<Feedback previousPath={this.props.ide.previousPath} />
</Overlay>
}
{this.props.location.pathname.match(/add-to-collection$/) &&
<Overlay
ariaLabel="add to collection"
title="Add to collection"
previousPath={this.props.ide.previousPath}
actions={<CollectionSearchbar />}
isFixedHeight
>
2019-11-25 21:19:22 +01:00
<AddToCollectionList
projectId={this.props.params.project_id}
username={this.props.params.username}
user={this.props.user}
/>
</Overlay>
}
{this.props.ide.shareModalVisible &&
2017-11-13 20:44:23 +01:00
<Overlay
title="Share"
2017-11-13 20:44:23 +01:00
ariaLabel="share"
closeOverlay={this.props.closeShareModal}
>
<ShareModal
Update sketch list styling (#819) * parent b3c3efcec96b5e5bb4e00be742e8f17a025db409 author Laksh Singla <lakshsingla@gmail.com> 1549106083 +0530 committer Cassie Tarakajian <ctarakajian@gmail.com> 1560540243 -0400 parent b3c3efcec96b5e5bb4e00be742e8f17a025db409 author Laksh Singla <lakshsingla@gmail.com> 1549106083 +0530 committer Cassie Tarakajian <ctarakajian@gmail.com> 1560540198 -0400 parent b3c3efcec96b5e5bb4e00be742e8f17a025db409 author Laksh Singla <lakshsingla@gmail.com> 1549106083 +0530 committer Cassie Tarakajian <ctarakajian@gmail.com> 1560539667 -0400 Created initial html structure and styling for new SketchList design Final styling of ActionDialogueBox commplete Dropdown menu disappearing while clicking anywhere on the table Fixed linting issues and renamed variables Minor tweaks in the SketchList dropdown dialogue UI Themifyed the dropdown Made changes in the dropdown: Arrow positioned slightly updwards, Removed blank space and added box-shadow in dropdown, themifyed dropdowns dashed border color Added Delete and Share functionality to Dialog box Added Duplicate functionality to Dialog box Added download functionality to Dialog box SketchList does not open a sketch if dialogue box is opened SketchList Rename initial UI completed Enter key handled for rename project option [WIP] Updating rename functionality Download option now working for all the sketches Duplicate functionality extended for non opened sketches too Modified overlay behaviour to close only the last overlay Share modal can now display different projects Dropdown closes when Share and Delete are closing for a more natural UX fix broken files from rebasing Created initial html structure and styling for new SketchList design Final styling of ActionDialogueBox commplete Added Delete and Share functionality to Dialog box Added Duplicate functionality to Dialog box [WIP] Updating rename functionality Duplicate functionality extended for non opened sketches too Modified overlay behaviour to close only the last overlay Share modal can now display different projects Final styling of ActionDialogueBox commplete Fixed linting issues and renamed variables Minor tweaks in the SketchList dropdown dialogue UI Themifyed the dropdown Added Delete and Share functionality to Dialog box [WIP] Updating rename functionality Modified overlay behaviour to close only the last overlay Share modal can now display different projects Dropdown closes when Share and Delete are closing for a more natural UX fix broken files from rebasing Final styling of ActionDialogueBox commplete Minor tweaks in the SketchList dropdown dialogue UI Themifyed the dropdown [WIP] Updating rename functionality Duplicate functionality extended for non opened sketches too Modified overlay behaviour to close only the last overlay Share modal can now display different projects Dropdown closes when Share and Delete are closing for a more natural UX * fix bugs in merge commit * move sketch list dialogue to ul/li * update sketch option dropdown to use dropdown placeholder, remove unused css * major refactor of sketchlist component, fix showShareModal action, minor updates ot icon sizing * fix broken links on asset list * remove unused image, fix options for different users in sketch list
2019-06-19 22:21:25 +02:00
projectId={this.props.ide.shareModalProjectId}
projectName={this.props.ide.shareModalProjectName}
ownerUsername={this.props.ide.shareModalProjectUsername}
2017-11-13 20:44:23 +01:00
/>
</Overlay>
}
{this.props.ide.keyboardShortcutVisible &&
2017-11-13 20:44:23 +01:00
<Overlay
title={this.props.t('KeyboardShortcuts')}
2017-11-13 20:44:23 +01:00
ariaLabel="keyboard shortcuts"
closeOverlay={this.props.closeKeyboardShortcutModal}
>
<KeyboardShortcutModal />
</Overlay>
}
{this.props.ide.errorType &&
2017-11-13 20:44:23 +01:00
<Overlay
title="Error"
2017-11-13 20:44:23 +01:00
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>
}
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,
Update sketch list styling (#819) * parent b3c3efcec96b5e5bb4e00be742e8f17a025db409 author Laksh Singla <lakshsingla@gmail.com> 1549106083 +0530 committer Cassie Tarakajian <ctarakajian@gmail.com> 1560540243 -0400 parent b3c3efcec96b5e5bb4e00be742e8f17a025db409 author Laksh Singla <lakshsingla@gmail.com> 1549106083 +0530 committer Cassie Tarakajian <ctarakajian@gmail.com> 1560540198 -0400 parent b3c3efcec96b5e5bb4e00be742e8f17a025db409 author Laksh Singla <lakshsingla@gmail.com> 1549106083 +0530 committer Cassie Tarakajian <ctarakajian@gmail.com> 1560539667 -0400 Created initial html structure and styling for new SketchList design Final styling of ActionDialogueBox commplete Dropdown menu disappearing while clicking anywhere on the table Fixed linting issues and renamed variables Minor tweaks in the SketchList dropdown dialogue UI Themifyed the dropdown Made changes in the dropdown: Arrow positioned slightly updwards, Removed blank space and added box-shadow in dropdown, themifyed dropdowns dashed border color Added Delete and Share functionality to Dialog box Added Duplicate functionality to Dialog box Added download functionality to Dialog box SketchList does not open a sketch if dialogue box is opened SketchList Rename initial UI completed Enter key handled for rename project option [WIP] Updating rename functionality Download option now working for all the sketches Duplicate functionality extended for non opened sketches too Modified overlay behaviour to close only the last overlay Share modal can now display different projects Dropdown closes when Share and Delete are closing for a more natural UX fix broken files from rebasing Created initial html structure and styling for new SketchList design Final styling of ActionDialogueBox commplete Added Delete and Share functionality to Dialog box Added Duplicate functionality to Dialog box [WIP] Updating rename functionality Duplicate functionality extended for non opened sketches too Modified overlay behaviour to close only the last overlay Share modal can now display different projects Final styling of ActionDialogueBox commplete Fixed linting issues and renamed variables Minor tweaks in the SketchList dropdown dialogue UI Themifyed the dropdown Added Delete and Share functionality to Dialog box [WIP] Updating rename functionality Modified overlay behaviour to close only the last overlay Share modal can now display different projects Dropdown closes when Share and Delete are closing for a more natural UX fix broken files from rebasing Final styling of ActionDialogueBox commplete Minor tweaks in the SketchList dropdown dialogue UI Themifyed the dropdown [WIP] Updating rename functionality Duplicate functionality extended for non opened sketches too Modified overlay behaviour to close only the last overlay Share modal can now display different projects Dropdown closes when Share and Delete are closing for a more natural UX * fix bugs in merge commit * move sketch list dialogue to ul/li * update sketch option dropdown to use dropdown placeholder, remove unused css * major refactor of sketchlist component, fix showShareModal action, minor updates ot icon sizing * fix broken links on asset list * remove unused image, fix options for different users in sketch list
2019-06-19 22:21:25 +02:00
shareModalProjectId: PropTypes.string.isRequired,
shareModalProjectName: PropTypes.string.isRequired,
shareModalProjectUsername: PropTypes.string.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,
runtimeErrorWarningVisible: PropTypes.bool.isRequired,
uploadFileModalVisible: 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,
lineNumbers: 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,
setLineNumbers: 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
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,
2020-04-23 20:59:33 +02:00
closeNewFileModal: PropTypes.func.isRequired,
2016-08-30 20:39:37 +02:00
createFolder: 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,
showRuntimeErrorWarning: PropTypes.func.isRequired,
2017-10-12 21:38:02 +02:00
hideRuntimeErrorWarning: PropTypes.func.isRequired,
startSketch: PropTypes.func.isRequired,
openUploadFileModal: PropTypes.func.isRequired,
closeUploadFileModal: PropTypes.func.isRequired,
t: 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 withTranslation('WebEditor')(withRouter(connect(mapStateToProps, mapDispatchToProps)(IDEView)));