-
+
{ this.overlay = element; }}>
- {(() => {
- if ((this.props.preferences.textOutput && this.props.ide.isPlaying) || this.props.ide.isTextOutputPlaying) {
- return (
-
- );
- }
- return '';
- })()}
+ {(() => {
+ if ((this.props.preferences.textOutput && this.props.ide.isPlaying) || this.props.ide.isTextOutputPlaying) {
+ return (
+
+ );
+ }
+ return '';
+ })()}
@@ -449,10 +443,10 @@ IDEView.propTypes = {
project_id: PropTypes.string,
username: PropTypes.string,
reset_password_token: PropTypes.string,
- }),
+ }).isRequired,
location: PropTypes.shape({
pathname: PropTypes.string
- }),
+ }).isRequired,
getProject: PropTypes.func.isRequired,
user: PropTypes.shape({
authenticated: PropTypes.bool.isRequired,
@@ -483,12 +477,9 @@ IDEView.propTypes = {
justOpenedProject: PropTypes.bool.isRequired,
errorType: PropTypes.string
}).isRequired,
- startSketch: PropTypes.func.isRequired,
stopSketch: PropTypes.func.isRequired,
startTextOutput: PropTypes.func.isRequired,
stopTextOutput: PropTypes.func.isRequired,
- detectInfiniteLoops: PropTypes.func.isRequired,
- resetInfiniteLoops: PropTypes.func.isRequired,
project: PropTypes.shape({
id: PropTypes.string,
name: PropTypes.string.isRequired,
@@ -501,11 +492,9 @@ IDEView.propTypes = {
openPreferences: PropTypes.func.isRequired,
editorAccessibility: PropTypes.shape({
lintMessages: PropTypes.array.isRequired,
- lineNumber: PropTypes.string.isRequired
}).isRequired,
updateLintMessage: PropTypes.func.isRequired,
clearLintMessage: PropTypes.func.isRequired,
- updateLineNumber: PropTypes.func.isRequired,
preferences: PropTypes.shape({
fontSize: PropTypes.number.isRequired,
indentationAmount: PropTypes.number.isRequired,
@@ -524,14 +513,22 @@ IDEView.propTypes = {
setAutosave: PropTypes.func.isRequired,
setLintWarning: PropTypes.func.isRequired,
setTextOutput: PropTypes.func.isRequired,
- files: PropTypes.array.isRequired,
+ files: PropTypes.arrayOf(PropTypes.shape({
+ id: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+ content: PropTypes.string.isRequired
+ })).isRequired,
updateFileContent: PropTypes.func.isRequired,
selectedFile: PropTypes.shape({
id: PropTypes.string.isRequired,
content: PropTypes.string.isRequired
- }),
+ }).isRequired,
setSelectedFile: PropTypes.func.isRequired,
- htmlFile: PropTypes.object.isRequired,
+ htmlFile: PropTypes.shape({
+ id: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+ content: PropTypes.string.isRequired
+ }).isRequired,
dispatchConsoleEvent: PropTypes.func.isRequired,
newFile: PropTypes.func.isRequired,
closeNewFileModal: PropTypes.func.isRequired,
@@ -565,13 +562,11 @@ IDEView.propTypes = {
toast: PropTypes.shape({
isVisible: PropTypes.bool.isRequired
}).isRequired,
- showToast: PropTypes.func.isRequired,
- setToastText: PropTypes.func.isRequired,
autosaveProject: PropTypes.func.isRequired,
router: PropTypes.shape({
setRouteLeaveHook: PropTypes.func
}).isRequired,
- route: PropTypes.object.isRequired,
+ route: PropTypes.oneOfType([PropTypes.object, PropTypes.element]).isRequired,
setUnsavedChanges: PropTypes.func.isRequired,
setTheme: PropTypes.func.isRequired,
setAutorefresh: PropTypes.func.isRequired,
@@ -580,8 +575,10 @@ IDEView.propTypes = {
startRefreshSketch: PropTypes.func.isRequired,
setBlobUrl: PropTypes.func.isRequired,
setPreviousPath: PropTypes.func.isRequired,
- resetProject: PropTypes.func.isRequired,
- console: PropTypes.array.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
diff --git a/client/modules/IDE/reducers/console.js b/client/modules/IDE/reducers/console.js
index 215865c0..294342ff 100644
--- a/client/modules/IDE/reducers/console.js
+++ b/client/modules/IDE/reducers/console.js
@@ -2,11 +2,18 @@ import * as ActionTypes from '../../../constants';
const consoleMax = 200;
const initialState = [];
+let messageId = 0;
const console = (state = initialState, action) => {
+ let messages;
switch (action.type) {
case ActionTypes.CONSOLE_EVENT:
- return state.concat(action.event).slice(-consoleMax);
+ messages = [...action.event];
+ messages.forEach((message) => {
+ message.id = messageId;
+ messageId += 1;
+ });
+ return state.concat(messages).slice(-consoleMax);
case ActionTypes.CLEAR_CONSOLE:
return [];
default:
diff --git a/client/modules/IDE/reducers/editorAccessibility.js b/client/modules/IDE/reducers/editorAccessibility.js
index 03defd11..4806fa42 100644
--- a/client/modules/IDE/reducers/editorAccessibility.js
+++ b/client/modules/IDE/reducers/editorAccessibility.js
@@ -1,21 +1,20 @@
import * as ActionTypes from '../../../constants';
const initialState = {
- lineNumber: 'line',
lintMessages: []
};
+let messageId = 0;
const editorAccessibility = (state = initialState, action) => {
switch (action.type) {
case ActionTypes.UPDATE_LINT_MESSAGE:
+ messageId += 1;
return Object.assign({}, state, {
lintMessages: state.lintMessages.concat(
- { severity: action.severity, line: action.line, message: action.message })
+ { severity: action.severity, line: action.line, message: action.message, id: messageId })
});
case ActionTypes.CLEAR_LINT_MESSAGE:
return Object.assign({}, state, { lintMessages: [] });
- case ActionTypes.UPDATE_LINENUMBER:
- return Object.assign({}, state, { lineNumber: `line ${action.lineNumber}` });
default:
return state;
}
diff --git a/client/modules/IDE/reducers/files.js b/client/modules/IDE/reducers/files.js
index 4e9139b4..9cb624de 100644
--- a/client/modules/IDE/reducers/files.js
+++ b/client/modules/IDE/reducers/files.js
@@ -1,5 +1,5 @@
-import * as ActionTypes from '../../../constants';
import objectID from 'bson-objectid';
+import * as ActionTypes from '../../../constants';
const defaultSketch = `function setup() {
createCanvas(400, 400);
@@ -42,7 +42,8 @@ const initialState = () => {
id: r,
_id: r,
children: [a, b, c],
- fileType: 'folder'
+ fileType: 'folder',
+ content: ''
},
{
name: 'sketch.js',
@@ -92,7 +93,7 @@ function deleteChild(state, parentId, id) {
function deleteMany(state, ids) {
const newState = [...state];
- ids.forEach(id => {
+ ids.forEach((id) => {
let fileIndex;
newState.find((file, index) => {
if (file.id === id) {
@@ -111,7 +112,7 @@ const files = (state, action) => {
}
switch (action.type) {
case ActionTypes.UPDATE_FILE_CONTENT:
- return state.map(file => {
+ return state.map((file) => {
if (file.name !== action.name) {
return file;
}
@@ -119,7 +120,7 @@ const files = (state, action) => {
return Object.assign({}, file, { content: action.content });
});
case ActionTypes.SET_BLOB_URL:
- return state.map(file => {
+ return state.map((file) => {
if (file.name !== action.name) {
return file;
}
@@ -151,7 +152,7 @@ const files = (state, action) => {
fileType: action.fileType || 'file' }];
}
case ActionTypes.SHOW_FILE_OPTIONS:
- return state.map(file => {
+ return state.map((file) => {
if (file.id !== action.id) {
return file;
}
@@ -159,7 +160,7 @@ const files = (state, action) => {
return Object.assign({}, file, { isOptionsOpen: true });
});
case ActionTypes.HIDE_FILE_OPTIONS:
- return state.map(file => {
+ return state.map((file) => {
if (file.id !== action.id) {
return file;
}
@@ -167,7 +168,7 @@ const files = (state, action) => {
return Object.assign({}, file, { isOptionsOpen: false });
});
case ActionTypes.UPDATE_FILE_NAME:
- return state.map(file => {
+ return state.map((file) => {
if (file.id !== action.id) {
return file;
}
@@ -188,7 +189,7 @@ const files = (state, action) => {
// return newState.filter(file => file.id !== action.id);
}
case ActionTypes.SHOW_EDIT_FILE_NAME:
- return state.map(file => {
+ return state.map((file) => {
if (file.id !== action.id) {
return file;
}
@@ -196,7 +197,7 @@ const files = (state, action) => {
return Object.assign({}, file, { isEditingName: true });
});
case ActionTypes.HIDE_EDIT_FILE_NAME:
- return state.map(file => {
+ return state.map((file) => {
if (file.id !== action.id) {
return file;
}
@@ -204,21 +205,21 @@ const files = (state, action) => {
return Object.assign({}, file, { isEditingName: false });
});
case ActionTypes.SET_SELECTED_FILE:
- return state.map(file => {
+ return state.map((file) => {
if (file.id === action.selectedFile) {
return Object.assign({}, file, { isSelectedFile: true });
}
return Object.assign({}, file, { isSelectedFile: false });
});
case ActionTypes.SHOW_FOLDER_CHILDREN:
- return state.map(file => {
+ return state.map((file) => {
if (file.id === action.id) {
return Object.assign({}, file, { isFolderClosed: false });
}
return file;
});
case ActionTypes.HIDE_FOLDER_CHILDREN:
- return state.map(file => {
+ return state.map((file) => {
if (file.id === action.id) {
return Object.assign({}, file, { isFolderClosed: true });
}
@@ -229,9 +230,9 @@ const files = (state, action) => {
}
};
-export const getHTMLFile = (state) => state.filter(file => file.name.match(/.*\.html$/i))[0];
-export const getJSFiles = (state) => state.filter(file => file.name.match(/.*\.js$/i));
-export const getCSSFiles = (state) => state.filter(file => file.name.match(/.*\.css$/i));
-export const getLinkedFiles = (state) => state.filter(file => file.url);
+export const getHTMLFile = state => state.filter(file => file.name.match(/.*\.html$/i))[0];
+export const getJSFiles = state => state.filter(file => file.name.match(/.*\.js$/i));
+export const getCSSFiles = state => state.filter(file => file.name.match(/.*\.css$/i));
+export const getLinkedFiles = state => state.filter(file => file.url);
export default files;
diff --git a/client/modules/IDE/reducers/project.js b/client/modules/IDE/reducers/project.js
index 2a89d519..e09e72ce 100644
--- a/client/modules/IDE/reducers/project.js
+++ b/client/modules/IDE/reducers/project.js
@@ -1,5 +1,5 @@
-import * as ActionTypes from '../../../constants';
import generate from 'project-name-generator';
+import * as ActionTypes from '../../../constants';
const initialState = () => {
const generatedString = generate({ words: 2 }).spaced;
diff --git a/client/modules/IDE/reducers/projects.js b/client/modules/IDE/reducers/projects.js
index f167c8a3..05acd147 100644
--- a/client/modules/IDE/reducers/projects.js
+++ b/client/modules/IDE/reducers/projects.js
@@ -5,7 +5,7 @@ const sketches = (state = [], action) => {
case ActionTypes.SET_PROJECTS:
return action.projects;
case ActionTypes.DELETE_PROJECT:
- return state.filter((sketch) =>
+ return state.filter(sketch =>
sketch.id !== action.id
);
default:
diff --git a/client/modules/User/actions.js b/client/modules/User/actions.js
index 21617ac5..89818ee8 100644
--- a/client/modules/User/actions.js
+++ b/client/modules/User/actions.js
@@ -1,6 +1,6 @@
-import * as ActionTypes from '../../constants';
import { browserHistory } from 'react-router';
import axios from 'axios';
+import * as ActionTypes from '../../constants';
import { showErrorModal, justOpenedProject } from '../IDE/actions/ide';
@@ -16,9 +16,9 @@ export function authError(error) {
export function signUpUser(previousPath, formValues) {
return (dispatch) => {
axios.post(`${ROOT_URL}/signup`, formValues, { withCredentials: true })
- .then(response => {
+ .then((response) => {
dispatch({ type: ActionTypes.AUTH_USER,
- user: response.data
+ user: response.data
});
dispatch(justOpenedProject());
browserHistory.push(previousPath);
@@ -48,9 +48,9 @@ export function loginUserFailure(error) {
export function validateAndLoginUser(previousPath, formProps, dispatch) {
return new Promise((resolve, reject) => {
loginUser(formProps)
- .then(response => {
+ .then((response) => {
dispatch({ type: ActionTypes.AUTH_USER,
- user: response.data
+ user: response.data
});
dispatch({
type: ActionTypes.SET_PREFERENCES,
@@ -60,7 +60,7 @@ export function validateAndLoginUser(previousPath, formProps, dispatch) {
browserHistory.push(previousPath);
resolve();
})
- .catch(response => {
+ .catch((response) => {
reject({ password: response.data.message, _error: 'Login failed!' });
});
});
@@ -69,7 +69,7 @@ export function validateAndLoginUser(previousPath, formProps, dispatch) {
export function getUser() {
return (dispatch) => {
axios.get(`${ROOT_URL}/session`, { withCredentials: true })
- .then(response => {
+ .then((response) => {
dispatch({
type: ActionTypes.AUTH_USER,
user: response.data
@@ -79,7 +79,7 @@ export function getUser() {
preferences: response.data.preferences
});
})
- .catch(response => {
+ .catch((response) => {
dispatch(authError(response.data.error));
});
};
@@ -88,13 +88,13 @@ export function getUser() {
export function validateSession() {
return (dispatch, getState) => {
axios.get(`${ROOT_URL}/session`, { withCredentials: true })
- .then(response => {
+ .then((response) => {
const state = getState();
if (state.user.username !== response.data.username) {
dispatch(showErrorModal('staleSession'));
}
})
- .catch(response => {
+ .catch((response) => {
if (response.status === 404) {
dispatch(showErrorModal('staleSession'));
}
diff --git a/client/modules/User/components/LoginForm.jsx b/client/modules/User/components/LoginForm.jsx
index 31047940..b1049049 100644
--- a/client/modules/User/components/LoginForm.jsx
+++ b/client/modules/User/components/LoginForm.jsx
@@ -40,9 +40,14 @@ LoginForm.propTypes = {
handleSubmit: PropTypes.func.isRequired,
validateAndLoginUser: PropTypes.func.isRequired,
submitting: PropTypes.bool,
- invalid: PropTypes.bool,
pristine: PropTypes.bool,
previousPath: PropTypes.string.isRequired
};
+LoginForm.defaultProps = {
+ submitting: false,
+ pristine: true,
+ invalid: false
+};
+
export default LoginForm;
diff --git a/client/modules/User/components/NewPasswordForm.jsx b/client/modules/User/components/NewPasswordForm.jsx
index 3dc57eba..6e28de49 100644
--- a/client/modules/User/components/NewPasswordForm.jsx
+++ b/client/modules/User/components/NewPasswordForm.jsx
@@ -44,7 +44,13 @@ NewPasswordForm.propTypes = {
pristine: PropTypes.bool,
params: PropTypes.shape({
reset_password_token: PropTypes.string,
- }),
+ }).isRequired,
+};
+
+NewPasswordForm.defaultProps = {
+ invalid: false,
+ pristine: true,
+ submitting: false
};
export default NewPasswordForm;
diff --git a/client/modules/User/components/ResetPasswordForm.jsx b/client/modules/User/components/ResetPasswordForm.jsx
index cbc3c14f..2c3dd4c9 100644
--- a/client/modules/User/components/ResetPasswordForm.jsx
+++ b/client/modules/User/components/ResetPasswordForm.jsx
@@ -31,7 +31,13 @@ ResetPasswordForm.propTypes = {
pristine: PropTypes.bool,
user: PropTypes.shape({
resetPasswordInitiate: PropTypes.bool
- })
+ }).isRequired
+};
+
+ResetPasswordForm.defaultProps = {
+ submitting: false,
+ pristine: true,
+ invalid: false
};
export default ResetPasswordForm;
diff --git a/client/modules/User/components/SignupForm.jsx b/client/modules/User/components/SignupForm.jsx
index ffc33cf6..58513d1e 100644
--- a/client/modules/User/components/SignupForm.jsx
+++ b/client/modules/User/components/SignupForm.jsx
@@ -69,4 +69,10 @@ SignupForm.propTypes = {
previousPath: PropTypes.string.isRequired
};
+SignupForm.defaultProps = {
+ submitting: false,
+ pristine: true,
+ invalid: false
+};
+
export default SignupForm;
diff --git a/client/modules/User/pages/LoginView.jsx b/client/modules/User/pages/LoginView.jsx
index 2cabbeef..255d6408 100644
--- a/client/modules/User/pages/LoginView.jsx
+++ b/client/modules/User/pages/LoginView.jsx
@@ -1,10 +1,10 @@
import React, { PropTypes } from 'react';
import { reduxForm } from 'redux-form';
+import { Link, browserHistory } from 'react-router';
+import InlineSVG from 'react-inlinesvg';
import { validateAndLoginUser } from '../actions';
import LoginForm from '../components/LoginForm';
// import GithubButton from '../components/GithubButton';
-import { Link, browserHistory } from 'react-router';
-import InlineSVG from 'react-inlinesvg';
const exitUrl = require('../../../images/exit.svg');
const logoUrl = require('../../../images/p5js-logo.svg');
@@ -41,7 +41,7 @@ class LoginView extends React.Component {
{/*
Or
*/}
- Don't have an account?
+ Don't have an account?
Sign Up
diff --git a/client/modules/User/pages/NewPasswordView.jsx b/client/modules/User/pages/NewPasswordView.jsx
index d1f0bd4b..03f6da64 100644
--- a/client/modules/User/pages/NewPasswordView.jsx
+++ b/client/modules/User/pages/NewPasswordView.jsx
@@ -1,11 +1,12 @@
import React, { PropTypes } from 'react';
import { reduxForm } from 'redux-form';
-import NewPasswordForm from '../components/NewPasswordForm';
-import * as UserActions from '../actions';
-import { bindActionCreators } from 'redux';
import classNames from 'classnames';
import { browserHistory } from 'react-router';
import InlineSVG from 'react-inlinesvg';
+import { bindActionCreators } from 'redux';
+import NewPasswordForm from '../components/NewPasswordForm';
+import * as UserActions from '../actions';
+
const exitUrl = require('../../../images/exit.svg');
const logoUrl = require('../../../images/p5js-logo.svg');
@@ -55,11 +56,11 @@ class NewPasswordView extends React.Component {
NewPasswordView.propTypes = {
params: PropTypes.shape({
reset_password_token: PropTypes.string,
- }),
+ }).isRequired,
validateResetPasswordToken: PropTypes.func.isRequired,
user: PropTypes.shape({
resetPasswordInvalid: PropTypes.bool
- })
+ }).isRequired
};
function validate(formProps) {
diff --git a/client/modules/User/pages/ResetPasswordView.jsx b/client/modules/User/pages/ResetPasswordView.jsx
index 230bdc4e..1badd774 100644
--- a/client/modules/User/pages/ResetPasswordView.jsx
+++ b/client/modules/User/pages/ResetPasswordView.jsx
@@ -1,11 +1,12 @@
import React, { PropTypes } from 'react';
import { Link, browserHistory } from 'react-router';
-import * as UserActions from '../actions';
-import { bindActionCreators } from 'redux';
-import { reduxForm } from 'redux-form';
-import ResetPasswordForm from '../components/ResetPasswordForm';
import classNames from 'classnames';
import InlineSVG from 'react-inlinesvg';
+import { bindActionCreators } from 'redux';
+import { reduxForm } from 'redux-form';
+import * as UserActions from '../actions';
+import ResetPasswordForm from '../components/ResetPasswordForm';
+
const exitUrl = require('../../../images/exit.svg');
const logoUrl = require('../../../images/p5js-logo.svg');
@@ -43,7 +44,7 @@ class ResetPasswordView extends React.Component {
Reset Your Password
- Your password reset email should arrive shortly. If you don't see it, check
+ Your password reset email should arrive shortly. If you don't see it, check
in your spam folder as sometimes it can end up there.
diff --git a/client/modules/User/pages/SignupView.jsx b/client/modules/User/pages/SignupView.jsx
index f43310a2..d5759957 100644
--- a/client/modules/User/pages/SignupView.jsx
+++ b/client/modules/User/pages/SignupView.jsx
@@ -1,11 +1,12 @@
import React, { PropTypes } from 'react';
import { bindActionCreators } from 'redux';
-import * as UserActions from '../actions';
-import { reduxForm } from 'redux-form';
-import SignupForm from '../components/SignupForm';
import axios from 'axios';
import { Link, browserHistory } from 'react-router';
import InlineSVG from 'react-inlinesvg';
+import { reduxForm } from 'redux-form';
+import * as UserActions from '../actions';
+import SignupForm from '../components/SignupForm';
+
const exitUrl = require('../../../images/exit.svg');
const logoUrl = require('../../../images/p5js-logo.svg');
@@ -66,7 +67,7 @@ function asyncValidate(formProps, dispatch, props) {
queryParams[fieldToValidate] = formProps[fieldToValidate];
queryParams.check_type = fieldToValidate;
return axios.get('/api/signup/duplicate_check', { params: queryParams })
- .then(response => {
+ .then((response) => {
if (response.data.exists) {
const error = {};
error[fieldToValidate] = response.data.message;
@@ -90,7 +91,7 @@ function validate(formProps) {
if (!formProps.email) {
errors.email = 'Please enter an email.';
- } else if (!formProps.email.match(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i)) {
+ } else if (!formProps.email.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i)) {
errors.email = 'Please enter a valid email address.';
}
diff --git a/client/modules/User/reducers.js b/client/modules/User/reducers.js
index 9e3b5b9c..04220f58 100644
--- a/client/modules/User/reducers.js
+++ b/client/modules/User/reducers.js
@@ -4,7 +4,7 @@ const user = (state = { authenticated: false }, action) => {
switch (action.type) {
case ActionTypes.AUTH_USER:
return { ...action.user,
- authenticated: true };
+ authenticated: true };
case ActionTypes.UNAUTH_USER:
return {
authenticated: false
diff --git a/client/reducers.js b/client/reducers.js
index b31912e8..4505623a 100644
--- a/client/reducers.js
+++ b/client/reducers.js
@@ -1,4 +1,5 @@
import { combineReducers } from 'redux';
+import { reducer as form } from 'redux-form';
import files from './modules/IDE/reducers/files';
import ide from './modules/IDE/reducers/ide';
import preferences from './modules/IDE/reducers/preferences';
@@ -8,7 +9,6 @@ import user from './modules/User/reducers';
import sketches from './modules/IDE/reducers/projects';
import toast from './modules/IDE/reducers/toast';
import console from './modules/IDE/reducers/console';
-import { reducer as form } from 'redux-form';
const rootReducer = combineReducers({
form,
diff --git a/client/routes.jsx b/client/routes.jsx
index 45b2b326..50159175 100644
--- a/client/routes.jsx
+++ b/client/routes.jsx
@@ -14,21 +14,21 @@ const checkAuth = (store) => {
store.dispatch(getUser());
};
-const routes = (store) =>
+const routes = store =>
(
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
);
export default routes;
diff --git a/client/styles/abstracts/_placeholders.scss b/client/styles/abstracts/_placeholders.scss
index 93e72b2d..fc1a4876 100644
--- a/client/styles/abstracts/_placeholders.scss
+++ b/client/styles/abstracts/_placeholders.scss
@@ -175,3 +175,16 @@
height:1px;
overflow:hidden;
}
+
+
+%link {
+ @include themify() {
+ text-decoration: none;
+ color: getThemifyVariable('inactive-text-color');
+ cursor: pointer;
+ &:hover {
+ text-decoration: none;
+ color: getThemifyVariable('primary-text-color');
+ }
+ }
+}
\ No newline at end of file
diff --git a/client/styles/base/_base.scss b/client/styles/base/_base.scss
index ea422343..75ae3c76 100644
--- a/client/styles/base/_base.scss
+++ b/client/styles/base/_base.scss
@@ -6,10 +6,13 @@ html, body {
font-size: #{$base-font-size}px;
}
-body, input, button {
+body, input {
@include themify() {
color: getThemifyVariable('primary-text-color');
}
+}
+
+body, input, button {
font-family: Montserrat, sans-serif;
}
@@ -20,13 +23,7 @@ body, input, button {
a {
@include themify() {
- text-decoration: none;
- color: getThemifyVariable('inactive-text-color');
- cursor: pointer;
- &:hover {
- text-decoration: none;
- color: getThemifyVariable('primary-text-color');
- }
+ @extend %link;
}
}
@@ -34,10 +31,6 @@ input, button {
font-size: 1rem;
}
-button:focus {
- outline: none;
-}
-
input {
padding: #{5 / $base-font-size}rem;
border: 1px solid ;
@@ -55,6 +48,14 @@ input[type="submit"] {
}
}
+button {
+ @include themify() {
+ @extend %link;
+ }
+ background: transparent;
+ border: none;
+}
+
h2 {
font-size: #{21 / $base-font-size}em;
}
@@ -71,3 +72,6 @@ h6 {
thead {
text-align: left;
}
+th {
+ text-align: left;
+}
diff --git a/client/styles/components/_console.scss b/client/styles/components/_console.scss
index 68897e9e..93a55dcd 100644
--- a/client/styles/components/_console.scss
+++ b/client/styles/components/_console.scss
@@ -97,6 +97,11 @@
}
.preview-console__clear {
+ @include themify() {
+ @extend %link;
+ }
+ background: transparent;
+ border: none;
padding-right: #{10 / $base-font-size}rem;
.preview-console--collapsed & {
display: none;
diff --git a/client/styles/components/_preferences.scss b/client/styles/components/_preferences.scss
index 926e4e55..e684cd96 100644
--- a/client/styles/components/_preferences.scss
+++ b/client/styles/components/_preferences.scss
@@ -24,7 +24,8 @@
margin-right: #{-6 / $base-font-size}rem;
}
-.preference button {
+.preference__minus-button,
+.preference__plus-button {
@include themify() {
@extend %preferences-button;
width: #{32 / $base-font-size}rem;
diff --git a/client/styles/components/_sidebar.scss b/client/styles/components/_sidebar.scss
index a24e1e7d..7b9e999b 100644
--- a/client/styles/components/_sidebar.scss
+++ b/client/styles/components/_sidebar.scss
@@ -56,6 +56,7 @@
height: #{20 / $base-font-size}rem;
font-size: #{12 / $base-font-size}rem;
cursor: pointer;
+ position: relative;
@include themify() {
color: map-get($theme-map, 'inactive-text-color');
&:hover > .file-item__content .sidebar__file-item-name {
@@ -106,6 +107,15 @@
.sidebar__file-item--editing & {
display: none;
}
+ &:before {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ content: '';
+ width: 100%;
+ }
}
.sidebar__file-item-show-options {
@@ -225,6 +235,8 @@
& svg {
height: #{10 / $base-font-size}rem;
}
+ background-color: transparent;
+ border: none;
}
.sidebar__file-item-closed {
@@ -260,6 +272,14 @@
width: #{145 / $base-font-size}rem;
}
+.sidebar__file-item-option {
+ @include themify() {
+ @extend %link;
+ }
+ background-color: transparent;
+ border: none;
+}
+
.sidebar__file-item--closed .file-item__children {
display: none;
diff --git a/package.json b/package.json
index 6646923c..1c6a952d 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,7 @@
"build": "NODE_ENV=production webpack --config webpack.config.prod.js --progress",
"test": "echo \"Error: no test specified\" && exit 1",
"fetch-examples": "node fetch-examples.js",
- "postinstall" : "git submodule update --remote --recursive"
+ "postinstall": "git submodule update --remote --recursive"
},
"main": "index.js",
"author": "Cassie Tarakajian",
@@ -20,27 +20,25 @@
"url": "git+https://github.com/catarak/p5.js-web-editor.git"
},
"devDependencies": {
- "babel-eslint": "^6.1.0",
+ "babel-eslint": "^7.1.1",
"babel-loader": "^6.2.4",
"babel-plugin-transform-react-constant-elements": "^6.8.0",
"babel-plugin-transform-react-inline-elements": "^6.8.0",
"babel-plugin-transform-react-remove-prop-types": "^0.2.6",
- "babel-polyfill": "^6.8.0",
"babel-preset-es2015": "^6.6.0",
"babel-preset-es2015-native-modules": "^6.9.2",
"babel-preset-react": "^6.5.0",
"babel-preset-react-hmre": "^1.1.1",
"babel-preset-react-optimize": "^1.0.1",
"babel-preset-stage-0": "^6.5.0",
- "babel-register": "^6.8.0",
"chunk-manifest-webpack-plugin": "^0.1.0",
"css-loader": "^0.23.1",
"cssnano": "^3.7.1",
- "eslint": "^2.13.1",
- "eslint-config-airbnb": "^9.0.1",
- "eslint-plugin-import": "^1.9.2",
- "eslint-plugin-jsx-a11y": "^1.5.3",
- "eslint-plugin-react": "^5.2.2",
+ "eslint": "^3.14.0",
+ "eslint-config-airbnb": "^14.0.0",
+ "eslint-plugin-import": "^2.2.0",
+ "eslint-plugin-jsx-a11y": "^3.0.2",
+ "eslint-plugin-react": "^6.9.0",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",
"node-sass": "^3.7.0",
@@ -49,14 +47,8 @@
"postcss-focus": "^1.0.0",
"postcss-loader": "^0.9.1",
"postcss-reporter": "^1.3.3",
- "redux-devtools": "^3.3.1",
- "redux-devtools-dock-monitor": "^1.1.1",
- "redux-devtools-log-monitor": "^1.0.11",
"sass-loader": "^3.2.0",
"style-loader": "^0.13.1",
- "webpack": "^1.14.0",
- "webpack-dev-middleware": "^1.6.1",
- "webpack-hot-middleware": "^2.10.0",
"webpack-manifest-plugin": "^1.1.0"
},
"engines": {
@@ -67,6 +59,8 @@
"async": "^2.0.0",
"axios": "^0.12.0",
"babel-core": "^6.8.0",
+ "babel-polyfill": "^6.8.0",
+ "babel-register": "^6.8.0",
"bcrypt-nodejs": "0.0.3",
"blob-util": "^1.2.1",
"body-parser": "^1.15.1",
@@ -106,6 +100,9 @@
"react-router": "^2.6.0",
"react-split-pane": "^0.1.44",
"redux": "^3.5.2",
+ "redux-devtools": "^3.3.1",
+ "redux-devtools-dock-monitor": "^1.1.1",
+ "redux-devtools-log-monitor": "^1.0.11",
"redux-form": "^5.3.3",
"redux-thunk": "^2.1.0",
"request": "^2.76.0",
@@ -113,6 +110,9 @@
"s3-policy": "^0.2.0",
"shortid": "^2.2.6",
"srcdoc-polyfill": "^0.2.0",
+ "webpack": "^1.14.0",
+ "webpack-dev-middleware": "^1.6.1",
+ "webpack-hot-middleware": "^2.10.0",
"xhr": "^2.2.1"
}
}
diff --git a/server/config/passport.js b/server/config/passport.js
index 7ec0e1ba..515f816c 100644
--- a/server/config/passport.js
+++ b/server/config/passport.js
@@ -1,9 +1,9 @@
+import User from '../models/user';
+
const passport = require('passport');
const GitHubStrategy = require('passport-github').Strategy;
const LocalStrategy = require('passport-local').Strategy;
-import User from '../models/user';
-
passport.serializeUser((user, done) => {
done(null, user.id);
});
@@ -30,7 +30,7 @@ passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, don
return done(null, false, { msg: 'Invalid email or password.' });
});
})
- .catch((err) => done(null, false, { msg: err }));
+ .catch(err => done(null, false, { msg: err }));
}));
/**
@@ -42,20 +42,19 @@ passport.use(new GitHubStrategy({
callbackURL: '/auth/github/callback',
passReqToCallback: true
}, (req, accessToken, refreshToken, profile, done) => {
- User.findOne({ github: profile.id }, (err, existingUser) => {
+ User.findOne({ github: profile.id }, (findByGithubErr, existingUser) => {
if (existingUser) {
- return done(null, existingUser);
+ done(null, existingUser);
+ return;
}
- User.findOne({ email: profile._json.email }, (err, existingEmailUser) => {
+ User.findOne({ email: profile._json.email }, (findByEmailErr, existingEmailUser) => {
if (existingEmailUser) {
existingEmailUser.email = existingEmailUser.email || profile._json.email;
existingEmailUser.github = profile.id;
existingEmailUser.username = existingEmailUser.username || profile.username;
existingEmailUser.tokens.push({ kind: 'github', accessToken });
existingEmailUser.name = existingEmailUser.name || profile.displayName;
- existingEmailUser.save((err) => {
- return done(null, existingEmailUser);
- });
+ existingEmailUser.save(saveErr => done(null, existingEmailUser));
} else {
const user = new User();
user.email = profile._json.email;
@@ -63,9 +62,7 @@ passport.use(new GitHubStrategy({
user.username = profile.username;
user.tokens.push({ kind: 'github', accessToken });
user.name = profile.displayName;
- user.save((err) => {
- return done(null, user);
- });
+ user.save(saveErr => done(null, user));
}
});
});
diff --git a/server/controllers/aws.controller.js b/server/controllers/aws.controller.js
index 9ced0bf2..7a1b098c 100644
--- a/server/controllers/aws.controller.js
+++ b/server/controllers/aws.controller.js
@@ -26,3 +26,5 @@ export function signS3(req, res) {
};
return res.json(result);
}
+
+export default signS3;
diff --git a/server/controllers/embed.controller.js b/server/controllers/embed.controller.js
index 8e8db4ad..b5cfa9ef 100644
--- a/server/controllers/embed.controller.js
+++ b/server/controllers/embed.controller.js
@@ -1,10 +1,10 @@
+import jsdom, { serializeDocument } from 'jsdom';
import Project from '../models/project';
import {
injectMediaUrls,
resolvePathsForElementsWithAttribute,
resolveScripts,
resolveStyles } from '../utils/previewGeneration';
-import jsdom, { serializeDocument } from 'jsdom';
export function serveProject(req, res) {
Project.findById(req.params.project_id)
@@ -32,3 +32,5 @@ export function serveProject(req, res) {
});
});
}
+
+export default serveProject;
diff --git a/server/controllers/file.controller.js b/server/controllers/file.controller.js
index dab443c8..6cf4af5a 100644
--- a/server/controllers/file.controller.js
+++ b/server/controllers/file.controller.js
@@ -16,16 +16,18 @@ export function createFile(req, res) {
}, (err, updatedProject) => {
if (err) {
console.log(err);
- return res.json({ success: false });
+ res.json({ success: false });
+ return;
}
const newFile = updatedProject.files[updatedProject.files.length - 1];
updatedProject.files.id(req.body.parentId).children.push(newFile.id);
- updatedProject.save(innerErr => {
+ updatedProject.save((innerErr) => {
if (innerErr) {
console.log(innerErr);
- return res.json({ success: false });
+ res.json({ success: false });
+ return;
}
- return res.json(updatedProject.files[updatedProject.files.length - 1]);
+ res.json(updatedProject.files[updatedProject.files.length - 1]);
});
});
}
@@ -38,13 +40,13 @@ function getAllDescendantIds(files, nodeId) {
}
function deleteMany(files, ids) {
- ids.forEach(id => {
+ ids.forEach((id) => {
files.id(id).remove();
});
}
function deleteChild(files, parentId, id) {
- files = files.map((file) => {
+ return files.map((file) => {
if (file.id === parentId) {
file.children = file.children.filter(child => child !== id);
return file;
@@ -57,11 +59,11 @@ export function deleteFile(req, res) {
Project.findById(req.params.project_id, (err, project) => {
const idsToDelete = getAllDescendantIds(project.files, req.params.file_id);
deleteMany(project.files, [req.params.file_id, ...idsToDelete]);
- deleteChild(project.files, req.query.parentId, req.params.file_id);
+ project.files = deleteChild(project.files, req.query.parentId, req.params.file_id);
// project.files.id(req.params.file_id).remove();
// const childrenArray = project.files.id(req.query.parentId).children;
// project.files.id(req.query.parentId).children = childrenArray.filter(id => id !== req.params.file_id);
- project.save(innerErr => {
+ project.save((innerErr) => {
res.json(project.files);
});
});
@@ -70,12 +72,14 @@ export function deleteFile(req, res) {
export function getFileContent(req, res) {
Project.findById(req.params.project_id, (err, project) => {
if (err) {
- return res.status(404).send({ success: false, message: 'Project with that id does not exist.' });
+ res.status(404).send({ success: false, message: 'Project with that id does not exist.' });
+ return;
}
const filePath = req.params[0];
const resolvedFile = resolvePathToFile(filePath, project.files);
if (!resolvedFile) {
- return res.status(404).send({ success: false, message: 'File with that name and path does not exist.' });
+ res.status(404).send({ success: false, message: 'File with that name and path does not exist.' });
+ return;
}
res.send(resolvedFile.content);
});
diff --git a/server/controllers/project.controller.js b/server/controllers/project.controller.js
index aa4ee40d..00ce586d 100644
--- a/server/controllers/project.controller.js
+++ b/server/controllers/project.controller.js
@@ -1,13 +1,13 @@
-import Project from '../models/project';
-import User from '../models/user';
import archiver from 'archiver';
import request from 'request';
-import moment from 'moment';
+import Project from '../models/project';
+import User from '../models/user';
export function createProject(req, res) {
if (!req.user) {
- return res.status(403).send({ success: false, message: 'Session does not match owner of project.' });
+ res.status(403).send({ success: false, message: 'Session does not match owner of project.' });
+ return;
}
let projectValues = {
@@ -17,20 +17,27 @@ export function createProject(req, res) {
projectValues = Object.assign(projectValues, req.body);
Project.create(projectValues, (err, newProject) => {
- if (err) { return res.json({ success: false }); }
+ if (err) {
+ res.json({ success: false });
+ return;
+ }
Project.populate(newProject,
{ path: 'user', select: 'username' },
(innerErr, newProjectWithUser) => {
- if (innerErr) { return res.json({ success: false }); }
- return res.json(newProjectWithUser);
+ if (innerErr) {
+ res.json({ success: false });
+ return;
+ }
+ res.json(newProjectWithUser);
});
});
}
export function updateProject(req, res) {
- Project.findById(req.params.project_id, (err, project) => {
+ Project.findById(req.params.project_id, (findProjectErr, project) => {
if (!req.user || !project.user.equals(req.user._id)) {
- return res.status(403).send({ success: false, message: 'Session does not match owner of project.' });
+ res.status(403).send({ success: false, message: 'Session does not match owner of project.' });
+ return;
}
// if (req.body.updatedAt && moment(req.body.updatedAt) < moment(project.updatedAt)) {
// return res.status(409).send({ success: false, message: 'Attempted to save stale version of project.' });
@@ -40,27 +47,29 @@ export function updateProject(req, res) {
$set: req.body
})
.populate('user', 'username')
- .exec((err, updatedProject) => {
- if (err) {
- console.log(err);
- return res.json({ success: false });
+ .exec((updateProjectErr, updatedProject) => {
+ if (updateProjectErr) {
+ console.log(updateProjectErr);
+ res.json({ success: false });
+ return;
}
if (updatedProject.files.length !== req.body.files.length) {
const oldFileIds = updatedProject.files.map(file => file.id);
const newFileIds = req.body.files.map(file => file.id);
const staleIds = oldFileIds.filter(id => newFileIds.indexOf(id) === -1);
- staleIds.forEach(staleId => {
+ staleIds.forEach((staleId) => {
updatedProject.files.id(staleId).remove();
});
updatedProject.save((innerErr) => {
if (innerErr) {
console.log(innerErr);
- return res.json({ success: false });
+ res.json({ success: false });
+ return;
}
- return res.json(updatedProject);
+ res.json(updatedProject);
});
}
- return res.json(updatedProject);
+ res.json(updatedProject);
});
});
}
@@ -77,15 +86,17 @@ export function getProject(req, res) {
}
export function deleteProject(req, res) {
- Project.findById(req.params.project_id, (err, project) => {
+ Project.findById(req.params.project_id, (findProjectErr, project) => {
if (!req.user || !project.user.equals(req.user._id)) {
- return res.status(403).json({ success: false, message: 'Session does not match owner of project.' });
+ res.status(403).json({ success: false, message: 'Session does not match owner of project.' });
+ return;
}
- Project.remove({ _id: req.params.project_id }, (err) => {
- if (err) {
- return res.status(404).send({ message: 'Project with that id does not exist' });
+ Project.remove({ _id: req.params.project_id }, (removeProjectError) => {
+ if (removeProjectError) {
+ res.status(404).send({ message: 'Project with that id does not exist' });
+ return;
}
- return res.json({ success: true });
+ res.json({ success: true });
});
});
}
@@ -100,7 +111,7 @@ export function getProjects(req, res) {
});
} else {
// could just move this to client side
- return res.json([]);
+ res.json([]);
}
}
@@ -108,18 +119,18 @@ export function getProjectsForUser(req, res) {
if (req.params.username) {
User.findOne({ username: req.params.username }, (err, user) => {
if (!user) {
- return res.status(404).json({ message: 'User with that username does not exist.' });
+ res.status(404).json({ message: 'User with that username does not exist.' });
+ return;
}
Project.find({ user: user._id }) // eslint-disable-line no-underscore-dangle
.sort('-createdAt')
.select('name files id createdAt updatedAt')
- .exec((err, projects) => res.json(projects));
+ .exec((innerErr, projects) => res.json(projects));
});
} else {
// could just move this to client side
- return res.json([]);
+ res.json([]);
}
- return null;
}
function buildZip(project, req, res) {
@@ -127,7 +138,6 @@ function buildZip(project, req, res) {
const rootFile = project.files.find(file => file.name === 'root');
const numFiles = project.files.filter(file => file.fileType !== 'folder').length;
const files = project.files;
- const projectName = project.name;
let numCompletedFiles = 0;
zip.on('error', (err) => {
@@ -140,27 +150,25 @@ function buildZip(project, req, res) {
function addFileToZip(file, path) {
if (file.fileType === 'folder') {
const newPath = file.name === 'root' ? path : `${path}${file.name}/`;
- file.children.forEach(fileId => {
+ file.children.forEach((fileId) => {
const childFile = files.find(f => f.id === fileId);
(() => {
addFileToZip(childFile, newPath);
})();
});
- } else {
- if (file.url) {
- request({ method: 'GET', url: file.url, encoding: null }, (err, response, body) => {
- zip.append(body, { name: `${path}${file.name}` });
- numCompletedFiles += 1;
- if (numCompletedFiles === numFiles) {
- zip.finalize();
- }
- });
- } else {
- zip.append(file.content, { name: `${path}${file.name}` });
+ } else if (file.url) {
+ request({ method: 'GET', url: file.url, encoding: null }, (err, response, body) => {
+ zip.append(body, { name: `${path}${file.name}` });
numCompletedFiles += 1;
if (numCompletedFiles === numFiles) {
zip.finalize();
}
+ });
+ } else {
+ zip.append(file.content, { name: `${path}${file.name}` });
+ numCompletedFiles += 1;
+ if (numCompletedFiles === numFiles) {
+ zip.finalize();
}
}
}
diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js
index 648fd870..306f7ee5 100644
--- a/server/controllers/user.controller.js
+++ b/server/controllers/user.controller.js
@@ -1,8 +1,8 @@
-import User from '../models/user';
import crypto from 'crypto';
import async from 'async';
import nodemailer from 'nodemailer';
import mg from 'nodemailer-mailgun-transport';
+import User from '../models/user';
export function createUser(req, res, next) {
const user = new User({
@@ -12,17 +12,25 @@ export function createUser(req, res, next) {
});
User.findOne({ email: req.body.email },
- (err, existingUser) => { // eslint-disable-line consistent-return
- if (err) { res.status(404).send({ error: err }); }
+ (err, existingUser) => {
+ if (err) {
+ res.status(404).send({ error: err });
+ return;
+ }
if (existingUser) {
- return res.status(422).send({ error: 'Email is in use' });
+ res.status(422).send({ error: 'Email is in use' });
+ return;
}
- user.save((saveErr) => { // eslint-disable-line consistent-return
- if (saveErr) { return next(saveErr); }
- req.logIn(user, (loginErr) => { // eslint-disable-line consistent-return
+ user.save((saveErr) => {
+ if (saveErr) {
+ next(saveErr);
+ return;
+ }
+ req.logIn(user, (loginErr) => {
if (loginErr) {
- return next(loginErr);
+ next(loginErr);
+ return;
}
res.json({
email: req.user.email,
@@ -58,21 +66,24 @@ export function duplicateUserCheck(req, res) {
export function updatePreferences(req, res) {
User.findById(req.user.id, (err, user) => {
if (err) {
- return res.status(500).json({ error: err });
+ res.status(500).json({ error: err });
+ return;
}
if (!user) {
- return res.status(404).json({ error: 'Document not found' });
+ res.status(404).json({ error: 'Document not found' });
+ return;
}
const preferences = Object.assign({}, user.preferences, req.body.preferences);
user.preferences = preferences;
- user.save((err) => {
- if (err) {
- return res.status(500).json({ error: err });
+ user.save((saveErr) => {
+ if (saveErr) {
+ res.status(500).json({ error: saveErr });
+ return;
}
- return res.json(user.preferences);
+ res.json(user.preferences);
});
});
}
@@ -88,13 +99,14 @@ export function resetPasswordInitiate(req, res) {
(token, done) => {
User.findOne({ email: req.body.email }, (err, user) => {
if (!user) {
- return res.json({ success: true, message: 'If the email is registered with the editor, an email has been sent.' });
+ res.json({ success: true, message: 'If the email is registered with the editor, an email has been sent.' });
+ return;
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
- user.save((err) => {
- done(err, token, user);
+ user.save((saveErr) => {
+ done(saveErr, token, user);
});
});
},
@@ -124,41 +136,41 @@ export function resetPasswordInitiate(req, res) {
], (err) => {
if (err) {
console.log(err);
- return res.json({ success: false });
+ res.json({ success: false });
+ return;
}
- // send email here
- return res.json({ success: true, message: 'If the email is registered with the editor, an email has been sent.' });
+ res.json({ success: true, message: 'If the email is registered with the editor, an email has been sent.' });
});
}
export function validateResetPasswordToken(req, res) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, (err, user) => {
if (!user) {
- return res.status(401).json({ success: false, message: 'Password reset token is invalid or has expired.' });
+ res.status(401).json({ success: false, message: 'Password reset token is invalid or has expired.' });
+ return;
}
res.json({ success: true });
});
}
export function updatePassword(req, res) {
- User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function (err, user) {
+ User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, (err, user) => {
if (!user) {
- return res.status(401).json({ success: false, message: 'Password reset token is invalid or has expired.' });
+ res.status(401).json({ success: false, message: 'Password reset token is invalid or has expired.' });
+ return;
}
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
- user.save(function (err) {
- req.logIn(user, function (err) {
- return res.json({
- email: req.user.email,
- username: req.user.username,
- preferences: req.user.preferences,
- id: req.user._id
- });
- });
+ user.save((saveErr) => {
+ req.logIn(user, loginErr => res.json({
+ email: req.user.email,
+ username: req.user.username,
+ preferences: req.user.preferences,
+ id: req.user._id
+ }));
});
});
diff --git a/server/examples.js b/server/examples.js
index 658df6fa..2e2eda8d 100644
--- a/server/examples.js
+++ b/server/examples.js
@@ -3,10 +3,9 @@ import Q from 'q';
import mongoose from 'mongoose';
import objectID from 'bson-objectid';
import shortid from 'shortid';
+import eachSeries from 'async/eachSeries';
import User from './models/user';
import Project from './models/project';
-import async from 'async';
-import eachSeries from 'async/eachSeries';
const defaultHTML =
`
@@ -30,8 +29,8 @@ const defaultCSS =
}
`;
-const client_id = process.env.GITHUB_ID;
-const client_secret = process.env.GITHUB_SECRET;
+const clientId = process.env.GITHUB_ID;
+const clientSecret = process.env.GITHUB_SECRET;
const headers = { 'User-Agent': 'p5js-web-editor/0.0.1' };
@@ -41,144 +40,106 @@ mongoose.connection.on('error', () => {
process.exit(1);
});
-getp5User();
-
-function getp5User() {
- User.findOne({ username: 'p5' }, (err, user) => {
- if (err) throw err;
-
- if (!user) {
- user = new User({
- username: 'p5',
- email: 'p5-examples@gmail.com',
- password: 'test'
- });
- user.save(err => {
- if (err) throw err;
- console.log('Created a user p5' + user);
- });
- }
-
- Project.find({ user: user._id }, (err, projects) => {
- // if there are already some sketches, delete them
- console.log('Deleting old projects...');
- projects.forEach(project => {
- Project.remove({ _id: project._id }, err => {
- if (err) throw err;
- });
- });
- });
-
- return getCategories()
- .then(getSketchesInCategories)
- .then(getSketchContent)
- .then(createProjectsInP5user);
- });
-}
-
function getCategories() {
- let categories = [];
+ const categories = [];
const options = {
- url: 'https://api.github.com/repos/processing/p5.js-website/contents/dist/assets/examples/en?client_id=' +
- client_id + '&client_secret=' + client_secret,
+ url: `https://api.github.com/repos/processing/p5.js-website/contents/dist/assets/examples/en?client_id=${
+ clientId}&client_secret=${clientSecret}`,
method: 'GET',
headers
};
- return rp(options).then(res => {
+ return rp(options).then((res) => {
const json = JSON.parse(res);
- json.forEach(metadata => {
+ json.forEach((metadata) => {
let category = '';
- for (let j = 1; j < metadata.name.split('_').length; j++) {
- category += metadata.name.split('_')[j] + ' ';
+ for (let j = 1; j < metadata.name.split('_').length; j += 1) {
+ category += `${metadata.name.split('_')[j]} `;
}
categories.push({ url: metadata.url, name: category });
});
return categories;
- }).catch(err => {
+ }).catch((err) => {
throw err;
});
}
function getSketchesInCategories(categories) {
- return Q.all(categories.map(category => {
+ return Q.all(categories.map((category) => {
const options = {
- url: category.url.replace('?ref=master', '') + '?client_id=' + client_id + '&client_secret=' + client_secret,
+ url: `${category.url.replace('?ref=master', '')}?client_id=${clientId}&client_secret=${clientSecret}`,
method: 'GET',
headers
};
- return rp(options).then(res => {
- let projectsInOneCategory = [];
+ return rp(options).then((res) => {
+ const projectsInOneCategory = [];
const examples = JSON.parse(res);
- examples.forEach(example => {
+ examples.forEach((example) => {
let projectName;
if (example.name === '02_Instance_Container.js') {
- for (let i = 1; i < 5; i++) {
- const instanceProjectName = category.name + ': ' + 'Instance Container ' + i;
+ for (let i = 1; i < 5; i += 1) {
+ const instanceProjectName = `${category.name}: Instance Container ${i}`;
projectsInOneCategory.push({ sketchUrl: example.download_url, projectName: instanceProjectName });
}
} else {
if (example.name.split('_')[1]) {
- projectName = category.name + ': ' + example.name.split('_').slice(1).join(' ').replace('.js', '');
+ projectName = `${category.name}: ${example.name.split('_').slice(1).join(' ').replace('.js', '')}`;
} else {
- projectName = category.name + ': ' + example.name.replace('.js', '');
+ projectName = `${category.name}: ${example.name.replace('.js', '')}`;
}
projectsInOneCategory.push({ sketchUrl: example.download_url, projectName });
}
});
return projectsInOneCategory;
- }).catch(err => {
+ }).catch((err) => {
throw err;
});
}));
}
function getSketchContent(projectsInAllCategories) {
- return Q.all(projectsInAllCategories.map(projectsInOneCategory => {
- return Q.all(projectsInOneCategory.map(project => {
- const options = {
- url: project.sketchUrl.replace('?ref=master', '') + '?client_id=' + client_id + '&client_secret=' + client_secret,
- method: 'GET',
- headers
- };
+ return Q.all(projectsInAllCategories.map(projectsInOneCategory => Q.all(projectsInOneCategory.map((project) => {
+ const options = {
+ url: `${project.sketchUrl.replace('?ref=master', '')}?client_id=${clientId}&client_secret=${clientSecret}`,
+ method: 'GET',
+ headers
+ };
- return rp(options).then(res => {
- const noNumberprojectName = project.projectName.replace(/(\d+)/g, '');
- if (noNumberprojectName === 'Instance Mode : Instance Container ') {
- for (let i = 0; i < 4; i++) {
- let splitedRes = res.split('*/')[1].split('