From 8c270c2ced11d5ea5bc7b372bd81a89da6b6473f Mon Sep 17 00:00:00 2001 From: Cassie Tarakajian Date: Sat, 22 Oct 2016 16:42:43 -0400 Subject: [PATCH] generate blob urls for text and json files --- client/constants.js | 1 + client/modules/IDE/actions/files.js | 19 +++++++++++++++++++ client/modules/IDE/components/NewFileModal.js | 2 +- client/modules/IDE/components/PreviewFrame.js | 13 +++++++++++-- client/modules/IDE/pages/IDEView.js | 4 +++- client/modules/IDE/reducers/files.js | 7 +++++++ package.json | 3 ++- 7 files changed, 44 insertions(+), 5 deletions(-) diff --git a/client/constants.js b/client/constants.js index 8c59d051..1e50f5b7 100644 --- a/client/constants.js +++ b/client/constants.js @@ -41,6 +41,7 @@ export const SET_SELECTED_FILE = 'SET_SELECTED_FILE'; export const SHOW_MODAL = 'SHOW_MODAL'; export const HIDE_MODAL = 'HIDE_MODAL'; export const CREATE_FILE = 'CREATE_FILE'; +export const SET_BLOB_URL = 'SET_BLOB_URL'; export const EXPAND_SIDEBAR = 'EXPAND_SIDEBAR'; export const COLLAPSE_SIDEBAR = 'COLLAPSE_SIDEBAR'; diff --git a/client/modules/IDE/actions/files.js b/client/modules/IDE/actions/files.js index c599424b..43c03e79 100644 --- a/client/modules/IDE/actions/files.js +++ b/client/modules/IDE/actions/files.js @@ -1,6 +1,7 @@ import * as ActionTypes from '../../../constants'; import axios from 'axios'; import objectID from 'bson-objectid'; +import blobUtil from 'blob-util'; const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api'; @@ -222,3 +223,21 @@ export function hideFolderChildren(id) { id }; } + +export function setBlobUrl(file, blobURL) { + return { + type: ActionTypes.SET_BLOB_URL, + name: file.name, + blobURL + }; +} + +export function getBlobUrl(file) { + if (file.blobUrl) { + blobUtil.revokeObjectURL(file.blobUrl); + } + + const fileBlob = blobUtil.createBlob([file.content], { type: 'text/plain' }); + const blobURL = blobUtil.createObjectURL(fileBlob); + return blobURL; +} diff --git a/client/modules/IDE/components/NewFileModal.js b/client/modules/IDE/components/NewFileModal.js index df3592d0..a1fea74c 100644 --- a/client/modules/IDE/components/NewFileModal.js +++ b/client/modules/IDE/components/NewFileModal.js @@ -51,7 +51,7 @@ function validate(formProps) { if (!formProps.name) { errors.name = 'Please enter a name'; - } else if (!formProps.name.match(/(.+\.js$|.+\.css$|.+\.json$|.+\.txt)/i)) { + } else if (!formProps.name.match(/(.+\.js$|.+\.css$|.+\.json$|.+\.txt$)/i)) { errors.name = 'File must be of type JavaScript, CSS, JSON, or TXT.'; } diff --git a/client/modules/IDE/components/PreviewFrame.js b/client/modules/IDE/components/PreviewFrame.js index ab77c041..6c826f3c 100644 --- a/client/modules/IDE/components/PreviewFrame.js +++ b/client/modules/IDE/components/PreviewFrame.js @@ -4,7 +4,7 @@ import escapeStringRegexp from 'escape-string-regexp'; import srcDoc from 'srcdoc-polyfill'; import loopProtect from 'loop-protect'; - +import { getBlobUrl } from '../actions/files'; const startTag = '@fs-'; @@ -167,12 +167,13 @@ class PreviewFrame extends React.Component { htmlFile = hijackConsoleLogsScript() + htmlFile; const mediaFiles = this.props.files.filter(file => file.url); + const textFiles = this.props.files.filter(file => file.name.match(/(.+\.json$|.+\.txt$)/i)); const jsFiles = []; this.props.jsFiles.forEach(jsFile => { const newJSFile = { ...jsFile }; let jsFileStrings = newJSFile.content.match(/(['"])((\\\1|.)*?)\1/gm); - const jsFileRegex = /^('|")(?!(http:\/\/|https:\/\/)).*\.(png|jpg|jpeg|gif|bmp|mp3|wav|aiff|ogg|json)('|")$/i; + const jsFileRegex = /^('|")(?!(http:\/\/|https:\/\/)).*\.(png|jpg|jpeg|gif|bmp|mp3|wav|aiff|ogg|json|txt)('|")$/i; jsFileStrings = jsFileStrings || []; jsFileStrings.forEach(jsFileString => { if (jsFileString.match(jsFileRegex)) { @@ -184,6 +185,13 @@ class PreviewFrame extends React.Component { newJSFile.content = newJSFile.content.replace(filePath, file.url); // eslint-disable-line } }); + textFiles.forEach(file => { + if (file.name === fileName) { + const blobURL = getBlobUrl(file); + this.props.setBlobUrl(file, blobURL); + newJSFile.content = newJSFile.content.replace(filePath, blobURL); + } + }); } }); newJSFile.content = loopProtect(newJSFile.content); @@ -280,6 +288,7 @@ PreviewFrame.propTypes = { endSketchRefresh: PropTypes.func.isRequired, previewIsRefreshing: PropTypes.bool.isRequired, fullView: PropTypes.bool, + setBlobUrl: PropTypes.func.isRequired }; export default PreviewFrame; diff --git a/client/modules/IDE/pages/IDEView.js b/client/modules/IDE/pages/IDEView.js index 339599a6..223b4877 100644 --- a/client/modules/IDE/pages/IDEView.js +++ b/client/modules/IDE/pages/IDEView.js @@ -327,6 +327,7 @@ class IDEView extends React.Component { previewIsRefreshing={this.props.ide.previewIsRefreshing} endSketchRefresh={this.props.endSketchRefresh} stopSketch={this.props.stopSketch} + setBlobUrl={this.props.setBlobUrl} /> @@ -568,7 +569,8 @@ IDEView.propTypes = { setAutorefresh: PropTypes.func.isRequired, startSketchAndRefresh: PropTypes.func.isRequired, endSketchRefresh: PropTypes.func.isRequired, - startRefreshSketch: PropTypes.func.isRequired + startRefreshSketch: PropTypes.func.isRequired, + setBlobUrl: PropTypes.func.isRequired }; function mapStateToProps(state) { diff --git a/client/modules/IDE/reducers/files.js b/client/modules/IDE/reducers/files.js index 3b1b17cd..27cd527c 100644 --- a/client/modules/IDE/reducers/files.js +++ b/client/modules/IDE/reducers/files.js @@ -119,6 +119,13 @@ const files = (state, action) => { return Object.assign({}, file, { content: action.content }); }); + case ActionTypes.SET_BLOB_URL: + return state.map(file => { + if (file.name !== action.name) { + return file; + } + return Object.assign({}, file, { blobURL: action.blobURL }); + }); case ActionTypes.NEW_PROJECT: return [...action.files]; case ActionTypes.SET_PROJECT: diff --git a/package.json b/package.json index e6aae572..c71984c6 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "axios": "^0.12.0", "babel-core": "^6.8.0", "bcrypt-nodejs": "0.0.3", + "blob-util": "^1.2.1", "body-parser": "^1.15.1", "bson-objectid": "^1.1.4", "classnames": "^2.2.5", @@ -73,7 +74,7 @@ "dropzone": "^4.3.0", "escape-string-regexp": "^1.0.5", "eslint-loader": "^1.3.0", - "express": "^4.13.4", + "express": "^4.13.4", "express-session": "^1.13.0", "file-saver": "^1.3.2", "file-type": "^3.8.0",