Merge branch 'develop' into feature/mobile-settings-screen
This commit is contained in:
commit
7d6ba6f34f
7 changed files with 39 additions and 27 deletions
|
@ -155,18 +155,20 @@ export function saveProject(selectedFile = null, autosave = false) {
|
||||||
if (!autosave) {
|
if (!autosave) {
|
||||||
if (state.ide.justOpenedProject && state.preferences.autosave) {
|
if (state.ide.justOpenedProject && state.preferences.autosave) {
|
||||||
dispatch(showToast(5500));
|
dispatch(showToast(5500));
|
||||||
dispatch(setToastText('Project saved.'));
|
dispatch(setToastText('Sketch saved.'));
|
||||||
setTimeout(() => dispatch(setToastText('Autosave enabled.')), 1500);
|
setTimeout(() => dispatch(setToastText('Autosave enabled.')), 1500);
|
||||||
dispatch(resetJustOpenedProject());
|
dispatch(resetJustOpenedProject());
|
||||||
} else {
|
} else {
|
||||||
dispatch(showToast(1500));
|
dispatch(showToast(1500));
|
||||||
dispatch(setToastText('Project saved.'));
|
dispatch(setToastText('Sketch saved.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const { response } = error;
|
const { response } = error;
|
||||||
dispatch(endSavingProject());
|
dispatch(endSavingProject());
|
||||||
|
dispatch(setToastText('Failed to save sketch.'));
|
||||||
|
dispatch(showToast(1500));
|
||||||
if (response.status === 403) {
|
if (response.status === 403) {
|
||||||
dispatch(showErrorModal('staleSession'));
|
dispatch(showErrorModal('staleSession'));
|
||||||
} else if (response.status === 409) {
|
} else if (response.status === 409) {
|
||||||
|
@ -195,18 +197,20 @@ export function saveProject(selectedFile = null, autosave = false) {
|
||||||
if (!autosave) {
|
if (!autosave) {
|
||||||
if (state.preferences.autosave) {
|
if (state.preferences.autosave) {
|
||||||
dispatch(showToast(5500));
|
dispatch(showToast(5500));
|
||||||
dispatch(setToastText('Project saved.'));
|
dispatch(setToastText('Sketch saved.'));
|
||||||
setTimeout(() => dispatch(setToastText('Autosave enabled.')), 1500);
|
setTimeout(() => dispatch(setToastText('Autosave enabled.')), 1500);
|
||||||
dispatch(resetJustOpenedProject());
|
dispatch(resetJustOpenedProject());
|
||||||
} else {
|
} else {
|
||||||
dispatch(showToast(1500));
|
dispatch(showToast(1500));
|
||||||
dispatch(setToastText('Project saved.'));
|
dispatch(setToastText('Sketch saved.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const { response } = error;
|
const { response } = error;
|
||||||
dispatch(endSavingProject());
|
dispatch(endSavingProject());
|
||||||
|
dispatch(setToastText('Failed to save sketch.'));
|
||||||
|
dispatch(showToast(1500));
|
||||||
if (response.status === 403) {
|
if (response.status === 403) {
|
||||||
dispatch(showErrorModal('staleSession'));
|
dispatch(showErrorModal('staleSession'));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -237,16 +237,18 @@ class PreviewFrame extends React.Component {
|
||||||
jsFileStrings.forEach((jsFileString) => {
|
jsFileStrings.forEach((jsFileString) => {
|
||||||
if (jsFileString.match(MEDIA_FILE_QUOTED_REGEX)) {
|
if (jsFileString.match(MEDIA_FILE_QUOTED_REGEX)) {
|
||||||
const filePath = jsFileString.substr(1, jsFileString.length - 2);
|
const filePath = jsFileString.substr(1, jsFileString.length - 2);
|
||||||
|
const quoteCharacter = jsFileString.substr(0, 1);
|
||||||
const resolvedFile = resolvePathToFile(filePath, files);
|
const resolvedFile = resolvePathToFile(filePath, files);
|
||||||
|
|
||||||
if (resolvedFile) {
|
if (resolvedFile) {
|
||||||
if (resolvedFile.url) {
|
if (resolvedFile.url) {
|
||||||
newContent = newContent.replace(filePath, resolvedFile.url);
|
newContent = newContent.replace(jsFileString, quoteCharacter + resolvedFile.url + quoteCharacter);
|
||||||
} else if (resolvedFile.name.match(PLAINTEXT_FILE_REGEX)) {
|
} else if (resolvedFile.name.match(PLAINTEXT_FILE_REGEX)) {
|
||||||
// could also pull file from API instead of using bloburl
|
// could also pull file from API instead of using bloburl
|
||||||
const blobURL = getBlobUrl(resolvedFile);
|
const blobURL = getBlobUrl(resolvedFile);
|
||||||
this.props.setBlobUrl(resolvedFile, blobURL);
|
this.props.setBlobUrl(resolvedFile, blobURL);
|
||||||
const filePathRegex = new RegExp(filePath, 'gi');
|
|
||||||
newContent = newContent.replace(filePathRegex, blobURL);
|
newContent = newContent.replace(jsFileString, quoteCharacter + blobURL + quoteCharacter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,10 +264,11 @@ class PreviewFrame extends React.Component {
|
||||||
cssFileStrings.forEach((cssFileString) => {
|
cssFileStrings.forEach((cssFileString) => {
|
||||||
if (cssFileString.match(MEDIA_FILE_QUOTED_REGEX)) {
|
if (cssFileString.match(MEDIA_FILE_QUOTED_REGEX)) {
|
||||||
const filePath = cssFileString.substr(1, cssFileString.length - 2);
|
const filePath = cssFileString.substr(1, cssFileString.length - 2);
|
||||||
|
const quoteCharacter = cssFileString.substr(0, 1);
|
||||||
const resolvedFile = resolvePathToFile(filePath, files);
|
const resolvedFile = resolvePathToFile(filePath, files);
|
||||||
if (resolvedFile) {
|
if (resolvedFile) {
|
||||||
if (resolvedFile.url) {
|
if (resolvedFile.url) {
|
||||||
newContent = newContent.replace(filePath, resolvedFile.url);
|
newContent = newContent.replace(cssFileString, quoteCharacter + resolvedFile.url + quoteCharacter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,15 @@ import AddToCollectionList from '../components/AddToCollectionList';
|
||||||
import Feedback from '../components/Feedback';
|
import Feedback from '../components/Feedback';
|
||||||
import { CollectionSearchbar } from '../components/Searchbar';
|
import { CollectionSearchbar } from '../components/Searchbar';
|
||||||
|
|
||||||
|
function getTitle(props) {
|
||||||
|
const { id } = props.project;
|
||||||
|
return id ? `p5.js Web Editor | ${props.project.name}` : 'p5.js Web Editor';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isUserOwner(props) {
|
||||||
|
return props.project.owner && props.project.owner.id === props.user.id;
|
||||||
|
}
|
||||||
|
|
||||||
class IDEView extends React.Component {
|
class IDEView extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -92,7 +101,7 @@ class IDEView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (this.isUserOwner() && this.props.project.id) {
|
if (isUserOwner(this.props) && this.props.project.id) {
|
||||||
if (this.props.preferences.autosave && this.props.ide.unsavedChanges && !this.props.ide.justOpenedProject) {
|
if (this.props.preferences.autosave && this.props.ide.unsavedChanges && !this.props.ide.justOpenedProject) {
|
||||||
if (
|
if (
|
||||||
this.props.selectedFile.name === prevProps.selectedFile.name &&
|
this.props.selectedFile.name === prevProps.selectedFile.name &&
|
||||||
|
@ -123,21 +132,12 @@ class IDEView extends React.Component {
|
||||||
this.autosaveInterval = null;
|
this.autosaveInterval = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTitle = () => {
|
|
||||||
const { id } = this.props.project;
|
|
||||||
return id ? `p5.js Web Editor | ${this.props.project.name}` : 'p5.js Web Editor';
|
|
||||||
}
|
|
||||||
|
|
||||||
isUserOwner() {
|
|
||||||
return this.props.project.owner && this.props.project.owner.id === this.props.user.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleGlobalKeydown(e) {
|
handleGlobalKeydown(e) {
|
||||||
// 83 === s
|
// 83 === s
|
||||||
if (e.keyCode === 83 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac))) {
|
if (e.keyCode === 83 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac))) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (this.isUserOwner() || (this.props.user.authenticated && !this.props.project.owner)) {
|
if (isUserOwner(this.props) || (this.props.user.authenticated && !this.props.project.owner)) {
|
||||||
this.props.saveProject(this.cmController.getContent());
|
this.props.saveProject(this.cmController.getContent());
|
||||||
} else if (this.props.user.authenticated) {
|
} else if (this.props.user.authenticated) {
|
||||||
this.props.cloneProject();
|
this.props.cloneProject();
|
||||||
|
@ -208,7 +208,7 @@ class IDEView extends React.Component {
|
||||||
return (
|
return (
|
||||||
<div className="ide">
|
<div className="ide">
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{this.getTitle()}</title>
|
<title>{getTitle(this.props)}</title>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
{this.props.toast.isVisible && <Toast />}
|
{this.props.toast.isVisible && <Toast />}
|
||||||
<Nav
|
<Nav
|
||||||
|
@ -313,7 +313,7 @@ class IDEView extends React.Component {
|
||||||
isExpanded={this.props.ide.sidebarIsExpanded}
|
isExpanded={this.props.ide.sidebarIsExpanded}
|
||||||
expandSidebar={this.props.expandSidebar}
|
expandSidebar={this.props.expandSidebar}
|
||||||
collapseSidebar={this.props.collapseSidebar}
|
collapseSidebar={this.props.collapseSidebar}
|
||||||
isUserOwner={this.isUserOwner()}
|
isUserOwner={isUserOwner(this.props)}
|
||||||
clearConsole={this.props.clearConsole}
|
clearConsole={this.props.clearConsole}
|
||||||
consoleEvents={this.props.console}
|
consoleEvents={this.props.console}
|
||||||
showRuntimeErrorWarning={this.props.showRuntimeErrorWarning}
|
showRuntimeErrorWarning={this.props.showRuntimeErrorWarning}
|
||||||
|
|
|
@ -37,6 +37,11 @@ const getSortedCollections = createSelector(
|
||||||
return orderBy(collections, 'name', 'desc');
|
return orderBy(collections, 'name', 'desc');
|
||||||
}
|
}
|
||||||
return orderBy(collections, 'name', 'asc');
|
return orderBy(collections, 'name', 'asc');
|
||||||
|
} else if (field === 'numItems') {
|
||||||
|
if (direction === DIRECTION.DESC) {
|
||||||
|
return orderBy(collections, 'items.length', 'desc');
|
||||||
|
}
|
||||||
|
return orderBy(collections, 'items.length', 'asc');
|
||||||
}
|
}
|
||||||
const sortedCollections = [...collections].sort((a, b) => {
|
const sortedCollections = [...collections].sort((a, b) => {
|
||||||
const result =
|
const result =
|
||||||
|
|
|
@ -69,9 +69,8 @@ Note that this is optional, unless you are working on the part of the applicatio
|
||||||
If your S3 bucket is in the US East (N Virginia) region (us-east-1), you'll
|
If your S3 bucket is in the US East (N Virginia) region (us-east-1), you'll
|
||||||
need to set a custom URL base for it, because it does not follow the standard
|
need to set a custom URL base for it, because it does not follow the standard
|
||||||
naming pattern as the rest of the regions. Instead, add the following to your
|
naming pattern as the rest of the regions. Instead, add the following to your
|
||||||
environment/.env file:
|
environment/.env file, changing `BUCKET_NAME` to your bucket name. This is necessary because this override is currently treated as the full path to the bucket rather than as a proper base url:
|
||||||
|
`S3_BUCKET_URL_BASE=https://s3.amazonaws.com/{BUCKET_NAME}/`
|
||||||
`S3_BUCKET_URL_BASE=https://s3.amazonaws.com`
|
|
||||||
|
|
||||||
If you've configured your S3 bucket and DNS records to use a custom domain
|
If you've configured your S3 bucket and DNS records to use a custom domain
|
||||||
name, you can also set it using this variable. I.e.:
|
name, you can also set it using this variable. I.e.:
|
||||||
|
|
|
@ -34,6 +34,7 @@ export function serveProject(req, res) {
|
||||||
resolveScripts(sketchDoc, files);
|
resolveScripts(sketchDoc, files);
|
||||||
resolveStyles(sketchDoc, files);
|
resolveStyles(sketchDoc, files);
|
||||||
|
|
||||||
|
res.setHeader('Cache-Control', 'public, max-age=0');
|
||||||
res.send(serializeDocument(sketchDoc));
|
res.send(serializeDocument(sketchDoc));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -73,7 +73,7 @@ function getCategories() {
|
||||||
function getSketchesInCategories(categories) {
|
function getSketchesInCategories(categories) {
|
||||||
return Q.all(categories.map((category) => {
|
return Q.all(categories.map((category) => {
|
||||||
const options = {
|
const options = {
|
||||||
url: `${category.url.replace('?ref=master', '')}?client_id=${clientId}&client_secret=${clientSecret}`,
|
url: `${category.url.replace('?ref=main', '')}?client_id=${clientId}&client_secret=${clientSecret}`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers,
|
headers,
|
||||||
json: true
|
json: true
|
||||||
|
@ -107,7 +107,7 @@ function getSketchesInCategories(categories) {
|
||||||
function getSketchContent(projectsInAllCategories) {
|
function getSketchContent(projectsInAllCategories) {
|
||||||
return Q.all(projectsInAllCategories.map(projectsInOneCategory => Q.all(projectsInOneCategory.map((project) => {
|
return Q.all(projectsInAllCategories.map(projectsInOneCategory => Q.all(projectsInOneCategory.map((project) => {
|
||||||
const options = {
|
const options = {
|
||||||
url: `${project.sketchUrl.replace('?ref=master', '')}?client_id=${clientId}&client_secret=${clientSecret}`,
|
url: `${project.sketchUrl.replace('?ref=main', '')}?client_id=${clientId}&client_secret=${clientSecret}`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers
|
headers
|
||||||
};
|
};
|
||||||
|
@ -264,7 +264,7 @@ function createProjectsInP5user(projectsInAllCategories) {
|
||||||
const fileID = objectID().toHexString();
|
const fileID = objectID().toHexString();
|
||||||
newProject.files.push({
|
newProject.files.push({
|
||||||
name: assetName,
|
name: assetName,
|
||||||
url: `https://cdn.jsdelivr.net/gh/processing/p5.js-website@master/src/data/examples/assets/${assetName}`,
|
url: `https://cdn.jsdelivr.net/gh/processing/p5.js-website@main/src/data/examples/assets/${assetName}`,
|
||||||
id: fileID,
|
id: fileID,
|
||||||
_id: fileID,
|
_id: fileID,
|
||||||
children: [],
|
children: [],
|
||||||
|
|
Loading…
Reference in a new issue