From abdb287b1c59eab9842394968005c2a2635d6479 Mon Sep 17 00:00:00 2001 From: Kushagra Gour <chinchang457@gmail.com> Date: Thu, 4 Oct 2018 17:13:17 +0530 Subject: [PATCH] make ContentWraps conditional and add console in files mode --- src/components/ContentWrap.jsx | 1 - ...{ContentWrap2.jsx => ContentWrapFiles.jsx} | 127 +++++++++++++++++- src/components/app.jsx | 41 ++++-- 3 files changed, 148 insertions(+), 21 deletions(-) rename src/components/{ContentWrap2.jsx => ContentWrapFiles.jsx} (81%) diff --git a/src/components/ContentWrap.jsx b/src/components/ContentWrap.jsx index da9327b..4bd14b8 100644 --- a/src/components/ContentWrap.jsx +++ b/src/components/ContentWrap.jsx @@ -34,7 +34,6 @@ export default class ContentWrap extends Component { this.logCount = 0; window.onMessageFromConsole = this.onMessageFromConsole.bind(this); - window.previewException = this.previewException.bind(this); // `clearConsole` is on window because it gets called from inside iframe also. window.clearConsole = this.clearConsole.bind(this); diff --git a/src/components/ContentWrap2.jsx b/src/components/ContentWrapFiles.jsx similarity index 81% rename from src/components/ContentWrap2.jsx rename to src/components/ContentWrapFiles.jsx index 798cd9f..97fc9f9 100644 --- a/src/components/ContentWrap2.jsx +++ b/src/components/ContentWrapFiles.jsx @@ -1,19 +1,19 @@ import { h, Component } from 'preact'; -import UserCodeMirror from './UserCodeMirror.jsx'; -import { computeHtml, computeCss, computeJs } from '../computes'; +import UserCodeMirror from './UserCodeMirror'; import { modes, HtmlModes, CssModes, JsModes } from '../codeModes'; -import { log, writeFile, loadJS, getCompleteHtml } from '../utils'; -import { SplitPane } from './SplitPane.jsx'; +import { log, loadJS } from '../utils'; +import { SplitPane } from './SplitPane'; import { trackEvent } from '../analytics'; import CodeMirror from '../CodeMirror'; -import CodeMirrorBox from './CodeMirrorBox'; import { deferred } from '../deferred'; import { SidePane } from './SidePane'; +import { Console } from './Console'; + const minCodeWrapSize = 33; /* global htmlCodeEl, jsCodeEl, cssCodeEl, logCountEl */ -export default class ContentWrap2 extends Component { +export default class ContentWrapFiles extends Component { constructor(props) { super(props); this.state = { @@ -28,8 +28,12 @@ export default class ContentWrap2 extends Component { this.prefs = {}; this.codeInPreview = { html: null, css: null, js: null }; this.cmCodes = { html: props.currentItem.html, css: '', js: '' }; - // this.cm = {}; this.logCount = 0; + + window.onMessageFromConsole = this.onMessageFromConsole.bind(this); + window.previewException = this.previewException.bind(this); + // `clearConsole` is on window because it gets called from inside iframe also. + window.clearConsole = this.clearConsole.bind(this); } shouldComponentUpdate(nextProps, nextState) { return ( @@ -130,6 +134,19 @@ export default class ContentWrap2 extends Component { var obj = {}; this.props.currentItem.files.forEach(file => { obj[`/user/${file.name}`] = file.content || ''; + + // Add screenlog to index.html + if (file.name === 'index.html') { + obj[`/user/${file.name}`] = + '<script src="' + + (chrome.extension + ? chrome.extension.getURL('lib/screenlog.js') + : `${location.origin}${ + window.DEBUG ? '' : BASE_PATH + }/lib/screenlog.js`) + + '"></script>' + + obj[`/user/${file.name}`]; + } }); navigator.serviceWorker.controller.postMessage(obj); @@ -422,6 +439,92 @@ export default class ContentWrap2 extends Component { this.cm.focus(); } + updateLogCount() { + if (window.logCountEl) { + logCountEl.textContent = this.logCount; + } + } + + onMessageFromConsole() { + /* eslint-disable no-param-reassign */ + [...arguments].forEach(arg => { + if ( + arg && + arg.indexOf && + arg.indexOf('filesystem:chrome-extension') !== -1 + ) { + arg = arg.replace( + /filesystem:chrome-extension.*\.js:(\d+):*(\d*)/g, + 'script $1:$2' + ); + } + try { + this.consoleCm.replaceRange( + arg + + ' ' + + ((arg + '').match(/\[object \w+]/) ? JSON.stringify(arg) : '') + + '\n', + { + line: Infinity + } + ); + } catch (e) { + this.consoleCm.replaceRange('🌀\n', { + line: Infinity + }); + } + this.consoleCm.scrollTo(0, Infinity); + this.logCount++; + }); + this.updateLogCount(); + + /* eslint-enable no-param-reassign */ + } + + previewException(error) { + console.error('Possible infinite loop detected.', error.stack); + this.onMessageFromConsole('Possible infinite loop detected.', error.stack); + } + + toggleConsole() { + this.setState({ isConsoleOpen: !this.state.isConsoleOpen }); + trackEvent('ui', 'consoleToggle'); + } + consoleHeaderDblClickHandler(e) { + if (!e.target.classList.contains('js-console__header')) { + return; + } + trackEvent('ui', 'consoleToggleDblClick'); + this.toggleConsole(); + } + clearConsole() { + this.consoleCm.setValue(''); + this.logCount = 0; + this.updateLogCount(); + } + clearConsoleBtnClickHandler() { + this.clearConsole(); + trackEvent('ui', 'consoleClearBtnClick'); + } + + evalConsoleExpr(e) { + // Clear console on CTRL + L + if ((e.which === 76 || e.which === 12) && e.ctrlKey) { + this.clearConsole(); + trackEvent('ui', 'consoleClearKeyboardShortcut'); + } else if (e.which === 13) { + this.onMessageFromConsole('> ' + e.target.value); + + /* eslint-disable no-underscore-dangle */ + this.frame.contentWindow._wmEvaluate(e.target.value); + + /* eslint-enable no-underscore-dangle */ + + e.target.value = ''; + trackEvent('fn', 'evalConsoleExpr'); + } + } + render() { return ( <SplitPane @@ -489,6 +592,16 @@ export default class ContentWrap2 extends Component { id="demo-frame" allowfullscreen /> + <Console + isConsoleOpen={this.state.isConsoleOpen} + onConsoleHeaderDblClick={this.consoleHeaderDblClickHandler.bind( + this + )} + onClearConsoleBtnClick={this.clearConsoleBtnClickHandler.bind(this)} + toggleConsole={this.toggleConsole.bind(this)} + onEvalInputKeyup={this.evalConsoleExpr.bind(this)} + onReady={el => (this.consoleCm = el)} + /> </div> </SplitPane> ); diff --git a/src/components/app.jsx b/src/components/app.jsx index 8f2f3c9..74cb0f3 100644 --- a/src/components/app.jsx +++ b/src/components/app.jsx @@ -4,7 +4,8 @@ import { h, Component } from 'preact'; import '../service-worker-registration'; import { MainHeader } from './MainHeader.jsx'; -import ContentWrap2 from './ContentWrap2.jsx'; +import ContentWrap from './ContentWrap.jsx'; +import ContentWrapFiles from './ContentWrapFiles.jsx'; import Footer from './Footer.jsx'; import SavedItemPane from './SavedItemPane.jsx'; import AddLibrary from './AddLibrary.jsx'; @@ -1222,18 +1223,32 @@ export default class App extends Component { user={this.state.user} unsavedEditCount={this.state.unsavedEditCount} /> - <ContentWrap2 - currentItem={this.state.currentItem} - onCodeChange={this.onCodeChange.bind(this)} - onCodeSettingsChange={this.onCodeSettingsChange.bind(this)} - onCodeModeChange={this.onCodeModeChange.bind(this)} - onRef={comp => (this.contentWrap = comp)} - prefs={this.state.prefs} - onEditorFocus={this.editorFocusHandler.bind(this)} - onSplitUpdate={this.splitUpdateHandler.bind(this)} - onAddFile={this.addFileHandler.bind(this)} - onRemoveFile={this.removeFileHandler.bind(this)} - /> + {this.state.currentItem && this.state.currentItem.files ? ( + <ContentWrapFiles + currentItem={this.state.currentItem} + onCodeChange={this.onCodeChange.bind(this)} + onCodeSettingsChange={this.onCodeSettingsChange.bind(this)} + onCodeModeChange={this.onCodeModeChange.bind(this)} + onRef={comp => (this.contentWrap = comp)} + prefs={this.state.prefs} + onEditorFocus={this.editorFocusHandler.bind(this)} + onSplitUpdate={this.splitUpdateHandler.bind(this)} + onAddFile={this.addFileHandler.bind(this)} + onRemoveFile={this.removeFileHandler.bind(this)} + /> + ) : ( + <ContentWrap + currentLayoutMode={this.state.currentLayoutMode} + currentItem={this.state.currentItem} + onCodeChange={this.onCodeChange.bind(this)} + onCodeSettingsChange={this.onCodeSettingsChange.bind(this)} + onCodeModeChange={this.onCodeModeChange.bind(this)} + onRef={comp => (this.contentWrap = comp)} + prefs={this.state.prefs} + onEditorFocus={this.editorFocusHandler.bind(this)} + onSplitUpdate={this.splitUpdateHandler.bind(this)} + /> + )} <Footer prefs={this.state.prefs}