From f181bc6cb702555165cb4eb5b99bee0cf79f9873 Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Fri, 9 Oct 2020 19:06:19 +0200 Subject: [PATCH] Fix save on pressing play with new project -- show save button first time around (as isPlaying get reset when URL is change on save) --- client/modules/IDE/actions/project.js | 1 + .../modules/IDE/components/PreviewFrame.jsx | 101 ++++++++++-------- client/modules/IDE/components/Toolbar.jsx | 6 +- client/modules/IDE/pages/IDEView.jsx | 3 +- client/styles/components/_toolbar.scss | 12 +++ 5 files changed, 76 insertions(+), 47 deletions(-) diff --git a/client/modules/IDE/actions/project.js b/client/modules/IDE/actions/project.js index 05215579..b3da6819 100644 --- a/client/modules/IDE/actions/project.js +++ b/client/modules/IDE/actions/project.js @@ -127,6 +127,7 @@ function getSynchedProject(currentState, responseProject) { } export function saveProject(selectedFile = null, autosave = false, mobile = false) { + console.trace('saving inproject.js'); return (dispatch, getState) => { const state = getState(); if (state.project.isSaving) { diff --git a/client/modules/IDE/components/PreviewFrame.jsx b/client/modules/IDE/components/PreviewFrame.jsx index a5336423..c15186e4 100644 --- a/client/modules/IDE/components/PreviewFrame.jsx +++ b/client/modules/IDE/components/PreviewFrame.jsx @@ -59,7 +59,9 @@ class PreviewFrame extends React.Component { } componentDidUpdate(prevProps) { - // console.log(this.props, prevProps); + if (prevProps.isPlaying === true && this.props.isPlaying === false) { + console.trace('update', this.props, prevProps); + } if (shouldRenderSketch(this.props, prevProps)) this.renderSketch(); // small bug - if autorefresh is on, and the usr changes files // in the sketch, preview will reload @@ -339,72 +341,81 @@ class PreviewFrame extends React.Component { // console.log('changed and requiring reload:', changedFiles, filesRequiringReload, filesToHotSwap); let saving; - if (changedFiles.length > 0) { + console.log('is saving...', this.props); + if (changedFiles.length > 0 || this.props.project.updatedAt === '') { saving = this.props.saveProject(); } else { // can be done pretier: a promise that always resolves saving = new Promise((resolve, err) => resolve()); } + console.log('saving:', saving); + if (saving === null) { - // console.log('Error saving... not authenticated?'); + console.log('Error saving... not authenticated?'); this.props.stopSketch(); // prevent crazy loop of renderSketch() through componentDidUpdate() } else { saving.catch(() => { - // console.log('Error when saving... not authenticated? Redirect!'); + console.log('Error when saving... not authenticated? Redirect!'); this.props.stopSketch(); // prevent crazy loop of renderSketch() through componentDidUpdate() + // this.props.clearConsole(); // introduces bug: causes nested compnonentDidUpdate() }); saving.then(() => { + console.log('play!', this.props.isPlaying); if (this.props.isPlaying) { - this.props.clearConsole(); doc.removeAttribute('srcdoc'); - const source = `${window.location.origin}/${this.props.project.owner.username}/sketches/${this.props.project.id}/index.html`; - // console.log('FILES', this.props.files, doc.src, source, lastUpdate); - if (doc.src === source) { - // const newFiles = this.props.files.filter(file => new Date(file.updatedAt) > lastUpdate); - if (this.props.unsavedChanges) { - // console.log('unsaved changes'); - } - - // console.log('doc', doc); - // we need a hard reload - if (filesRequiringReload.length > 0) { - doc.src = source; // for now... - } else { - // if (doc.contentWindow.document.querySelector('script[src="/assets/hotswap.js"]') == null) { - // const headEl = doc.contentWindow.document.querySelector('head'); - // const srcEl = doc.contentWindow.document.createElement('script'); - // srcEl.src = '/assets/hotswap.js'; - // headEl.appendChild(srcEl); - // } - - console.log('Hot swap (..append):', filesToHotSwap); - const headEl = doc.contentWindow.document.querySelector('head'); - const updatevar = Date.now(); - filesToHotSwap.forEach((file) => { - // doc.contentWindow.postMessage({ 'action': 'code', 'contents': file.content }, '*'); - const srcEl = doc.contentWindow.document.createElement('script'); - srcEl.src = `${file.name}?changed=${updatevar}`; - srcEl.onload = 'setupAssets();'; // (re)load assets - headEl.appendChild(srcEl); - }); - } - // if ( this.props.htmlFile.content === doc.contentWindow) - // TODO: don't set, but update only (will be hard... :-P) + if (typeof this.props.project.owner === 'undefined') { + console.error('no owner for project?', this.props.project); } else { - doc.src = source; - } - // lastUpdate = new Date(); - if (this.props.endSketchRefresh) { - this.props.endSketchRefresh(); + const source = `${window.location.origin}/${this.props.project.owner.username}/sketches/${this.props.project.id}/index.html`; + // console.log('FILES', this.props.files, doc.src, source, lastUpdate); + if (doc.src === source) { + // const newFiles = this.props.files.filter(file => new Date(file.updatedAt) > lastUpdate); + if (this.props.unsavedChanges) { + // console.log('unsaved changes'); + } + + // console.log('doc', doc); + // we need a hard reload + if (filesRequiringReload.length > 0) { + doc.src = source; // for now... + } else { + // if (doc.contentWindow.document.querySelector('script[src="/assets/hotswap.js"]') == null) { + // const headEl = doc.contentWindow.document.querySelector('head'); + // const srcEl = doc.contentWindow.document.createElement('script'); + // srcEl.src = '/assets/hotswap.js'; + // headEl.appendChild(srcEl); + // } + + console.log('Hot swap (..append):', filesToHotSwap); + const headEl = doc.contentWindow.document.querySelector('head'); + const updatevar = Date.now(); + filesToHotSwap.forEach((file) => { + // doc.contentWindow.postMessage({ 'action': 'code', 'contents': file.content }, '*'); + const srcEl = doc.contentWindow.document.createElement('script'); + srcEl.src = `${file.name}?changed=${updatevar}`; + srcEl.onload = 'setupAssets();'; // (re)load assets + headEl.appendChild(srcEl); + }); + } + // if ( this.props.htmlFile.content === doc.contentWindow) + // TODO: don't set, but update only (will be hard... :-P) + } else { + doc.src = source; + } } } else { doc.removeAttribute('src'); doc.srcdoc = ''; srcDoc.set(doc, ' '); } + + // prevent looping + if (this.props.endSketchRefresh) { + this.props.endSketchRefresh(); + } }); } } @@ -463,7 +474,7 @@ PreviewFrame.propTypes = { }), updatedAt: PropTypes.string, }).isRequired, - clearConsole: PropTypes.func.isRequired, + // clearConsole: PropTypes.func, unsavedChanges: PropTypes.bool, cmController: PropTypes.shape({ getContent: PropTypes.func @@ -473,7 +484,7 @@ PreviewFrame.propTypes = { PreviewFrame.defaultProps = { fullView: false, unsavedChanges: false, - cmController: {} + cmController: {}, }; export default PreviewFrame; diff --git a/client/modules/IDE/components/Toolbar.jsx b/client/modules/IDE/components/Toolbar.jsx index 5da38560..1af979cc 100644 --- a/client/modules/IDE/components/Toolbar.jsx +++ b/client/modules/IDE/components/Toolbar.jsx @@ -60,7 +60,9 @@ class Toolbar extends React.Component { render() { const playButtonClass = classNames({ 'toolbar__play-button': true, - 'toolbar__play-button--selected': this.props.isPlaying + 'toolbar__play-button--selected': this.props.isPlaying, + 'toolbar__play-button--saved': this.props.isSaved, + 'toolbar__play-button--unsaved': !this.props.isSaved }); const stopButtonClass = classNames({ 'toolbar__stop-button': true, @@ -176,6 +178,7 @@ class Toolbar extends React.Component { Toolbar.propTypes = { isPlaying: PropTypes.bool.isRequired, + isSaved: PropTypes.bool.isRequired, preferencesIsVisible: PropTypes.bool.isRequired, stopSketch: PropTypes.func.isRequired, setProjectName: PropTypes.func.isRequired, @@ -215,6 +218,7 @@ function mapStateToProps(state) { infiniteLoop: state.ide.infiniteLoop, isPlaying: state.ide.isPlaying, owner: state.project.owner, + isSaved: state.project.updatedAt !== '', preferencesIsVisible: state.ide.preferencesIsVisible, project: state.project, }; diff --git a/client/modules/IDE/pages/IDEView.jsx b/client/modules/IDE/pages/IDEView.jsx index c30cc30f..c4e91e01 100644 --- a/client/modules/IDE/pages/IDEView.jsx +++ b/client/modules/IDE/pages/IDEView.jsx @@ -174,12 +174,13 @@ class IDEView extends React.Component { this.autosaveInterval = null; } saveProject() { + console.trace('saving!'); // return a Promise to save or null if ( isUserOwner(this.props) || (this.props.user.authenticated && !this.props.project.owner) ) { - console.log('project to save:', this.props.project); + console.trace('project to save:', this.props.project); return this.props.saveProject(this.cmController.getContent()); } else if (this.props.user.authenticated) { return this.props.cloneProject(); diff --git a/client/styles/components/_toolbar.scss b/client/styles/components/_toolbar.scss index bbbaa534..3d164e3d 100644 --- a/client/styles/components/_toolbar.scss +++ b/client/styles/components/_toolbar.scss @@ -1,4 +1,16 @@ .toolbar__play-button { + &--unsaved { + // for some reason, I cannot manage to have PreviewFrame save _and_ actuall yload the project (it stops the playback) + // pressing twice works. So just show a floppy the first time around :-) + svg { + display: none; + } + &::after{ + content: '\1F4BE'; // save floppy + } + // background-color: blue !important; + } + @include themify() { @extend %toolbar-button; display: flex;