From a1dcf775577f066457894346acf02362f71b305f Mon Sep 17 00:00:00 2001 From: catarak Date: Thu, 25 Aug 2016 00:18:28 -0400 Subject: [PATCH 1/4] upload text files locally --- client/modules/IDE/actions/files.js | 3 +- client/modules/IDE/actions/uploader.js | 135 ++++++++++++------ client/modules/IDE/components/FileUploader.js | 3 +- client/modules/IDE/reducers/files.js | 2 +- 4 files changed, 97 insertions(+), 46 deletions(-) diff --git a/client/modules/IDE/actions/files.js b/client/modules/IDE/actions/files.js index 32e67835..d9bb8e9f 100644 --- a/client/modules/IDE/actions/files.js +++ b/client/modules/IDE/actions/files.js @@ -104,7 +104,8 @@ export function createFile(formProps) { type: ActionTypes.CREATE_FILE, name: createUniqueName(formProps.name, state.files), id: `${maxFileId + 1}`, - url: formProps.url + url: formProps.url, + content: formProps.content || '' }); dispatch({ type: ActionTypes.HIDE_MODAL diff --git a/client/modules/IDE/actions/uploader.js b/client/modules/IDE/actions/uploader.js index c8a44d3f..ee305990 100644 --- a/client/modules/IDE/actions/uploader.js +++ b/client/modules/IDE/actions/uploader.js @@ -4,62 +4,111 @@ import { createFile } from './files'; const s3Bucket = `http://${process.env.S3_BUCKET}.s3.amazonaws.com/`; const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api'; +function localIntercept(file, options = {}) { + return new Promise((resolve, reject) => { + if (!options.readType) { + // const mime = file.type; + // const textType = a(_textTypes).any(type => { + // const re = new RegExp(type); + // return re.test(mime); + // }); + // options.readType = textType ? 'readAsText' : 'readAsDataURL'; + options.readType = 'readAsText'; // eslint-disable-line + } + const reader = new window.FileReader(); + reader.onload = () => { + resolve(reader.result); + }; + reader.onerror = () => { + reject(reader.result); + }; + + // run the reader + reader[options.readType](file); + }); +} + export function dropzoneAcceptCallback(file, done) { return () => { - file.postData = []; // eslint-disable-line - axios.post(`${ROOT_URL}/S3/sign`, { - name: file.name, - type: file.type, - size: file.size, - // _csrf: document.getElementById('__createPostToken').value - }, - { - withCredentials: true + // for text files and small files + // check mime type + // if text, local interceptor + if (file.type.match(/text\//)) { + localIntercept(file).then(result => { + file.content = result; // eslint-disable-line + done(); }) - .then(response => { - file.custom_status = 'ready'; // eslint-disable-line - file.postData = response.data; // eslint-disable-line - file.s3 = response.data.key; // eslint-disable-line - file.previewTemplate.className += ' uploading'; // eslint-disable-line - done(); - }) - .catch(response => { - file.custom_status = 'rejected'; // eslint-disable-line - if (response.data.responseText && response.data.responseText.message) { - done(response.data.responseText.message); - } - done('error preparing the upload'); - }); + .catch(result => { + done(`Failed to download file ${file.name}: ${result}`); + console.warn(file); + }); + } else { + file.postData = []; // eslint-disable-line + axios.post(`${ROOT_URL}/S3/sign`, { + name: file.name, + type: file.type, + size: file.size, + // _csrf: document.getElementById('__createPostToken').value + }, + { + withCredentials: true + }) + .then(response => { + file.custom_status = 'ready'; // eslint-disable-line + file.postData = response.data; // eslint-disable-line + file.s3 = response.data.key; // eslint-disable-line + file.previewTemplate.className += ' uploading'; // eslint-disable-line + done(); + }) + .catch(response => { + file.custom_status = 'rejected'; // eslint-disable-line + if (response.data.responseText && response.data.responseText.message) { + done(response.data.responseText.message); + } + done('error preparing the upload'); + }); + } }; } export function dropzoneSendingCallback(file, xhr, formData) { return () => { - Object.keys(file.postData).forEach(key => { - formData.append(key, file.postData[key]); - }); - formData.append('Content-type', ''); - formData.append('Content-length', ''); - formData.append('acl', 'public-read'); + if (!file.type.match(/text\//)) { + Object.keys(file.postData).forEach(key => { + formData.append(key, file.postData[key]); + }); + formData.append('Content-type', ''); + formData.append('Content-length', ''); + formData.append('acl', 'public-read'); + } }; } export function dropzoneCompleteCallback(file) { return (dispatch, getState) => { // eslint-disable-line - let inputHidden = '`; - // document.getElementById('uploader').appendChild(inputHidden); - document.getElementById('uploader').innerHTML += inputHidden; + if (!file.type.match(/text\//)) { + let inputHidden = '`; + // document.getElementById('uploader').appendChild(inputHidden); + document.getElementById('uploader').innerHTML += inputHidden; - const formParams = { - name: file.name, - url: `${s3Bucket}${file.postData.key}` - }; - createFile(formParams)(dispatch, getState); + const formParams = { + name: file.name, + url: `${s3Bucket}${file.postData.key}` + }; + createFile(formParams)(dispatch, getState); + } else { + const formParams = { + name: file.name, + content: file.content + }; + console.log(formParams); + createFile(formParams)(dispatch, getState); + } }; } diff --git a/client/modules/IDE/components/FileUploader.js b/client/modules/IDE/components/FileUploader.js index 817dd4ee..a034715d 100644 --- a/client/modules/IDE/components/FileUploader.js +++ b/client/modules/IDE/components/FileUploader.js @@ -23,7 +23,8 @@ class FileUploader extends React.Component { maxThumbnailFilesize: 8, // 3MB thumbnailWidth: 200, thumbnailHeight: 200, - acceptedFiles: 'image/bmp,image/gif,image/jpg,image/jpeg,image/png,audio/*', + // TODO what is a good list of MIME types???? + acceptedFiles: 'image/*,audio/*,text/javascript,text/html,text/css', dictDefaultMessage: 'Drop files here to upload or click to use the file browser', accept: this.props.dropzoneAcceptCallback, sending: this.props.dropzoneSendingCallback, diff --git a/client/modules/IDE/reducers/files.js b/client/modules/IDE/reducers/files.js index 150bda18..ff1a5a16 100644 --- a/client/modules/IDE/reducers/files.js +++ b/client/modules/IDE/reducers/files.js @@ -74,7 +74,7 @@ const files = (state = initialState, action) => { case ActionTypes.RESET_PROJECT: return initialState; case ActionTypes.CREATE_FILE: - return [...state, { name: action.name, id: action.id, content: '', url: action.url }]; + return [...state, { name: action.name, id: action.id, content: action.content, url: action.url }]; case ActionTypes.SHOW_FILE_OPTIONS: return state.map(file => { if (file.id !== action.id) { From ec728eb39299b8067365ef795c4e4be84802f414 Mon Sep 17 00:00:00 2001 From: catarak Date: Thu, 25 Aug 2016 11:25:22 -0400 Subject: [PATCH 2/4] fix uploading when project is saved --- client/modules/IDE/actions/files.js | 3 ++- client/modules/IDE/actions/uploader.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/client/modules/IDE/actions/files.js b/client/modules/IDE/actions/files.js index d9bb8e9f..cf09198b 100644 --- a/client/modules/IDE/actions/files.js +++ b/client/modules/IDE/actions/files.js @@ -71,7 +71,8 @@ export function createFile(formProps) { if (state.project.id) { const postParams = { name: createUniqueName(formProps.name, state.files), - url: formProps.url + url: formProps.url, + content: formProps.content || '' }; axios.post(`${ROOT_URL}/projects/${state.project.id}/files`, postParams, { withCredentials: true }) .then(response => { diff --git a/client/modules/IDE/actions/uploader.js b/client/modules/IDE/actions/uploader.js index ee305990..ad5e9c51 100644 --- a/client/modules/IDE/actions/uploader.js +++ b/client/modules/IDE/actions/uploader.js @@ -33,6 +33,7 @@ export function dropzoneAcceptCallback(file, done) { // for text files and small files // check mime type // if text, local interceptor + console.log(file.type); if (file.type.match(/text\//)) { localIntercept(file).then(result => { file.content = result; // eslint-disable-line From db85dcc04b7c5cb7eccd23c1375eacacc68bbe92 Mon Sep 17 00:00:00 2001 From: MathuraMG Date: Thu, 25 Aug 2016 12:32:06 -0400 Subject: [PATCH 3/4] add word line --- client/modules/IDE/components/Editor.js | 3 ++- client/modules/IDE/components/EditorAccessibility.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client/modules/IDE/components/Editor.js b/client/modules/IDE/components/Editor.js index 34658b6f..8b2bd924 100644 --- a/client/modules/IDE/components/Editor.js +++ b/client/modules/IDE/components/Editor.js @@ -54,7 +54,8 @@ class Editor extends React.Component { this.props.updateFileContent(this.props.file.name, this._cm.getValue()); })); this._cm.on('keyup', () => { - this.props.updateLineNumber(parseInt((this._cm.getCursor().line) + 1, 10)); + const temp = `line ${parseInt((this._cm.getCursor().line) + 1, 10)}`; + document.getElementById('current-line').innerHTML = temp; }); // this._cm.on('change', () => { // eslint-disable-line // // this.props.updateFileContent('sketch.js', this._cm.getValue()); diff --git a/client/modules/IDE/components/EditorAccessibility.js b/client/modules/IDE/components/EditorAccessibility.js index b2e0cbe3..e98b4605 100644 --- a/client/modules/IDE/components/EditorAccessibility.js +++ b/client/modules/IDE/components/EditorAccessibility.js @@ -27,7 +27,7 @@ class EditorAccessibility extends React.Component { {messages}

Current line - {this.props.lineNumber} +

); From 1de8c02cf2dc2c7483ca65957631c844828cfa6d Mon Sep 17 00:00:00 2001 From: catarak Date: Thu, 25 Aug 2016 12:39:36 -0400 Subject: [PATCH 4/4] fix a few regexes for preview frame --- client/modules/IDE/actions/uploader.js | 7 ++++--- client/modules/IDE/components/FileUploader.js | 8 ++++++-- client/modules/IDE/components/PreviewFrame.js | 2 +- client/modules/IDE/reducers/files.js | 6 +++--- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/client/modules/IDE/actions/uploader.js b/client/modules/IDE/actions/uploader.js index ad5e9c51..44173a59 100644 --- a/client/modules/IDE/actions/uploader.js +++ b/client/modules/IDE/actions/uploader.js @@ -1,5 +1,6 @@ import axios from 'axios'; import { createFile } from './files'; +const textFileRegex = /text\//; const s3Bucket = `http://${process.env.S3_BUCKET}.s3.amazonaws.com/`; const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api'; @@ -34,7 +35,7 @@ export function dropzoneAcceptCallback(file, done) { // check mime type // if text, local interceptor console.log(file.type); - if (file.type.match(/text\//)) { + if (file.type.match(textFileRegex)) { localIntercept(file).then(result => { file.content = result; // eslint-disable-line done(); @@ -74,7 +75,7 @@ export function dropzoneAcceptCallback(file, done) { export function dropzoneSendingCallback(file, xhr, formData) { return () => { - if (!file.type.match(/text\//)) { + if (!file.type.match(textFileRegex)) { Object.keys(file.postData).forEach(key => { formData.append(key, file.postData[key]); }); @@ -87,7 +88,7 @@ export function dropzoneSendingCallback(file, xhr, formData) { export function dropzoneCompleteCallback(file) { return (dispatch, getState) => { // eslint-disable-line - if (!file.type.match(/text\//)) { + if (!file.type.match(textFileRegex)) { let inputHidden = ' { - if (jsFileString.match(/^('|")(?!(http:\/\/|https:\/\/)).*\.(png|jpg|jpeg|gif|bmp|mp3|wav|aiff|ogg)('|")$/)) { + if (jsFileString.match(/^('|")(?!(http:\/\/|https:\/\/)).*\.(png|jpg|jpeg|gif|bmp|mp3|wav|aiff|ogg|json)('|")$/i)) { const filePath = jsFileString.substr(1, jsFileString.length - 2); let fileName = filePath; if (fileName.match(/^\.\//)) { diff --git a/client/modules/IDE/reducers/files.js b/client/modules/IDE/reducers/files.js index ff1a5a16..0f19f511 100644 --- a/client/modules/IDE/reducers/files.js +++ b/client/modules/IDE/reducers/files.js @@ -131,9 +131,9 @@ export const setSelectedFile = (state, id) => }); export const getFile = (state, id) => state.filter(file => file.id === id)[0]; -export const getHTMLFile = (state) => state.filter(file => file.name.match(/.*\.html$/))[0]; -export const getJSFiles = (state) => state.filter(file => file.name.match(/.*\.js$/)); -export const getCSSFiles = (state) => state.filter(file => file.name.match(/.*\.css$/)); +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;