diff --git a/client/modules/IDE/actions/files.js b/client/modules/IDE/actions/files.js index 32e67835..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 => { @@ -104,7 +105,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..44173a59 100644 --- a/client/modules/IDE/actions/uploader.js +++ b/client/modules/IDE/actions/uploader.js @@ -1,65 +1,116 @@ 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'; +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 + console.log(file.type); + if (file.type.match(textFileRegex)) { + 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(textFileRegex)) { + 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(textFileRegex)) { + 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/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 13c26753..a39c535d 100644 --- a/client/modules/IDE/components/EditorAccessibility.js +++ b/client/modules/IDE/components/EditorAccessibility.js @@ -28,7 +28,7 @@ class EditorAccessibility extends React.Component { {messages}

Current line - {this.props.lineNumber} +

); diff --git a/client/modules/IDE/components/FileUploader.js b/client/modules/IDE/components/FileUploader.js index 817dd4ee..d79d4b55 100644 --- a/client/modules/IDE/components/FileUploader.js +++ b/client/modules/IDE/components/FileUploader.js @@ -23,11 +23,16 @@ 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,application/json,application/x-font-ttf,application/x-font-truetype', dictDefaultMessage: 'Drop files here to upload or click to use the file browser', accept: this.props.dropzoneAcceptCallback, sending: this.props.dropzoneSendingCallback, - complete: this.props.dropzoneCompleteCallback + complete: this.props.dropzoneCompleteCallback, + error: (file, errorMessage) => { + console.log(file); + console.log(errorMessage); + } }); } diff --git a/client/modules/IDE/components/PreviewFrame.js b/client/modules/IDE/components/PreviewFrame.js index 3abd5455..a7fd872a 100644 --- a/client/modules/IDE/components/PreviewFrame.js +++ b/client/modules/IDE/components/PreviewFrame.js @@ -104,7 +104,7 @@ class PreviewFrame extends React.Component { let jsFileStrings = newJSFile.content.match(/(['"])((\\\1|.)*?)\1/gm); jsFileStrings = jsFileStrings || []; jsFileStrings.forEach(jsFileString => { - 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 150bda18..0f19f511 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) { @@ -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;