p5.js-web-editor/client/modules/IDE/components/PreviewFrame.js

106 lines
3.1 KiB
JavaScript
Raw Normal View History

2016-06-27 21:47:48 +02:00
import React, { PropTypes } from 'react';
2016-06-24 00:29:55 +02:00
import ReactDOM from 'react-dom';
2016-07-11 21:22:29 +02:00
import escapeStringRegexp from 'escape-string-regexp';
import srcDoc from 'srcdoc-polyfill';
2016-06-24 00:29:55 +02:00
class PreviewFrame extends React.Component {
componentDidMount() {
if (this.props.isPlaying) {
this.renderFrameContents();
}
}
2016-06-27 21:47:48 +02:00
componentDidUpdate(prevProps) {
if (this.props.isPlaying !== prevProps.isPlaying) {
2016-07-11 21:22:29 +02:00
this.renderSketch();
2016-06-27 21:47:48 +02:00
}
if (this.props.isPlaying && this.props.content !== prevProps.content) {
this.renderSketch();
}
}
componentWillUnmount() {
ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this).contentDocument.body);
}
2016-06-24 00:29:55 +02:00
clearPreview() {
2016-07-11 21:22:29 +02:00
const doc = ReactDOM.findDOMNode(this);
doc.srcDoc = '';
}
injectLocalFiles() {
let htmlFile = this.props.htmlFile.content;
this.props.jsFiles.forEach(jsFile => {
const fileName = escapeStringRegexp(jsFile.name);
const fileRegex = new RegExp(`<script.*?src=('|")((\.\/)|\/)?${fileName}('|").*?>([\s\S]*?)<\/script>`, 'gmi');
htmlFile = htmlFile.replace(fileRegex, `<script>\n${jsFile.content}\n</script>`);
});
2016-07-12 03:54:08 +02:00
this.props.cssFiles.forEach(cssFile => {
const fileName = escapeStringRegexp(cssFile.name);
const fileRegex = new RegExp(`<link.*?href=('|")((\.\/)|\/)?${fileName}('|").*?>`, 'gmi');
htmlFile = htmlFile.replace(fileRegex, `<style>\n${cssFile.content}\n</style>`);
});
// const htmlHead = htmlFile.match(/(?:<head.*?>)([\s\S]*?)(?:<\/head>)/gmi);
// const headRegex = new RegExp('head', 'i');
// let htmlHeadContents = htmlHead[0].split(headRegex)[1];
// htmlHeadContents = htmlHeadContents.slice(1, htmlHeadContents.length - 2);
// htmlHeadContents += '<link rel="stylesheet" type="text/css" href="/preview-styles.css" />\n';
// htmlFile = htmlFile.replace(/(?:<head.*?>)([\s\S]*?)(?:<\/head>)/gmi, `<head>\n${htmlHeadContents}\n</head>`);
2016-07-11 21:22:29 +02:00
return htmlFile;
2016-06-24 00:29:55 +02:00
}
renderSketch() {
2016-07-11 21:22:29 +02:00
const doc = ReactDOM.findDOMNode(this);
if (this.props.isPlaying) {
// TODO add polyfill for this
// doc.srcdoc = this.injectLocalFiles();
srcDoc.set(doc, this.injectLocalFiles());
2016-07-11 21:22:29 +02:00
} else {
// doc.srcdoc = '';
srcDoc.set(doc, '');
doc.contentWindow.document.open();
doc.contentWindow.document.write('');
doc.contentWindow.document.close();
2016-07-11 21:22:29 +02:00
}
2016-06-24 00:29:55 +02:00
}
2016-06-27 21:47:48 +02:00
renderFrameContents() {
const doc = ReactDOM.findDOMNode(this).contentDocument;
if (doc.readyState === 'complete') {
2016-06-27 23:22:54 +02:00
this.renderSketch();
2016-06-27 21:47:48 +02:00
} else {
setTimeout(this.renderFrameContents, 0);
2016-06-24 00:29:55 +02:00
}
}
render() {
2016-06-27 21:47:48 +02:00
return (
<iframe
className="preview-frame"
frameBorder="0"
title="sketch output"
2016-07-11 23:32:13 +02:00
sandbox="allow-scripts allow-pointer-lock allow-same-origin allow-popups allow-modals allow-forms"
2016-06-27 21:47:48 +02:00
></iframe>
);
2016-06-24 00:29:55 +02:00
}
}
2016-06-27 21:47:48 +02:00
PreviewFrame.propTypes = {
isPlaying: PropTypes.bool.isRequired,
head: PropTypes.object.isRequired,
2016-07-11 21:22:29 +02:00
content: PropTypes.string.isRequired,
htmlFile: PropTypes.shape({
content: PropTypes.string.isRequired
}),
2016-07-12 03:54:08 +02:00
jsFiles: PropTypes.array.isRequired,
cssFiles: PropTypes.array.isRequired
2016-06-27 21:47:48 +02:00
};
2016-06-24 00:29:55 +02:00
export default PreviewFrame;