fixes #96, downloads now work on safari and firefox

This commit is contained in:
Cassie Tarakajian 2016-11-02 14:08:53 -04:00
parent a06369ab06
commit 85b8f5b589
5 changed files with 64 additions and 54 deletions

View file

@ -42,7 +42,7 @@ function Nav(props) {
if (props.project.id) { if (props.project.id) {
return ( return (
<li className="nav__item"> <li className="nav__item">
<a className="nav__export" onClick={props.exportProjectAsZip}> <a className="nav__export" onClick={() => props.exportProjectAsZip(props.project.id)}>
Download Download
</a> </a>
</li> </li>

View file

@ -1,9 +1,6 @@
import * as ActionTypes from '../../../constants'; import * as ActionTypes from '../../../constants';
import { browserHistory } from 'react-router'; import { browserHistory } from 'react-router';
import axios from 'axios'; import axios from 'axios';
import JSZip from 'jszip';
import JSZipUtils from 'jszip-utils';
import { saveAs } from 'file-saver';
import { showToast, setToastText } from './toast'; import { showToast, setToastText } from './toast';
import { setUnsavedChanges, justOpenedProject, resetJustOpenedProject } from './ide'; import { setUnsavedChanges, justOpenedProject, resetJustOpenedProject } from './ide';
@ -127,53 +124,9 @@ export function createProject() {
}; };
} }
function buildZip(state) { export function exportProjectAsZip(projectId) {
const zip = new JSZip(); const win = window.open(`${ROOT_URL}/projects/${projectId}/zip`, '_blank');
const rootFile = state.files.find(file => file.name === 'root'); win.focus();
const numFiles = state.files.filter(file => file.fileType !== 'folder').length;
const files = state.files;
const projectName = state.project.name;
let numCompletedFiles = 0;
function addFileToZip(file, path) {
if (file.fileType === 'folder') {
const newPath = file.name === 'root' ? path : `${path}${file.name}/`;
file.children.forEach(fileId => {
const childFile = files.find(f => f.id === fileId);
(() => {
addFileToZip(childFile, newPath);
})();
});
} else {
if (file.url) {
JSZipUtils.getBinaryContent(file.url, (err, data) => {
zip.file(`${path}${file.name}`, data, { binary: true });
numCompletedFiles += 1;
if (numCompletedFiles === numFiles) {
zip.generateAsync({ type: 'blob' }).then((content) => {
saveAs(content, `${projectName}.zip`);
});
}
});
} else {
zip.file(`${path}${file.name}`, file.content);
numCompletedFiles += 1;
if (numCompletedFiles === numFiles) {
zip.generateAsync({ type: 'blob' }).then((content) => {
saveAs(content, `${projectName}.zip`);
});
}
}
}
}
addFileToZip(rootFile, '/');
}
export function exportProjectAsZip() {
return (dispatch, getState) => {
const state = getState();
buildZip(state);
};
} }
export function newProject() { export function newProject() {

View file

@ -58,6 +58,7 @@
"node": ">=4" "node": ">=4"
}, },
"dependencies": { "dependencies": {
"archiver": "^1.1.0",
"async": "^2.0.0", "async": "^2.0.0",
"axios": "^0.12.0", "axios": "^0.12.0",
"babel-core": "^6.8.0", "babel-core": "^6.8.0",
@ -76,13 +77,10 @@
"eslint-loader": "^1.3.0", "eslint-loader": "^1.3.0",
"express": "^4.13.4", "express": "^4.13.4",
"express-session": "^1.13.0", "express-session": "^1.13.0",
"file-saver": "^1.3.2",
"file-type": "^3.8.0", "file-type": "^3.8.0",
"htmlhint": "^0.9.13", "htmlhint": "^0.9.13",
"js-beautify": "^1.6.4", "js-beautify": "^1.6.4",
"jshint": "^2.9.2", "jshint": "^2.9.2",
"jszip": "^3.0.0",
"jszip-utils": "0.0.2",
"lodash": "^4.16.4", "lodash": "^4.16.4",
"loop-protect": "git+https://git@github.com/sagar-sm/loop-protect.git", "loop-protect": "git+https://git@github.com/sagar-sm/loop-protect.git",
"moment": "^2.14.1", "moment": "^2.14.1",
@ -102,6 +100,7 @@
"redux": "^3.5.2", "redux": "^3.5.2",
"redux-form": "^5.3.3", "redux-form": "^5.3.3",
"redux-thunk": "^2.1.0", "redux-thunk": "^2.1.0",
"request": "^2.76.0",
"s3-policy": "^0.2.0", "s3-policy": "^0.2.0",
"shortid": "^2.2.6", "shortid": "^2.2.6",
"srcdoc-polyfill": "^0.2.0", "srcdoc-polyfill": "^0.2.0",

View file

@ -1,5 +1,8 @@
import Project from '../models/project'; import Project from '../models/project';
import User from '../models/user'; import User from '../models/user';
import archiver from 'archiver';
import request from 'request';
export function createProject(req, res) { export function createProject(req, res) {
let projectValues = { let projectValues = {
@ -99,3 +102,56 @@ export function getProjectsForUser(req, res) {
return res.json([]); return res.json([]);
} }
} }
function buildZip(project, req, res) {
const zip = archiver('zip');
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', function(err) {
res.status(500).send({error: err.message});
});
res.attachment(`${project.name}.zip`);
zip.pipe(res);
function addFileToZip(file, path) {
if (file.fileType === 'folder') {
const newPath = file.name === 'root' ? path : `${path}${file.name}/`;
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}` });
numCompletedFiles += 1;
if (numCompletedFiles === numFiles) {
zip.finalize();
}
}
}
}
addFileToZip(rootFile, '/');
}
export function downloadProjectAsZip(req, res) {
Project.findById(req.params.project_id, (err, project) => {
//save project to some path
buildZip(project, req, res);
});
}

View file

@ -15,4 +15,6 @@ router.route('/projects').get(ProjectController.getProjects);
router.route('/:username/projects').get(ProjectController.getProjectsForUser); router.route('/:username/projects').get(ProjectController.getProjectsForUser);
router.route('/projects/:project_id/zip').get(ProjectController.downloadProjectAsZip);
export default router; export default router;