2016-08-24 05:01:20 +02:00
|
|
|
import objectID from 'bson-objectid';
|
2017-02-22 20:29:35 +01:00
|
|
|
import * as ActionTypes from '../../../constants';
|
2016-05-05 23:48:26 +02:00
|
|
|
|
2018-03-01 19:28:43 +01:00
|
|
|
const defaultSketch = `function setup() {
|
2016-06-24 00:29:55 +02:00
|
|
|
createCanvas(400, 400);
|
2018-03-01 19:28:43 +01:00
|
|
|
}
|
2016-05-10 00:28:38 +02:00
|
|
|
|
2018-03-01 19:28:43 +01:00
|
|
|
function draw() {
|
2016-06-24 00:29:55 +02:00
|
|
|
background(220);
|
2016-07-06 21:09:05 +02:00
|
|
|
}`;
|
|
|
|
|
|
|
|
const defaultHTML =
|
2016-07-12 03:54:08 +02:00
|
|
|
`<!DOCTYPE html>
|
2020-01-28 23:12:46 +01:00
|
|
|
<html lang="en">
|
2016-07-06 21:09:05 +02:00
|
|
|
<head>
|
2020-07-30 19:45:13 +02:00
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/addons/p5.sound.min.js"></script>
|
2016-07-12 03:54:08 +02:00
|
|
|
<link rel="stylesheet" type="text/css" href="style.css">
|
2017-10-30 20:36:09 +01:00
|
|
|
<meta charset="utf-8" />
|
2018-02-22 22:47:25 +01:00
|
|
|
|
2016-07-06 21:09:05 +02:00
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<script src="sketch.js"></script>
|
2018-03-01 19:28:43 +01:00
|
|
|
</body>
|
2016-07-06 21:09:05 +02:00
|
|
|
</html>
|
|
|
|
`;
|
|
|
|
|
2016-07-12 03:54:08 +02:00
|
|
|
const defaultCSS =
|
|
|
|
`html, body {
|
|
|
|
margin: 0;
|
|
|
|
padding: 0;
|
|
|
|
}
|
2018-09-08 20:50:39 +02:00
|
|
|
canvas {
|
|
|
|
display: block;
|
|
|
|
}
|
2016-07-12 03:54:08 +02:00
|
|
|
`;
|
2016-07-08 20:57:22 +02:00
|
|
|
|
2016-11-16 22:29:17 +01:00
|
|
|
const initialState = () => {
|
2016-08-24 05:01:20 +02:00
|
|
|
const a = objectID().toHexString();
|
|
|
|
const b = objectID().toHexString();
|
|
|
|
const c = objectID().toHexString();
|
2016-08-24 19:09:48 +02:00
|
|
|
const r = objectID().toHexString();
|
2016-08-24 05:01:20 +02:00
|
|
|
return [
|
|
|
|
{
|
|
|
|
name: 'root',
|
2016-08-24 19:09:48 +02:00
|
|
|
id: r,
|
|
|
|
_id: r,
|
2020-08-03 20:56:31 +02:00
|
|
|
children: [b, a, c],
|
2017-02-22 20:29:35 +01:00
|
|
|
fileType: 'folder',
|
|
|
|
content: ''
|
2016-08-24 05:01:20 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'sketch.js',
|
|
|
|
content: defaultSketch,
|
2016-08-24 19:09:48 +02:00
|
|
|
id: a,
|
|
|
|
_id: a,
|
2016-09-14 21:57:52 +02:00
|
|
|
isSelectedFile: true,
|
2016-09-04 02:31:34 +02:00
|
|
|
fileType: 'file',
|
|
|
|
children: []
|
2016-08-24 05:01:20 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'index.html',
|
|
|
|
content: defaultHTML,
|
2016-08-24 19:09:48 +02:00
|
|
|
id: b,
|
2016-08-25 23:32:27 +02:00
|
|
|
_id: b,
|
2016-09-04 02:31:34 +02:00
|
|
|
fileType: 'file',
|
|
|
|
children: []
|
2016-08-24 05:01:20 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'style.css',
|
|
|
|
content: defaultCSS,
|
2016-08-24 19:09:48 +02:00
|
|
|
id: c,
|
2016-08-25 23:32:27 +02:00
|
|
|
_id: c,
|
2016-09-04 02:31:34 +02:00
|
|
|
fileType: 'file',
|
|
|
|
children: []
|
2016-08-24 05:01:20 +02:00
|
|
|
}];
|
2016-11-16 22:29:17 +01:00
|
|
|
};
|
2016-07-06 21:09:05 +02:00
|
|
|
|
2016-09-02 18:01:23 +02:00
|
|
|
function getAllDescendantIds(state, nodeId) {
|
|
|
|
return state.find(file => file.id === nodeId).children
|
2018-05-05 02:22:39 +02:00
|
|
|
.reduce((acc, childId) => (
|
|
|
|
[...acc, childId, ...getAllDescendantIds(state, childId)]
|
|
|
|
), []);
|
2016-09-02 18:01:23 +02:00
|
|
|
}
|
|
|
|
|
2016-09-03 00:11:27 +02:00
|
|
|
function deleteChild(state, parentId, id) {
|
|
|
|
const newState = state.map((file) => {
|
|
|
|
if (file.id === parentId) {
|
|
|
|
const newFile = Object.assign({}, file);
|
|
|
|
newFile.children = newFile.children.filter(child => child !== id);
|
|
|
|
return newFile;
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
});
|
|
|
|
return newState;
|
|
|
|
}
|
|
|
|
|
2016-09-02 18:01:23 +02:00
|
|
|
function deleteMany(state, ids) {
|
|
|
|
const newState = [...state];
|
2017-02-22 20:29:35 +01:00
|
|
|
ids.forEach((id) => {
|
2016-09-02 18:01:23 +02:00
|
|
|
let fileIndex;
|
|
|
|
newState.find((file, index) => {
|
|
|
|
if (file.id === id) {
|
|
|
|
fileIndex = index;
|
|
|
|
}
|
|
|
|
return file.id === id;
|
|
|
|
});
|
|
|
|
newState.splice(fileIndex, 1);
|
|
|
|
});
|
|
|
|
return newState;
|
|
|
|
}
|
|
|
|
|
2020-08-03 20:56:31 +02:00
|
|
|
function sortedChildrenId(state, children) {
|
|
|
|
const childrenArray = state.filter(file => children.includes(file.id));
|
|
|
|
childrenArray.sort((a, b) => (a.name > b.name ? 1 : -1));
|
|
|
|
return childrenArray.map(child => child.id);
|
|
|
|
}
|
|
|
|
|
2020-08-04 18:24:45 +02:00
|
|
|
function updateParent(state, action) {
|
2020-08-04 06:58:21 +02:00
|
|
|
return state.map((file) => {
|
|
|
|
if (file.id === action.parentId) {
|
|
|
|
const newFile = Object.assign({}, file);
|
|
|
|
newFile.children = [...newFile.children, action.id];
|
|
|
|
return newFile;
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function renameFile(state, action) {
|
|
|
|
return state.map((file) => {
|
|
|
|
if (file.id !== action.id) {
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
return Object.assign({}, file, { name: action.name });
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-08-24 05:01:20 +02:00
|
|
|
const files = (state, action) => {
|
|
|
|
if (state === undefined) {
|
|
|
|
state = initialState(); // eslint-disable-line
|
|
|
|
}
|
2016-06-24 00:29:55 +02:00
|
|
|
switch (action.type) {
|
2016-07-07 19:50:52 +02:00
|
|
|
case ActionTypes.UPDATE_FILE_CONTENT:
|
2017-02-22 20:29:35 +01:00
|
|
|
return state.map((file) => {
|
2019-02-25 18:57:10 +01:00
|
|
|
if (file.id !== action.id) {
|
2016-07-06 21:09:05 +02:00
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
2020-09-21 12:22:19 +02:00
|
|
|
return Object.assign({}, file, { content: action.content, changed: true });
|
2016-07-06 21:09:05 +02:00
|
|
|
});
|
2020-09-21 12:22:19 +02:00
|
|
|
case ActionTypes.SET_UNSAVED_CHANGES:
|
|
|
|
if (action.value) {
|
|
|
|
// ignore.
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
return state.map((file) => {
|
|
|
|
if (file.changed) {
|
|
|
|
return Object.assign({}, file, { changed: false });
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
});
|
|
|
|
// return Object.assign({}, state, { unsavedChanges: action.value });
|
2016-10-22 22:42:43 +02:00
|
|
|
case ActionTypes.SET_BLOB_URL:
|
2017-02-22 20:29:35 +01:00
|
|
|
return state.map((file) => {
|
2019-02-25 18:57:10 +01:00
|
|
|
if (file.id !== action.id) {
|
2016-10-22 22:42:43 +02:00
|
|
|
return file;
|
|
|
|
}
|
|
|
|
return Object.assign({}, file, { blobURL: action.blobURL });
|
|
|
|
});
|
2016-06-24 00:29:55 +02:00
|
|
|
case ActionTypes.NEW_PROJECT:
|
2016-07-06 23:29:07 +02:00
|
|
|
return [...action.files];
|
2016-06-29 18:52:16 +02:00
|
|
|
case ActionTypes.SET_PROJECT:
|
2016-07-06 23:29:07 +02:00
|
|
|
return [...action.files];
|
2016-08-12 18:45:26 +02:00
|
|
|
case ActionTypes.RESET_PROJECT:
|
2016-08-24 21:36:37 +02:00
|
|
|
return initialState();
|
2016-08-24 01:40:47 +02:00
|
|
|
case ActionTypes.CREATE_FILE: // eslint-disable-line
|
2018-05-05 02:22:39 +02:00
|
|
|
{
|
2020-08-04 06:58:21 +02:00
|
|
|
const newState = [
|
2020-08-04 18:24:45 +02:00
|
|
|
...updateParent(state, action),
|
2018-05-05 02:22:39 +02:00
|
|
|
{
|
|
|
|
name: action.name,
|
|
|
|
id: action.id,
|
|
|
|
_id: action._id,
|
|
|
|
content: action.content,
|
|
|
|
url: action.url,
|
|
|
|
children: action.children,
|
2020-09-21 12:22:19 +02:00
|
|
|
fileType: action.fileType || 'file',
|
|
|
|
changed: false,
|
2020-08-04 06:58:21 +02:00
|
|
|
}];
|
2020-08-03 20:56:31 +02:00
|
|
|
return newState.map((file) => {
|
|
|
|
if (file.id === action.parentId) {
|
|
|
|
file.children = sortedChildrenId(newState, file.children);
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
});
|
2018-05-05 02:22:39 +02:00
|
|
|
}
|
2016-08-03 21:11:59 +02:00
|
|
|
case ActionTypes.UPDATE_FILE_NAME:
|
2020-08-03 20:56:31 +02:00
|
|
|
{
|
2020-08-04 06:58:21 +02:00
|
|
|
const newState = renameFile(state, action);
|
2020-08-03 20:56:31 +02:00
|
|
|
return newState.map((file) => {
|
|
|
|
if (file.children.includes(action.id)) {
|
|
|
|
file.children = sortedChildrenId(newState, file.children);
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
});
|
|
|
|
}
|
2016-08-03 21:11:59 +02:00
|
|
|
case ActionTypes.DELETE_FILE:
|
2018-05-05 02:22:39 +02:00
|
|
|
{
|
|
|
|
const newState = deleteMany(state, [action.id, ...getAllDescendantIds(state, action.id)]);
|
|
|
|
return deleteChild(newState, action.parentId, action.id);
|
|
|
|
// const newState = state.map((file) => {
|
|
|
|
// if (file.id === action.parentId) {
|
|
|
|
// const newChildren = file.children.filter(child => child !== action.id);
|
|
|
|
// return { ...file, children: newChildren };
|
|
|
|
// }
|
|
|
|
// return file;
|
|
|
|
// });
|
|
|
|
// return newState.filter(file => file.id !== action.id);
|
|
|
|
}
|
2016-08-24 19:09:48 +02:00
|
|
|
case ActionTypes.SET_SELECTED_FILE:
|
2017-02-22 20:29:35 +01:00
|
|
|
return state.map((file) => {
|
2016-08-24 19:09:48 +02:00
|
|
|
if (file.id === action.selectedFile) {
|
2016-09-14 21:57:52 +02:00
|
|
|
return Object.assign({}, file, { isSelectedFile: true });
|
2016-08-24 19:09:48 +02:00
|
|
|
}
|
2016-09-14 21:57:52 +02:00
|
|
|
return Object.assign({}, file, { isSelectedFile: false });
|
2016-08-24 19:09:48 +02:00
|
|
|
});
|
2016-08-31 00:46:59 +02:00
|
|
|
case ActionTypes.SHOW_FOLDER_CHILDREN:
|
2017-02-22 20:29:35 +01:00
|
|
|
return state.map((file) => {
|
2016-08-31 00:46:59 +02:00
|
|
|
if (file.id === action.id) {
|
|
|
|
return Object.assign({}, file, { isFolderClosed: false });
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
});
|
|
|
|
case ActionTypes.HIDE_FOLDER_CHILDREN:
|
2017-02-22 20:29:35 +01:00
|
|
|
return state.map((file) => {
|
2016-08-31 00:46:59 +02:00
|
|
|
if (file.id === action.id) {
|
|
|
|
return Object.assign({}, file, { isFolderClosed: true });
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
});
|
2016-06-24 00:29:55 +02:00
|
|
|
default:
|
2020-08-04 20:16:25 +02:00
|
|
|
return state.map((file) => {
|
2020-08-04 21:02:02 +02:00
|
|
|
file.children = sortedChildrenId(state, file.children);
|
2020-08-04 20:16:25 +02:00
|
|
|
return file;
|
|
|
|
});
|
2016-06-24 00:29:55 +02:00
|
|
|
}
|
|
|
|
};
|
2016-05-05 23:48:26 +02:00
|
|
|
|
2017-02-22 20:29:35 +01:00
|
|
|
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);
|
2016-07-08 20:57:22 +02:00
|
|
|
|
2016-07-06 21:09:05 +02:00
|
|
|
export default files;
|