Improve current console (#656)
* init v2 * make replay work * fix a failing scenary of react-frame * fix some bugs * delete/comment some files * remove * fix some bugs && remove more comments * remove unnecessary lines * minor tweak * fix some bugs * try to hook iframe using webpack * update * changes according to cassie * minor tweak * fix lint * extract sass * add icons * update webpack config * update webpack configuration * update * tweak * fix a small bug
1
client/images/console-debug-dark.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="10" height="10" viewBox="0 0 24 24"><path fill="#0c99e2" d="M14,12H10V10H14M14,16H10V14H14M20,8H17.19C16.74,7.22 16.12,6.55 15.37,6.04L17,4.41L15.59,3L13.42,5.17C12.96,5.06 12.5,5 12,5C11.5,5 11.04,5.06 10.59,5.17L8.41,3L7,4.41L8.62,6.04C7.88,6.55 7.26,7.22 6.81,8H4V10H6.09C6.04,10.33 6,10.66 6,11V12H4V14H6V15C6,15.34 6.04,15.67 6.09,16H4V18H6.81C7.85,19.79 9.78,21 12,21C14.22,21 16.15,19.79 17.19,18H20V16H17.91C17.96,15.67 18,15.34 18,15V14H20V12H18V11C18,10.66 17.96,10.33 17.91,10H20V8Z" /></svg>
|
After Width: | Height: | Size: 743 B |
1
client/images/console-debug-light.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="10" height="10" viewBox="0 0 24 24"><path fill="#007BBB" d="M14,12H10V10H14M14,16H10V14H14M20,8H17.19C16.74,7.22 16.12,6.55 15.37,6.04L17,4.41L15.59,3L13.42,5.17C12.96,5.06 12.5,5 12,5C11.5,5 11.04,5.06 10.59,5.17L8.41,3L7,4.41L8.62,6.04C7.88,6.55 7.26,7.22 6.81,8H4V10H6.09C6.04,10.33 6,10.66 6,11V12H4V14H6V15C6,15.34 6.04,15.67 6.09,16H4V18H6.81C7.85,19.79 9.78,21 12,21C14.22,21 16.15,19.79 17.19,18H20V16H17.91C17.96,15.67 18,15.34 18,15V14H20V12H18V11C18,10.66 17.96,10.33 17.91,10H20V8Z" /></svg>
|
After Width: | Height: | Size: 743 B |
1
client/images/console-error-dark.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="10" height="10" viewBox="0 0 24 24"><path fill="#df3a3d" d="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z" /></svg>
|
After Width: | Height: | Size: 510 B |
1
client/images/console-error-light.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="10" height="10" viewBox="0 0 24 24"><path fill="#D11518" d="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z" /></svg>
|
After Width: | Height: | Size: 510 B |
1
client/images/console-info-dark.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="10" height="10" viewBox="0 0 24 24"><path fill="#a3a3a3" d="M13,9H11V7H13M13,17H11V11H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" /></svg>
|
After Width: | Height: | Size: 414 B |
1
client/images/console-info-light.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="10" height="10" viewBox="0 0 24 24"><path fill="#7D7D7D" d="M13,9H11V7H13M13,17H11V11H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" /></svg>
|
After Width: | Height: | Size: 414 B |
1
client/images/console-warn-dark.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="10" height="10" viewBox="0 0 24 24"><path fill="#f5bc38" d="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z" /></svg>
|
After Width: | Height: | Size: 359 B |
1
client/images/console-warn-light.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="10" height="10" viewBox="0 0 24 24"><path fill="#FAAF00" d="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z" /></svg>
|
After Width: | Height: | Size: 359 B |
|
@ -2,13 +2,63 @@ import PropTypes from 'prop-types';
|
|||
import React from 'react';
|
||||
import InlineSVG from 'react-inlinesvg';
|
||||
import classNames from 'classnames';
|
||||
import { Console as ConsoleFeed } from 'console-feed';
|
||||
import { CONSOLE_FEED_WITHOUT_ICONS, CONSOLE_FEED_LIGHT_STYLES, CONSOLE_FEED_DARK_STYLES, CONSOLE_FEED_CONTRAST_STYLES } from '../../../styles/components/_console-feed.scss';
|
||||
import warnLightUrl from '../../../images/console-warn-light.svg';
|
||||
import warnDarkUrl from '../../../images/console-warn-dark.svg';
|
||||
import errorLightUrl from '../../../images/console-error-light.svg';
|
||||
import errorDarkUrl from '../../../images/console-error-dark.svg';
|
||||
import debugLightUrl from '../../../images/console-debug-light.svg';
|
||||
import debugDarkUrl from '../../../images/console-debug-dark.svg';
|
||||
import infoLightUrl from '../../../images/console-info-light.svg';
|
||||
import infoDarkUrl from '../../../images/console-info-dark.svg';
|
||||
|
||||
const upArrowUrl = require('../../../images/up-arrow.svg');
|
||||
const downArrowUrl = require('../../../images/down-arrow.svg');
|
||||
|
||||
class Console extends React.Component {
|
||||
componentDidUpdate() {
|
||||
componentDidUpdate(prevProps) {
|
||||
this.consoleMessages.scrollTop = this.consoleMessages.scrollHeight;
|
||||
if (this.props.theme !== prevProps.theme) {
|
||||
this.props.clearConsole();
|
||||
this.props.dispatchConsoleEvent(this.props.consoleEvents);
|
||||
}
|
||||
}
|
||||
|
||||
getConsoleFeedStyle(theme, times) {
|
||||
const style = {};
|
||||
const CONSOLE_FEED_LIGHT_ICONS = {
|
||||
LOG_WARN_ICON: `url(${warnLightUrl})`,
|
||||
LOG_ERROR_ICON: `url(${errorLightUrl})`,
|
||||
LOG_DEBUG_ICON: `url(${debugLightUrl})`,
|
||||
LOG_INFO_ICON: `url(${infoLightUrl})`
|
||||
};
|
||||
const CONSOLE_FEED_DARK_ICONS = {
|
||||
LOG_WARN_ICON: `url(${warnDarkUrl})`,
|
||||
LOG_ERROR_ICON: `url(${errorDarkUrl})`,
|
||||
LOG_DEBUG_ICON: `url(${debugDarkUrl})`,
|
||||
LOG_INFO_ICON: `url(${infoDarkUrl})`
|
||||
};
|
||||
if (times > 1) {
|
||||
Object.assign(style, CONSOLE_FEED_WITHOUT_ICONS);
|
||||
}
|
||||
switch (theme) {
|
||||
case 'light':
|
||||
return Object.assign(CONSOLE_FEED_LIGHT_STYLES, CONSOLE_FEED_LIGHT_ICONS, style);
|
||||
case 'dark':
|
||||
return Object.assign(CONSOLE_FEED_DARK_STYLES, CONSOLE_FEED_DARK_ICONS, style);
|
||||
case 'contrast':
|
||||
return Object.assign(CONSOLE_FEED_CONTRAST_STYLES, CONSOLE_FEED_DARK_ICONS, style);
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
formatData(args) {
|
||||
if (!Array.isArray(args)) {
|
||||
return Array.of(args);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -39,17 +89,25 @@ class Console extends React.Component {
|
|||
</div>
|
||||
<div ref={(element) => { this.consoleMessages = element; }} className="preview-console__messages">
|
||||
{this.props.consoleEvents.map((consoleEvent) => {
|
||||
const { arguments: args, method } = consoleEvent;
|
||||
const { arguments: args, method, times } = consoleEvent;
|
||||
const { theme } = this.props;
|
||||
Object.assign(consoleEvent, { data: this.formatData(args) });
|
||||
if (Object.keys(args).length === 0) {
|
||||
return (
|
||||
<div key={consoleEvent.id} className="preview-console__undefined">
|
||||
<div key={consoleEvent.id} className="preview-console__message preview-console__message--undefined">
|
||||
<span key={`${consoleEvent.id}-0`}>undefined</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div key={consoleEvent.id} className={`preview-console__${method}`}>
|
||||
{Object.keys(args).map(key => <span key={`${consoleEvent.id}-${key}`}>{args[key]}</span>)}
|
||||
<div key={consoleEvent.id} className={`preview-console__message preview-console__message--${method}`}>
|
||||
{ times > 1 &&
|
||||
<div className="preview-console__logged-times">{times}</div>
|
||||
}
|
||||
<ConsoleFeed
|
||||
styles={this.getConsoleFeedStyle(theme, times)}
|
||||
logs={Array.of(consoleEvent)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
@ -67,7 +125,9 @@ Console.propTypes = {
|
|||
isExpanded: PropTypes.bool.isRequired,
|
||||
collapseConsole: PropTypes.func.isRequired,
|
||||
expandConsole: PropTypes.func.isRequired,
|
||||
clearConsole: PropTypes.func.isRequired
|
||||
clearConsole: PropTypes.func.isRequired,
|
||||
dispatchConsoleEvent: PropTypes.func.isRequired,
|
||||
theme: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
Console.defaultProps = {
|
||||
|
|
|
@ -116,8 +116,8 @@ class Editor extends React.Component {
|
|||
this.props.setUnsavedChanges(true);
|
||||
this.props.updateFileContent(this.props.file.name, this._cm.getValue());
|
||||
if (this.props.autorefresh && this.props.isPlaying) {
|
||||
this.props.startRefreshSketch();
|
||||
this.props.clearConsole();
|
||||
this.props.startRefreshSketch();
|
||||
}
|
||||
}, 400));
|
||||
|
||||
|
|
|
@ -2,10 +2,9 @@ import PropTypes from 'prop-types';
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
// import escapeStringRegexp from 'escape-string-regexp';
|
||||
import { isEqual } from 'lodash';
|
||||
import srcDoc from 'srcdoc-polyfill';
|
||||
|
||||
import loopProtect from 'loop-protect';
|
||||
import loopProtectScript from 'loop-protect/dist/loop-protect.min';
|
||||
import { JSHINT } from 'jshint';
|
||||
import decomment from 'decomment';
|
||||
import { getBlobUrl } from '../actions/files';
|
||||
|
@ -18,38 +17,20 @@ import {
|
|||
EXTERNAL_LINK_REGEX,
|
||||
NOT_EXTERNAL_LINK_REGEX
|
||||
} from '../../../../server/utils/fileUtils';
|
||||
import { hijackConsole, hijackConsoleErrorsScript, startTag, getAllScriptOffsets }
|
||||
import { hijackConsoleErrorsScript, startTag, getAllScriptOffsets }
|
||||
from '../../../utils/consoleUtils';
|
||||
|
||||
|
||||
class PreviewFrame extends React.Component {
|
||||
componentDidMount() {
|
||||
if (this.props.isPlaying) {
|
||||
this.renderFrameContents();
|
||||
}
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleConsoleEvent = this.handleConsoleEvent.bind(this);
|
||||
}
|
||||
|
||||
window.addEventListener('message', (messageEvent) => {
|
||||
console.log(messageEvent);
|
||||
messageEvent.data.forEach((message) => {
|
||||
const args = message.arguments;
|
||||
Object.keys(args).forEach((key) => {
|
||||
if (args[key].includes('Exiting potential infinite loop')) {
|
||||
this.props.stopSketch();
|
||||
this.props.expandConsole();
|
||||
}
|
||||
});
|
||||
});
|
||||
this.props.dispatchConsoleEvent(messageEvent.data);
|
||||
});
|
||||
componentDidMount() {
|
||||
window.addEventListener('message', this.handleConsoleEvent);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
// if sketch starts or stops playing, want to rerender
|
||||
if (this.props.isPlaying !== prevProps.isPlaying) {
|
||||
this.renderSketch();
|
||||
return;
|
||||
}
|
||||
|
||||
// if the user explicitly clicks on the play button
|
||||
if (this.props.isPlaying && this.props.previewIsRefreshing) {
|
||||
this.renderSketch();
|
||||
|
@ -86,12 +67,43 @@ class PreviewFrame extends React.Component {
|
|||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('message', this.handleConsoleEvent);
|
||||
ReactDOM.unmountComponentAtNode(this.iframeElement.contentDocument.body);
|
||||
}
|
||||
|
||||
clearPreview() {
|
||||
const doc = this.iframeElement;
|
||||
doc.srcDoc = '';
|
||||
handleConsoleEvent(messageEvent) {
|
||||
if (Array.isArray(messageEvent.data)) {
|
||||
messageEvent.data.every((message, index, arr) => {
|
||||
const { arguments: args } = message;
|
||||
let hasInfiniteLoop = false;
|
||||
Object.keys(args).forEach((key) => {
|
||||
if (typeof args[key] === 'string' && args[key].includes('Exiting potential infinite loop')) {
|
||||
this.props.stopSketch();
|
||||
this.props.expandConsole();
|
||||
hasInfiniteLoop = true;
|
||||
}
|
||||
});
|
||||
if (hasInfiniteLoop) {
|
||||
return false;
|
||||
}
|
||||
if (index === arr.length - 1) {
|
||||
Object.assign(message, { times: 1 });
|
||||
return false;
|
||||
}
|
||||
const cur = Object.assign(message, { times: 1 });
|
||||
const nextIndex = index + 1;
|
||||
while (isEqual(cur.arguments, arr[nextIndex].arguments) && cur.method === arr[nextIndex].method) {
|
||||
cur.times += 1;
|
||||
arr.splice(nextIndex, 1);
|
||||
if (nextIndex === arr.length) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
this.props.dispatchConsoleEvent(messageEvent.data);
|
||||
}
|
||||
}
|
||||
|
||||
addLoopProtect(sketchDoc) {
|
||||
|
@ -121,9 +133,7 @@ class PreviewFrame extends React.Component {
|
|||
injectLocalFiles() {
|
||||
const htmlFile = this.props.htmlFile.content;
|
||||
let scriptOffs = [];
|
||||
|
||||
const resolvedFiles = this.resolveJSAndCSSLinks(this.props.files);
|
||||
|
||||
const parser = new DOMParser();
|
||||
const sketchDoc = parser.parseFromString(htmlFile, 'text/html');
|
||||
|
||||
|
@ -138,10 +148,6 @@ class PreviewFrame extends React.Component {
|
|||
this.resolveScripts(sketchDoc, resolvedFiles);
|
||||
this.resolveStyles(sketchDoc, resolvedFiles);
|
||||
|
||||
const scriptsToInject = [
|
||||
loopProtectScript,
|
||||
hijackConsole
|
||||
];
|
||||
const accessiblelib = sketchDoc.createElement('script');
|
||||
accessiblelib.setAttribute(
|
||||
'src',
|
||||
|
@ -156,7 +162,6 @@ class PreviewFrame extends React.Component {
|
|||
const textSection = sketchDoc.createElement('section');
|
||||
textSection.setAttribute('id', 'textOutput-content');
|
||||
sketchDoc.getElementById('accessible-outputs').appendChild(textSection);
|
||||
this.iframeElement.focus();
|
||||
}
|
||||
if (this.props.gridOutput) {
|
||||
sketchDoc.body.appendChild(accessibleOutputs);
|
||||
|
@ -164,7 +169,6 @@ class PreviewFrame extends React.Component {
|
|||
const gridSection = sketchDoc.createElement('section');
|
||||
gridSection.setAttribute('id', 'gridOutput-content');
|
||||
sketchDoc.getElementById('accessible-outputs').appendChild(gridSection);
|
||||
this.iframeElement.focus();
|
||||
}
|
||||
if (this.props.soundOutput) {
|
||||
sketchDoc.body.appendChild(accessibleOutputs);
|
||||
|
@ -174,11 +178,9 @@ class PreviewFrame extends React.Component {
|
|||
sketchDoc.getElementById('accessible-outputs').appendChild(soundSection);
|
||||
}
|
||||
|
||||
scriptsToInject.forEach((scriptToInject) => {
|
||||
const script = sketchDoc.createElement('script');
|
||||
script.text = scriptToInject;
|
||||
sketchDoc.head.appendChild(script);
|
||||
});
|
||||
const previewScripts = sketchDoc.createElement('script');
|
||||
previewScripts.src = '/previewScripts.js';
|
||||
sketchDoc.head.appendChild(previewScripts);
|
||||
|
||||
const sketchDocString = `<!DOCTYPE HTML>\n${sketchDoc.documentElement.outerHTML}`;
|
||||
scriptOffs = getAllScriptOffsets(sketchDocString);
|
||||
|
@ -320,15 +322,6 @@ class PreviewFrame extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
renderFrameContents() {
|
||||
const doc = this.iframeElement.contentDocument;
|
||||
if (doc.readyState === 'complete') {
|
||||
this.renderSketch();
|
||||
} else {
|
||||
setTimeout(this.renderFrameContents, 0);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<iframe
|
||||
|
|
|
@ -366,6 +366,8 @@ class IDEView extends React.Component {
|
|||
expandConsole={this.props.expandConsole}
|
||||
collapseConsole={this.props.collapseConsole}
|
||||
clearConsole={this.props.clearConsole}
|
||||
dispatchConsoleEvent={this.props.dispatchConsoleEvent}
|
||||
theme={this.props.preferences.theme}
|
||||
/>
|
||||
</SplitPane>
|
||||
<div className="preview-frame-holder">
|
||||
|
|
|
@ -5,6 +5,10 @@ $p5js-pink: #ed225d;
|
|||
$white: #fff;
|
||||
$black: #000;
|
||||
$yellow: #F5DC23;
|
||||
$orange: #ffa500;
|
||||
$red: #ff0000;
|
||||
$lightsteelblue: #B0C4DE;
|
||||
$dodgerblue: #1E90FF;
|
||||
$primary-text-color: #333;
|
||||
$icon-color: #8b8b8b;
|
||||
$icon-hover-color: #333;
|
||||
|
@ -37,8 +41,13 @@ $themes: (
|
|||
icon-toast-hover-color: $white,
|
||||
shadow-color: rgba(0, 0, 0, 0.16),
|
||||
console-background-color: #eee,
|
||||
console-color: $white,
|
||||
console-header-background-color: #d6d6d6,
|
||||
console-header-color: #b1b1b1,
|
||||
console-info-background-color: $lightsteelblue,
|
||||
console-warn-background-color: $orange,
|
||||
console-debug-background-color: $dodgerblue,
|
||||
console-error-background-color: $red,
|
||||
ide-border-color: #f4f4f4,
|
||||
editor-gutter-color: #f4f4f4,
|
||||
file-selected-color: #f4f4f4,
|
||||
|
@ -78,8 +87,13 @@ $themes: (
|
|||
icon-toast-hover-color: $white,
|
||||
shadow-color: rgba(0, 0, 0, 0.16),
|
||||
console-background-color: #4f4f4f,
|
||||
console-color: $black,
|
||||
console-header-background-color: #3f3f3f,
|
||||
console-header-color: #b5b5b5,
|
||||
console-info-background-color: $lightsteelblue,
|
||||
console-warn-background-color: $orange,
|
||||
console-debug-background-color: $dodgerblue,
|
||||
console-error-background-color: $red,
|
||||
ide-border-color: #949494,
|
||||
editor-gutter-color: #363636,
|
||||
file-selected-color: #404040,
|
||||
|
@ -118,8 +132,13 @@ $themes: (
|
|||
icon-toast-hover-color: $yellow,
|
||||
shadow-color: rgba(0, 0, 0, 0.16),
|
||||
console-background-color: #4f4f4f,
|
||||
console-color: $black,
|
||||
console-header-background-color: #3f3f3f,
|
||||
console-header-color: #b5b5b5,
|
||||
console-info-background-color: $lightsteelblue,
|
||||
console-warn-background-color: $orange,
|
||||
console-debug-background-color: $dodgerblue,
|
||||
console-error-background-color: $red,
|
||||
ide-border-color: #949494,
|
||||
editor-gutter-color: #454545,
|
||||
file-selected-color: #404040,
|
||||
|
@ -152,4 +171,4 @@ $form-button-active-color: $white;
|
|||
$form-navigation-options-color: #999999;
|
||||
|
||||
$about-play-background-color: rgba(255, 255, 255, 0.7);
|
||||
$about-button-border-color: rgba(151, 151, 151, 0.7);
|
||||
$about-button-border-color: rgba(151, 151, 151, 0.7);
|
47
client/styles/components/_console-feed.scss
Normal file
|
@ -0,0 +1,47 @@
|
|||
$CONSOLE_FEED_WITHOUT_ICONS: (
|
||||
LOG_WARN_ICON: 'none',
|
||||
LOG_ERROR_ICON: 'none',
|
||||
LOG_DEBUG_ICON: 'none',
|
||||
LOG_INFO_ICON: 'none'
|
||||
);
|
||||
|
||||
$CONSOLE_FEED_LIGHT_STYLES: (
|
||||
BASE_BACKGROUND_COLOR: '',
|
||||
LOG_ERROR_BACKGROUND: 'hsl(0, 100%, 97%)',
|
||||
LOG_ERROR_COLOR: '#D11518',
|
||||
LOG_ERROR_BORDER: 'hsl(0, 100%, 92%)',
|
||||
LOG_WARN_BACKGROUND: 'hsl(50, 100%, 95%)',
|
||||
LOG_WARN_COLOR: '#FAAF00',
|
||||
LOG_WARN_BORDER: 'hsl(50, 100%, 88%)',
|
||||
LOG_INFO_COLOR: '#7D7D7D',
|
||||
LOG_DEBUG_COLOR: '#007BBB',
|
||||
LOG_COLOR: 'rgb(128, 128, 128)'
|
||||
);
|
||||
|
||||
$CONSOLE_FEED_DARK_STYLES: (
|
||||
BASE_BACKGROUND_COLOR: '',
|
||||
BASE_COLOR: 'white',
|
||||
OBJECT_NAME_COLOR: 'white',
|
||||
OBJECT_VALUE_NULL_COLOR: 'hsl(230, 100%, 80%)',
|
||||
OBJECT_VALUE_UNDEFINED_COLOR: 'hsl(230, 100%, 80%)',
|
||||
OBJECT_VALUE_REGEXP_COLOR: 'hsl(230, 100%, 80%)',
|
||||
OBJECT_VALUE_STRING_COLOR: 'hsl(230, 100%, 80%)',
|
||||
OBJECT_VALUE_SYMBOL_COLOR: 'hsl(230, 100%, 80%)',
|
||||
OBJECT_VALUE_NUMBER_COLOR: 'hsl(230, 100%, 80%)',
|
||||
OBJECT_VALUE_BOOLEAN_COLOR: 'hsl(230, 100%, 80%)',
|
||||
OBJECT_VALUE_FUNCTION_KEYWORD_COLOR: 'hsl(230, 100%, 80%)',
|
||||
LOG_ERROR_BACKGROUND: 'hsl(0, 100%, 8%)',
|
||||
LOG_ERROR_COLOR: '#df3a3d',
|
||||
LOG_WARN_BACKGROUND: 'hsl(50, 100%, 10%)',
|
||||
LOG_WARN_COLOR: '#f5bc38',
|
||||
LOG_INFO_COLOR: '#a3a3a3',
|
||||
LOG_DEBUG_COLOR: '#0c99e2',
|
||||
TABLE_BORDER_COLOR: 'grey',
|
||||
TABLE_TH_BACKGROUND_COLOR: 'transparent',
|
||||
TABLE_TH_HOVER_COLOR: 'grey',
|
||||
TABLE_SORT_ICON_COLOR: 'grey',
|
||||
TABLE_DATA_BACKGROUND_IMAGE: 'grey',
|
||||
TABLE_DATA_BACKGROUND_SIZE: 'grey'
|
||||
);
|
||||
|
||||
$CONSOLE_FEED_CONTRAST_STYLES: $CONSOLE_FEED_DARK_STYLES;
|
|
@ -17,29 +17,12 @@
|
|||
text-align:left;
|
||||
}
|
||||
|
||||
// assign styles to different types of console messages
|
||||
.preview-console__log {
|
||||
@include themify(){
|
||||
color: getThemifyVariable('secondary-text-color');
|
||||
.preview-console__message {
|
||||
@include themify() {
|
||||
color: getThemifyVariable('console-color');
|
||||
}
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.preview-console__undefined {
|
||||
@include themify(){
|
||||
color: getThemifyVariable('inactive-text-color');
|
||||
}
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.preview-console__error {
|
||||
color: $console-error-color;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.preview-console__warn {
|
||||
color: $console-warn-color;
|
||||
flex: 1 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,4 +85,36 @@
|
|||
.preview-console--collapsed & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-console__logged-times {
|
||||
font-size: #{10 / $base-font-size}rem;
|
||||
font-weight: bold;
|
||||
margin: #{2 / $base-font-size}rem 0 0 #{8 / $base-font-size}rem;
|
||||
border-radius: 10px;
|
||||
padding: #{1 / $base-font-size}rem #{4 / $base-font-size}rem;
|
||||
z-index: 100;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
|
||||
.preview-console__message--info &, .preview-console__message--log & {
|
||||
@include themify() {
|
||||
background-color: getThemifyVariable('console-info-background-color');
|
||||
}
|
||||
}
|
||||
.preview-console__message--warn & {
|
||||
@include themify() {
|
||||
background-color: getThemifyVariable('console-warn-background-color');
|
||||
}
|
||||
}
|
||||
.preview-console__message--debug & {
|
||||
@include themify() {
|
||||
background-color: getThemifyVariable('console-debug-background-color');
|
||||
}
|
||||
}
|
||||
.preview-console__message--error & {
|
||||
@include themify() {
|
||||
background-color: getThemifyVariable('console-error-background-color');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
position: absolute;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,42 +2,6 @@ import {
|
|||
EXTERNAL_LINK_REGEX
|
||||
} from '../../server/utils/fileUtils';
|
||||
|
||||
export const hijackConsole = `var iframeWindow = window;
|
||||
var originalConsole = iframeWindow.console;
|
||||
iframeWindow.console = {};
|
||||
|
||||
var methods = [
|
||||
'debug', 'clear', 'error', 'info', 'log', 'warn'
|
||||
];
|
||||
|
||||
var consoleBuffer = [];
|
||||
var LOGWAIT = 500;
|
||||
|
||||
methods.forEach( function(method) {
|
||||
iframeWindow.console[method] = function() {
|
||||
originalConsole[method].apply(originalConsole, arguments);
|
||||
|
||||
var args = Array.from(arguments);
|
||||
args = args.map(function(i) {
|
||||
// catch objects
|
||||
return (typeof i === 'string') ? i : JSON.stringify(i);
|
||||
});
|
||||
|
||||
consoleBuffer.push({
|
||||
method: method,
|
||||
arguments: args,
|
||||
source: 'sketch'
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
setInterval(function() {
|
||||
if (consoleBuffer.length > 0) {
|
||||
window.parent.postMessage(consoleBuffer, '*');
|
||||
consoleBuffer.length = 0;
|
||||
}
|
||||
}, LOGWAIT);`;
|
||||
|
||||
export const hijackConsoleErrorsScript = (offs) => {
|
||||
const s = `
|
||||
function getScriptOff(line) {
|
||||
|
|
21
client/utils/previewEntry.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import loopProtect from 'loop-protect';
|
||||
import Hook from 'console-feed/lib/Hook/index';
|
||||
|
||||
window.loopProtect = loopProtect;
|
||||
|
||||
const consoleBuffer = [];
|
||||
const LOGWAIT = 500;
|
||||
Hook(window.console, (log) => {
|
||||
const { method, data: args } = log[0];
|
||||
consoleBuffer.push({
|
||||
method,
|
||||
arguments: args,
|
||||
source: 'sketch'
|
||||
});
|
||||
});
|
||||
setInterval(() => {
|
||||
if (consoleBuffer.length > 0) {
|
||||
window.parent.postMessage(consoleBuffer, '*');
|
||||
consoleBuffer.length = 0;
|
||||
}
|
||||
}, LOGWAIT);
|
|
@ -73,6 +73,7 @@
|
|||
"clipboard": "^1.7.1",
|
||||
"codemirror": "^5.38.0",
|
||||
"connect-mongo": "^1.2.0",
|
||||
"console-feed": "^2.8.1",
|
||||
"cookie-parser": "^1.4.1",
|
||||
"cors": "^2.8.1",
|
||||
"cross-env": "^5.1.3",
|
||||
|
@ -106,9 +107,8 @@
|
|||
"project-name-generator": "^2.1.3",
|
||||
"prop-types": "^15.6.0",
|
||||
"q": "^1.4.1",
|
||||
"raw-loader": "^0.5.1",
|
||||
"react": "^16.2.0",
|
||||
"react-dom": "^16.2.0",
|
||||
"react": "^16.4.0",
|
||||
"react-dom": "^16.4.0",
|
||||
"react-helmet": "^5.1.3",
|
||||
"react-hot-loader": "^4.1.2",
|
||||
"react-inlinesvg": "^0.7.5",
|
||||
|
@ -126,6 +126,9 @@
|
|||
"request-promise": "^4.1.1",
|
||||
"s3": "^4.4.0",
|
||||
"s3-policy": "^0.2.0",
|
||||
"sass-extract": "^2.1.0",
|
||||
"sass-extract-js": "^0.4.0",
|
||||
"sass-extract-loader": "^1.1.0",
|
||||
"shortid": "^2.2.6",
|
||||
"slugify": "^1.2.9",
|
||||
"srcdoc-polyfill": "^0.2.0",
|
||||
|
|
|
@ -39,7 +39,7 @@ const corsOriginsWhitelist = [
|
|||
// Run Webpack dev server in development mode
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const compiler = webpack(config);
|
||||
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }));
|
||||
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config[0].output.publicPath }));
|
||||
app.use(webpackHotMiddleware(compiler));
|
||||
|
||||
corsOriginsWhitelist.push(/localhost/);
|
||||
|
|
|
@ -18,7 +18,7 @@ module.exports = {
|
|||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.scss$/,
|
||||
test: /main\.scss$/,
|
||||
exclude: /node_modules/,
|
||||
loader: ExtractTextPlugin.extract({
|
||||
fallback: 'style-loader',
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
require('dotenv').config();
|
||||
|
||||
module.exports = {
|
||||
module.exports = [{
|
||||
devtool: 'cheap-module-eval-source-map',
|
||||
entry: {
|
||||
app: [
|
||||
|
@ -70,7 +71,7 @@ module.exports = {
|
|||
// }
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
test: /main\.scss$/,
|
||||
loaders: ['style-loader', 'css-loader', 'sass-loader']
|
||||
},
|
||||
{
|
||||
|
@ -82,9 +83,52 @@ module.exports = {
|
|||
loader: 'file-loader'
|
||||
},
|
||||
{
|
||||
test: /.*loop-protect.min.js$/,
|
||||
loader: 'raw-loader'
|
||||
test: /_console-feed.scss/,
|
||||
loader: 'sass-extract-loader',
|
||||
options: {
|
||||
plugins: [{ plugin: 'sass-extract-js', options: { camelCase: false } }]
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
{
|
||||
entry: path.resolve(__dirname, 'client/utils/previewEntry.js'),
|
||||
target: 'web',
|
||||
output: {
|
||||
path: `${__dirname}`,
|
||||
filename: 'previewScripts.js',
|
||||
publicPath: '/'
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['*', '.js', '.jsx'],
|
||||
modules: [
|
||||
'client',
|
||||
'node_modules',
|
||||
],
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader',
|
||||
query: {
|
||||
presets: [
|
||||
'react',
|
||||
'env',
|
||||
'stage-0',
|
||||
],
|
||||
plugins: [
|
||||
[
|
||||
'babel-plugin-webpack-loaders', {
|
||||
'config': './webpack.config.babel.js',
|
||||
"verbose": false
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
}]
|
||||
|
|
|
@ -8,7 +8,7 @@ const postcssReporter = require('postcss-reporter');
|
|||
const cssnano = require('cssnano');
|
||||
require('dotenv').config();
|
||||
|
||||
module.exports = {
|
||||
module.exports = [{
|
||||
devtool: 'source-map',
|
||||
|
||||
entry: {
|
||||
|
@ -53,7 +53,7 @@ module.exports = {
|
|||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.scss$/,
|
||||
test: /main\.scss$/,
|
||||
exclude: /node_modules/,
|
||||
loader: ExtractTextPlugin.extract({
|
||||
fallback: 'style-loader',
|
||||
|
@ -74,8 +74,11 @@ module.exports = {
|
|||
loader: 'file-loader'
|
||||
},
|
||||
{
|
||||
test: /.*loop-protect.min.js$/,
|
||||
loader: 'raw-loader'
|
||||
test: /_console-feed.scss/,
|
||||
loader: 'sass-extract-loader',
|
||||
options: {
|
||||
plugins: [{ plugin: 'sass-extract-js', options: { camelCase: false } }]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -126,4 +129,40 @@ module.exports = {
|
|||
})
|
||||
],
|
||||
|
||||
};
|
||||
},
|
||||
{
|
||||
entry: {
|
||||
app: [
|
||||
'./client/utils/previewEntry.js'
|
||||
]
|
||||
},
|
||||
target: 'web',
|
||||
output: {
|
||||
path: `${__dirname}/dist/static`,
|
||||
filename: 'previewScripts.js',
|
||||
publicPath: '/'
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['*', '.js', '.jsx'],
|
||||
modules: [
|
||||
'client',
|
||||
'node_modules',
|
||||
],
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
warnings: false
|
||||
}
|
||||
})
|
||||
]
|
||||
}];
|