From 7f0b7afac106c7bc4d4bdfb1f1ef9cd374444fc3 Mon Sep 17 00:00:00 2001 From: therewasaguy Date: Sun, 17 Jul 2016 19:06:43 -0400 Subject: [PATCH] add Console component, gets postMessage from previewFrame --- client/constants.js | 2 + client/modules/IDE/actions/ide.js | 7 ++ client/modules/IDE/components/Console.js | 49 +++++++++++ client/modules/IDE/components/PreviewFrame.js | 84 ++++++++++++++----- client/modules/IDE/pages/IDEView.js | 13 ++- client/modules/IDE/reducers/ide.js | 8 +- client/styles/components/_console.scss | 14 ++++ 7 files changed, 151 insertions(+), 26 deletions(-) create mode 100644 client/modules/IDE/components/Console.js create mode 100644 client/styles/components/_console.scss diff --git a/client/constants.js b/client/constants.js index 967df39b..f6256cad 100644 --- a/client/constants.js +++ b/client/constants.js @@ -31,5 +31,7 @@ export const SET_PROJECTS = 'SET_PROJECTS'; export const SET_SELECTED_FILE = 'SET_SELECTED_FILE'; +export const CONSOLE_EVENT = 'CONSOLE_EVENT'; + // eventually, handle errors more specifically and better export const ERROR = 'ERROR'; diff --git a/client/modules/IDE/actions/ide.js b/client/modules/IDE/actions/ide.js index 0bcbc414..eec73884 100644 --- a/client/modules/IDE/actions/ide.js +++ b/client/modules/IDE/actions/ide.js @@ -24,3 +24,10 @@ export function setSelectedFile(fileId) { selectedFile: fileId }; } + +export function dispatchConsoleEvent(...args) { + return { + type: ActionTypes.CONSOLE_EVENT, + event: args[0].data + }; +} diff --git a/client/modules/IDE/components/Console.js b/client/modules/IDE/components/Console.js new file mode 100644 index 00000000..06b39c8c --- /dev/null +++ b/client/modules/IDE/components/Console.js @@ -0,0 +1,49 @@ +import React, { PropTypes } from 'react'; + +const consoleMax = 5; + +class Console extends React.Component { + + constructor(props) { + super(props); + this.children = []; + } + + shouldComponentUpdate(nextProps) { + // clear children if paused, but only update when new consoleEvent happens + if (!nextProps.isPlaying) { + this.children = []; + } + return nextProps.consoleEvent !== this.props.consoleEvent; + } + + render() { + const args = this.props.consoleEvent.arguments; + const method = this.props.consoleEvent.method; + + const nextChild = ( +
+ {Object.keys(args).map((key) => {args[key]})} +
+ ); + this.children.push(nextChild); + + if (this.children.length > consoleMax) { + this.children = this.children.slice(0, 1); + } + + return ( +
+ {this.children} +
+ ); + } + +} + +Console.propTypes = { + consoleEvent: PropTypes.object, + isPlaying: PropTypes.bool.isRequired +}; + +export default Console; diff --git a/client/modules/IDE/components/PreviewFrame.js b/client/modules/IDE/components/PreviewFrame.js index b0313441..ac42e845 100644 --- a/client/modules/IDE/components/PreviewFrame.js +++ b/client/modules/IDE/components/PreviewFrame.js @@ -3,14 +3,68 @@ import ReactDOM from 'react-dom'; import escapeStringRegexp from 'escape-string-regexp'; import srcDoc from 'srcdoc-polyfill'; +const hijackConsoleScript = ``; + class PreviewFrame extends React.Component { componentDidMount() { - this.hijackConsole(); - if (this.props.isPlaying) { this.renderFrameContents(); } + + window.addEventListener('message', (msg) => { + if (msg.data.source === 'sketch') { + this.props.dispatchConsoleEvent(msg); + } + }); } componentDidUpdate(prevProps) { @@ -53,29 +107,11 @@ class PreviewFrame extends React.Component { // htmlHeadContents = htmlHeadContents.slice(1, htmlHeadContents.length - 2); // htmlHeadContents += '\n'; // htmlFile = htmlFile.replace(/(?:)([\s\S]*?)(?:<\/head>)/gmi, `\n${htmlHeadContents}\n`); + htmlFile += hijackConsoleScript; return htmlFile; } - hijackConsole() { - const iframeWindow = ReactDOM.findDOMNode(this).contentWindow; - const originalConsole = iframeWindow.console; - iframeWindow.console = {}; - - const methods = [ - 'debug', 'clear', 'error', 'info', 'log', 'warn' - ]; - - methods.forEach((method) => { - iframeWindow.console[method] = (...theArgs) => { - originalConsole[method].apply(originalConsole, theArgs); - - // TO DO: do something with the arguments - // window.alert(JSON.stringify(theArgs)); - }; - }); - } - renderSketch() { const doc = ReactDOM.findDOMNode(this); if (this.props.isPlaying) { @@ -107,7 +143,7 @@ class PreviewFrame extends React.Component { frameBorder="0" title="sketch output" sandbox="allow-scripts allow-pointer-lock allow-same-origin allow-popups allow-modals allow-forms" - > + /> ); } } @@ -120,7 +156,9 @@ PreviewFrame.propTypes = { content: PropTypes.string.isRequired }), jsFiles: PropTypes.array.isRequired, - cssFiles: PropTypes.array.isRequired + cssFiles: PropTypes.array.isRequired, + dispatchConsoleEvent: PropTypes.func.isRequired, + children: PropTypes.element }; export default PreviewFrame; diff --git a/client/modules/IDE/pages/IDEView.js b/client/modules/IDE/pages/IDEView.js index c7308fa9..62f5956e 100644 --- a/client/modules/IDE/pages/IDEView.js +++ b/client/modules/IDE/pages/IDEView.js @@ -5,6 +5,7 @@ import PreviewFrame from '../components/PreviewFrame'; import Toolbar from '../components/Toolbar'; import Preferences from '../components/Preferences'; import Nav from '../../../components/Nav'; +import Console from '../components/Console'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import * as FileActions from '../actions/files'; @@ -77,8 +78,14 @@ class IDEView extends React.Component { } isPlaying={this.props.ide.isPlaying} + dispatchConsoleEvent={this.props.dispatchConsoleEvent} + /> + + ); } } @@ -92,7 +99,8 @@ IDEView.propTypes = { createProject: PropTypes.func.isRequired, saveProject: PropTypes.func.isRequired, ide: PropTypes.shape({ - isPlaying: PropTypes.bool.isRequired + isPlaying: PropTypes.bool.isRequired, + consoleEvent: PropTypes.object }).isRequired, startSketch: PropTypes.func.isRequired, stopSketch: PropTypes.func.isRequired, @@ -125,7 +133,8 @@ IDEView.propTypes = { setSelectedFile: PropTypes.func.isRequired, htmlFile: PropTypes.object.isRequired, jsFiles: PropTypes.array.isRequired, - cssFiles: PropTypes.array.isRequired + cssFiles: PropTypes.array.isRequired, + dispatchConsoleEvent: PropTypes.func.isRequired }; function mapStateToProps(state) { diff --git a/client/modules/IDE/reducers/ide.js b/client/modules/IDE/reducers/ide.js index 9c4c5b88..7fc1d033 100644 --- a/client/modules/IDE/reducers/ide.js +++ b/client/modules/IDE/reducers/ide.js @@ -2,7 +2,11 @@ import * as ActionTypes from '../../../constants'; const initialState = { isPlaying: false, - selectedFile: '1' + selectedFile: '1', + consoleEvent: { + method: undefined, + arguments: [] + } }; const ide = (state = initialState, action) => { @@ -17,6 +21,8 @@ const ide = (state = initialState, action) => { case ActionTypes.SET_PROJECT: case ActionTypes.NEW_PROJECT: return Object.assign({}, state, { selectedFile: action.selectedFile }); + case ActionTypes.CONSOLE_EVENT: + return Object.assign({}, state, { consoleEvent: action.event }); default: return state; } diff --git a/client/styles/components/_console.scss b/client/styles/components/_console.scss new file mode 100644 index 00000000..f1502c46 --- /dev/null +++ b/client/styles/components/_console.scss @@ -0,0 +1,14 @@ +.preview-console { + position: fixed; + width:100%; + height:60px; + right:0px; + bottom: 0px; + background:grey; + z-index:1000; + + & > { + position:relative; + text-align:left; + } +} \ No newline at end of file