Fix save on pressing play with new project -- show save button first time around (as isPlaying get reset when URL is change on save)

This commit is contained in:
Ruben van de Ven 2020-10-09 19:06:19 +02:00
parent c1810ed47f
commit f181bc6cb7
5 changed files with 76 additions and 47 deletions

View file

@ -127,6 +127,7 @@ function getSynchedProject(currentState, responseProject) {
} }
export function saveProject(selectedFile = null, autosave = false, mobile = false) { export function saveProject(selectedFile = null, autosave = false, mobile = false) {
console.trace('saving inproject.js');
return (dispatch, getState) => { return (dispatch, getState) => {
const state = getState(); const state = getState();
if (state.project.isSaving) { if (state.project.isSaving) {

View file

@ -59,7 +59,9 @@ class PreviewFrame extends React.Component {
} }
componentDidUpdate(prevProps) { 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(); if (shouldRenderSketch(this.props, prevProps)) this.renderSketch();
// small bug - if autorefresh is on, and the usr changes files // small bug - if autorefresh is on, and the usr changes files
// in the sketch, preview will reload // in the sketch, preview will reload
@ -339,72 +341,81 @@ class PreviewFrame extends React.Component {
// console.log('changed and requiring reload:', changedFiles, filesRequiringReload, filesToHotSwap); // console.log('changed and requiring reload:', changedFiles, filesRequiringReload, filesToHotSwap);
let saving; let saving;
if (changedFiles.length > 0) { console.log('is saving...', this.props);
if (changedFiles.length > 0 || this.props.project.updatedAt === '') {
saving = this.props.saveProject(); saving = this.props.saveProject();
} else { } else {
// can be done pretier: a promise that always resolves // can be done pretier: a promise that always resolves
saving = new Promise((resolve, err) => resolve()); saving = new Promise((resolve, err) => resolve());
} }
console.log('saving:', saving);
if (saving === null) { 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() this.props.stopSketch(); // prevent crazy loop of renderSketch() through componentDidUpdate()
} else { } else {
saving.catch(() => { 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.stopSketch(); // prevent crazy loop of renderSketch() through componentDidUpdate()
// this.props.clearConsole(); // introduces bug: causes nested compnonentDidUpdate()
}); });
saving.then(() => { saving.then(() => {
console.log('play!', this.props.isPlaying);
if (this.props.isPlaying) { if (this.props.isPlaying) {
this.props.clearConsole();
doc.removeAttribute('srcdoc'); doc.removeAttribute('srcdoc');
const source = `${window.location.origin}/${this.props.project.owner.username}/sketches/${this.props.project.id}/index.html`; if (typeof this.props.project.owner === 'undefined') {
// console.log('FILES', this.props.files, doc.src, source, lastUpdate); console.error('no owner for project?', this.props.project);
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 { } else {
doc.src = source; 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);
// lastUpdate = new Date(); if (doc.src === source) {
if (this.props.endSketchRefresh) { // const newFiles = this.props.files.filter(file => new Date(file.updatedAt) > lastUpdate);
this.props.endSketchRefresh(); 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 { } else {
doc.removeAttribute('src'); doc.removeAttribute('src');
doc.srcdoc = ''; doc.srcdoc = '';
srcDoc.set(doc, ' '); srcDoc.set(doc, ' ');
} }
// prevent looping
if (this.props.endSketchRefresh) {
this.props.endSketchRefresh();
}
}); });
} }
} }
@ -463,7 +474,7 @@ PreviewFrame.propTypes = {
}), }),
updatedAt: PropTypes.string, updatedAt: PropTypes.string,
}).isRequired, }).isRequired,
clearConsole: PropTypes.func.isRequired, // clearConsole: PropTypes.func,
unsavedChanges: PropTypes.bool, unsavedChanges: PropTypes.bool,
cmController: PropTypes.shape({ cmController: PropTypes.shape({
getContent: PropTypes.func getContent: PropTypes.func
@ -473,7 +484,7 @@ PreviewFrame.propTypes = {
PreviewFrame.defaultProps = { PreviewFrame.defaultProps = {
fullView: false, fullView: false,
unsavedChanges: false, unsavedChanges: false,
cmController: {} cmController: {},
}; };
export default PreviewFrame; export default PreviewFrame;

View file

@ -60,7 +60,9 @@ class Toolbar extends React.Component {
render() { render() {
const playButtonClass = classNames({ const playButtonClass = classNames({
'toolbar__play-button': true, '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({ const stopButtonClass = classNames({
'toolbar__stop-button': true, 'toolbar__stop-button': true,
@ -176,6 +178,7 @@ class Toolbar extends React.Component {
Toolbar.propTypes = { Toolbar.propTypes = {
isPlaying: PropTypes.bool.isRequired, isPlaying: PropTypes.bool.isRequired,
isSaved: PropTypes.bool.isRequired,
preferencesIsVisible: PropTypes.bool.isRequired, preferencesIsVisible: PropTypes.bool.isRequired,
stopSketch: PropTypes.func.isRequired, stopSketch: PropTypes.func.isRequired,
setProjectName: PropTypes.func.isRequired, setProjectName: PropTypes.func.isRequired,
@ -215,6 +218,7 @@ function mapStateToProps(state) {
infiniteLoop: state.ide.infiniteLoop, infiniteLoop: state.ide.infiniteLoop,
isPlaying: state.ide.isPlaying, isPlaying: state.ide.isPlaying,
owner: state.project.owner, owner: state.project.owner,
isSaved: state.project.updatedAt !== '',
preferencesIsVisible: state.ide.preferencesIsVisible, preferencesIsVisible: state.ide.preferencesIsVisible,
project: state.project, project: state.project,
}; };

View file

@ -174,12 +174,13 @@ class IDEView extends React.Component {
this.autosaveInterval = null; this.autosaveInterval = null;
} }
saveProject() { saveProject() {
console.trace('saving!');
// return a Promise to save or null // return a Promise to save or null
if ( if (
isUserOwner(this.props) || isUserOwner(this.props) ||
(this.props.user.authenticated && !this.props.project.owner) (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()); return this.props.saveProject(this.cmController.getContent());
} else if (this.props.user.authenticated) { } else if (this.props.user.authenticated) {
return this.props.cloneProject(); return this.props.cloneProject();

View file

@ -1,4 +1,16 @@
.toolbar__play-button { .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() { @include themify() {
@extend %toolbar-button; @extend %toolbar-button;
display: flex; display: flex;