Skip to content

Commit 921f136

Browse files
committed
Move window message handling to component
1 parent 7efc078 commit 921f136

File tree

3 files changed

+103
-81
lines changed

3 files changed

+103
-81
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import React, { useEffect, useCallback } from 'react';
2+
import { useDispatch } from 'react-redux';
3+
import { Decode, Encode, Hook, Unhook } from 'console-feed';
4+
import { isEqual } from 'lodash';
5+
import { dispatchConsoleEvent } from '../actions/console';
6+
import { stopSketch, expandConsole } from '../actions/console';
7+
import handleConsoleExpressions from '../../../utils/evaluateConsole';
8+
9+
function useMessageEvent(callback) {
10+
useEffect(() => {
11+
window.addEventListener('message', callback);
12+
return () => window.removeEventListener('message', callback);
13+
}, [callback]);
14+
}
15+
16+
function MessageHandler() {
17+
const dispatch = useDispatch();
18+
19+
const handleMessageEvent = useCallback((messageEvent) => {
20+
if (messageEvent.origin !== window.origin) return;
21+
if (Array.isArray(messageEvent.data)) {
22+
const decodedMessages = messageEvent.data.map(message => Object.assign(
23+
Decode(message.log),
24+
{ source: message.source }
25+
));
26+
decodedMessages.every((message, index, arr) => {
27+
const { data: args, source } = message;
28+
if (source === 'console') {
29+
let consoleInfo = '';
30+
const consoleBuffer = [];
31+
const LOGWAIT = 100;
32+
Hook(window.console, (log) => {
33+
consoleBuffer.push({
34+
log,
35+
source: 'sketch'
36+
});
37+
});
38+
setInterval(() => {
39+
if (consoleBuffer.length > 0) {
40+
window.postMessage(consoleBuffer, '*');
41+
consoleBuffer.length = 0;
42+
}
43+
}, LOGWAIT);
44+
consoleInfo = handleConsoleExpressions(args);
45+
Unhook(window.console);
46+
if (!consoleInfo) {
47+
return false;
48+
}
49+
window.postMessage([{
50+
log: Encode({ method: 'result', data: Encode(consoleInfo) }),
51+
source: 'sketch'
52+
}], '*');
53+
}
54+
let hasInfiniteLoop = false;
55+
Object.keys(args).forEach((key) => {
56+
if (typeof args[key] === 'string' && args[key].includes('Exiting potential infinite loop')) {
57+
dispatch(stopSketch());
58+
dispatch(expandConsole());
59+
hasInfiniteLoop = true;
60+
}
61+
});
62+
if (hasInfiniteLoop) {
63+
return false;
64+
}
65+
if (index === arr.length - 1) {
66+
Object.assign(message, { times: 1 });
67+
return false;
68+
}
69+
const cur = Object.assign(message, { times: 1 });
70+
const nextIndex = index + 1;
71+
while (isEqual(cur.data, arr[nextIndex].data) && cur.method === arr[nextIndex].method) {
72+
cur.times += 1;
73+
arr.splice(nextIndex, 1);
74+
if (nextIndex === arr.length) {
75+
return false;
76+
}
77+
}
78+
return true;
79+
});
80+
81+
dispatch(dispatchConsoleEvent(decodedMessages));
82+
}
83+
});
84+
85+
useMessageEvent(handleMessageEvent);
86+
return null;
87+
}
88+
89+
export default MessageHandler;

client/modules/IDE/components/PreviewFrame.jsx

Lines changed: 6 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ import PropTypes from 'prop-types';
22
import React from 'react';
33
import ReactDOM from 'react-dom';
44
// import escapeStringRegexp from 'escape-string-regexp';
5-
import { isEqual } from 'lodash';
65
import srcDoc from 'srcdoc-polyfill';
76
import loopProtect from 'loop-protect';
87
import { JSHINT } from 'jshint';
98
import decomment from 'decomment';
10-
import { Hook, Unhook, Encode, Decode } from 'console-feed';
119
import classNames from 'classnames';
1210
import { getBlobUrl } from '../actions/files';
1311
import { resolvePathToFile } from '../../../../server/utils/filePath';
@@ -21,7 +19,6 @@ import {
2119
} from '../../../../server/utils/fileUtils';
2220
import { hijackConsoleErrorsScript, startTag, getAllScriptOffsets }
2321
from '../../../utils/consoleUtils';
24-
import handleConsoleExpressions from '../../../utils/evaluateConsole';
2522

2623

2724
const shouldRenderSketch = (props, prevProps = undefined) => {
@@ -43,12 +40,11 @@ const shouldRenderSketch = (props, prevProps = undefined) => {
4340
class PreviewFrame extends React.Component {
4441
constructor(props) {
4542
super(props);
46-
this.handleConsoleEvent = this.handleConsoleEvent.bind(this);
43+
44+
this.iframe = React.createRef();
4745
}
4846

4947
componentDidMount() {
50-
window.addEventListener('message', this.handleConsoleEvent);
51-
5248
const props = {
5349
...this.props,
5450
previewIsRefreshing: this.props.previewIsRefreshing,
@@ -64,77 +60,10 @@ class PreviewFrame extends React.Component {
6460
}
6561

6662
componentWillUnmount() {
67-
window.removeEventListener('message', this.handleConsoleEvent);
68-
const iframeBody = this.iframeElement.contentDocument.body;
63+
const iframeBody = this.iframe.current.contentDocument.body;
6964
if (iframeBody) { ReactDOM.unmountComponentAtNode(iframeBody); }
7065
}
7166

72-
handleConsoleEvent(messageEvent) {
73-
if (messageEvent.origin !== window.origin) return;
74-
if (Array.isArray(messageEvent.data)) {
75-
const decodedMessages = messageEvent.data.map(message => Object.assign(
76-
Decode(message.log),
77-
{ source: message.source }
78-
));
79-
decodedMessages.every((message, index, arr) => {
80-
const { data: args, source } = message;
81-
if (source === 'console') {
82-
let consoleInfo = '';
83-
const consoleBuffer = [];
84-
const LOGWAIT = 100;
85-
Hook(window.console, (log) => {
86-
consoleBuffer.push({
87-
log,
88-
source: 'sketch'
89-
});
90-
});
91-
setInterval(() => {
92-
if (consoleBuffer.length > 0) {
93-
window.postMessage(consoleBuffer, '*');
94-
consoleBuffer.length = 0;
95-
}
96-
}, LOGWAIT);
97-
consoleInfo = handleConsoleExpressions(args);
98-
Unhook(window.console);
99-
if (!consoleInfo) {
100-
return false;
101-
}
102-
window.postMessage([{
103-
log: Encode({ method: 'result', data: Encode(consoleInfo) }),
104-
source: 'sketch'
105-
}], '*');
106-
}
107-
let hasInfiniteLoop = false;
108-
Object.keys(args).forEach((key) => {
109-
if (typeof args[key] === 'string' && args[key].includes('Exiting potential infinite loop')) {
110-
this.props.stopSketch();
111-
this.props.expandConsole();
112-
hasInfiniteLoop = true;
113-
}
114-
});
115-
if (hasInfiniteLoop) {
116-
return false;
117-
}
118-
if (index === arr.length - 1) {
119-
Object.assign(message, { times: 1 });
120-
return false;
121-
}
122-
const cur = Object.assign(message, { times: 1 });
123-
const nextIndex = index + 1;
124-
while (isEqual(cur.data, arr[nextIndex].data) && cur.method === arr[nextIndex].method) {
125-
cur.times += 1;
126-
arr.splice(nextIndex, 1);
127-
if (nextIndex === arr.length) {
128-
return false;
129-
}
130-
}
131-
return true;
132-
});
133-
134-
this.props.dispatchConsoleEvent(decodedMessages);
135-
}
136-
}
137-
13867
addLoopProtect(sketchDoc) {
13968
const scriptsInHTML = sketchDoc.getElementsByTagName('script');
14069
const scriptsInHTMLArray = Array.prototype.slice.call(scriptsInHTML);
@@ -353,7 +282,7 @@ class PreviewFrame extends React.Component {
353282
}
354283

355284
renderSketch() {
356-
const doc = this.iframeElement;
285+
const doc = this.iframe.current;
357286
const localFiles = this.injectLocalFiles();
358287
if (this.props.isPlaying) {
359288
this.props.clearConsole();
@@ -382,7 +311,7 @@ class PreviewFrame extends React.Component {
382311
role="main"
383312
frameBorder="0"
384313
title="sketch preview"
385-
ref={(element) => { this.iframeElement = element; }}
314+
ref={this.iframe}
386315
sandbox={sandboxAttributes}
387316
/>
388317
);
@@ -404,17 +333,14 @@ PreviewFrame.propTypes = {
404333
url: PropTypes.string,
405334
id: PropTypes.string.isRequired
406335
})).isRequired,
407-
dispatchConsoleEvent: PropTypes.func.isRequired,
408336
endSketchRefresh: PropTypes.func.isRequired,
409337
previewIsRefreshing: PropTypes.bool.isRequired,
410338
fullView: PropTypes.bool,
411339
setBlobUrl: PropTypes.func.isRequired,
412-
stopSketch: PropTypes.func.isRequired,
413-
expandConsole: PropTypes.func.isRequired,
414340
clearConsole: PropTypes.func.isRequired,
415341
cmController: PropTypes.shape({
416342
getContent: PropTypes.func
417-
}),
343+
})
418344
};
419345

420346
PreviewFrame.defaultProps = {

client/modules/IDE/pages/IDEView.jsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import About from '../components/About';
3434
import AddToCollectionList from '../components/AddToCollectionList';
3535
import Feedback from '../components/Feedback';
3636
import { CollectionSearchbar } from '../components/Searchbar';
37+
import MessageHandler from '../components/MessageHandler';
3738

3839

3940
function getTitle(props) {
@@ -83,6 +84,8 @@ class IDEView extends React.Component {
8384
consoleSize: props.ide.consoleIsExpanded ? 150 : 29,
8485
sidebarSize: props.ide.sidebarIsExpanded ? 160 : 20,
8586
};
87+
88+
this.previewFrame = React.createRef();
8689
}
8790

8891
componentDidMount() {
@@ -259,6 +262,7 @@ class IDEView extends React.Component {
259262
<Helmet>
260263
<title>{getTitle(this.props)}</title>
261264
</Helmet>
265+
<MessageHandler />
262266
{this.props.toast.isVisible && <Toast />}
263267
<Nav
264268
warnIfUnsavedChanges={this.handleUnsavedChanges}
@@ -383,7 +387,9 @@ class IDEView extends React.Component {
383387
this.cmController = ctl;
384388
}}
385389
/>
386-
<Console />
390+
<Console
391+
previewFrame={this.previewFrame.current}
392+
/>
387393
</SplitPane>
388394
<section className="preview-frame-holder">
389395
<header className="preview-frame__header">
@@ -428,6 +434,7 @@ class IDEView extends React.Component {
428434
clearConsole={this.props.clearConsole}
429435
cmController={this.cmController}
430436
language={this.props.preferences.language}
437+
ref={this.previewFrame}
431438
/>
432439
</div>
433440
</section>

0 commit comments

Comments
 (0)