mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2025-12-24 22:52:40 +00:00
* Include two versions of Marked.js
* Include two versions of Marked.js
* Working two different render pipelines
Adds stylesheet "styleLegacy.less"
Adds markdownHandler "markdownLegacy.js"
The BrewRenderer will switch between these and the new pipeline dependent on the "version" prop passed in.
* Mustache-style div blocks
* Legacy snippets & columnbreak
* Codemirror styling for Div Blocks
* Lint
* Codemirror highlights for inline Divs as well
These will turn red `{{class Content}}`
Multi-line divs will turn purple
```
{{class,class2
content
}}
```
No real need for these to be different colors. Just for testing.
* More lint
* Update dependencies.
* Adding Button to switch render pipelines
* Update Marked.js
* Popup alert to refresh page when renderer changed
* Don't compress files in Development (very slow)
* Block DIV or inline Span depending on {{ placement
* \column emits a Div instead of Span
* Allow share page to use new renderer
* {{ divs no longer need empty lines. Spans work in lists.
* Typo
* Typo
* Enforce \page must be at start of line. Code cleanup.
* Inject newlines after/before {{/}} to avoid needing blank lines
* Fixes issues with tables.
* Remove console.log
* Fix spacing issue for Spans
* Move things from Brewrenderer to Markdown
Try to keep all custom text fiddling in one spot.
* Rename variables
* Update Font-Awesome to v5.15. Fix style issues on popups.
* Update {{ Divs/Spans, Fix nested hilighting
* Fixed Spans/divs with no tags or just commas
* Use blacklist for {{ to allow more characters
* Update package-lock.json
* Update all icons to Font-awesome 5
* V3 hidden behind config variable
Add "globalThis.enable_v3 = true" in the console to enable.
* lint
* Give user styles higher priority to still allow overrides
* Apply style priority to *all* user styles
* Change .legacy .v3 to .phb, .phb3
196 lines
5.7 KiB
JavaScript
196 lines
5.7 KiB
JavaScript
require('./brewRenderer.less');
|
|
const React = require('react');
|
|
const createClass = require('create-react-class');
|
|
const _ = require('lodash');
|
|
const cx = require('classnames');
|
|
|
|
const MarkdownLegacy = require('naturalcrit/markdownLegacy.js');
|
|
const Markdown = require('naturalcrit/markdown.js');
|
|
const ErrorBar = require('./errorBar/errorBar.jsx');
|
|
|
|
//TODO: move to the brew renderer
|
|
const RenderWarnings = require('homebrewery/renderWarnings/renderWarnings.jsx');
|
|
const NotificationPopup = require('./notificationPopup/notificationPopup.jsx');
|
|
const Frame = require('react-frame-component').default;
|
|
|
|
const PAGE_HEIGHT = 1056;
|
|
const PPR_THRESHOLD = 50;
|
|
|
|
const BrewRenderer = createClass({
|
|
getDefaultProps : function() {
|
|
return {
|
|
text : '',
|
|
renderer : '',
|
|
errors : []
|
|
};
|
|
},
|
|
getInitialState : function() {
|
|
const pages = this.props.text.split(/^\\page/gm);
|
|
let renderer = 'legacy';
|
|
if(this.props.renderer)
|
|
renderer = this.props.renderer;
|
|
|
|
return {
|
|
viewablePageNumber : 0,
|
|
height : 0,
|
|
isMounted : false,
|
|
|
|
pages : pages,
|
|
usePPR : pages.length >= PPR_THRESHOLD,
|
|
visibility : 'hidden',
|
|
renderer : renderer,
|
|
initialContent : `<!DOCTYPE html><html><head>
|
|
<link href="//use.fontawesome.com/releases/v5.15.1/css/all.css" rel="stylesheet" />
|
|
<link href="//fonts.googleapis.com/css?family=Open+Sans:400,300,600,700" rel="stylesheet" type="text/css" />
|
|
<link href='/homebrew/bundle.css' rel='stylesheet' />
|
|
<base target=_blank>
|
|
</head><body style='overflow: hidden'><div></div></body></html>`
|
|
};
|
|
},
|
|
height : 0,
|
|
lastRender : <div></div>,
|
|
|
|
componentWillUnmount : function() {
|
|
window.removeEventListener('resize', this.updateSize);
|
|
},
|
|
|
|
componentWillReceiveProps : function(nextProps) {
|
|
const pages = nextProps.text.split(/^\\page/gm);
|
|
this.setState({
|
|
pages : pages,
|
|
usePPR : pages.length >= PPR_THRESHOLD
|
|
});
|
|
},
|
|
|
|
updateSize : function() {
|
|
this.setState({
|
|
height : this.refs.main.parentNode.clientHeight,
|
|
});
|
|
},
|
|
|
|
handleScroll : function(e){
|
|
const target = e.target;
|
|
this.setState((prevState)=>({
|
|
viewablePageNumber : Math.floor(target.scrollTop / target.scrollHeight * prevState.pages.length)
|
|
}));
|
|
},
|
|
|
|
shouldRender : function(pageText, index){
|
|
if(!this.state.isMounted) return false;
|
|
|
|
const viewIndex = this.state.viewablePageNumber;
|
|
if(index == viewIndex - 3) return true;
|
|
if(index == viewIndex - 2) return true;
|
|
if(index == viewIndex - 1) return true;
|
|
if(index == viewIndex) return true;
|
|
if(index == viewIndex + 1) return true;
|
|
if(index == viewIndex + 2) return true;
|
|
if(index == viewIndex + 3) return true;
|
|
|
|
//Check for style tages
|
|
if(pageText.indexOf('<style>') !== -1) return true;
|
|
|
|
return false;
|
|
},
|
|
|
|
renderPageInfo : function(){
|
|
return <div className='pageInfo' ref='main'>
|
|
{this.state.viewablePageNumber + 1} / {this.state.pages.length}
|
|
</div>;
|
|
},
|
|
|
|
renderPPRmsg : function(){
|
|
if(!this.state.usePPR) return;
|
|
|
|
return <div className='ppr_msg'>
|
|
Partial Page Renderer enabled, because your brew is so large. May effect rendering.
|
|
</div>;
|
|
},
|
|
|
|
renderDummyPage : function(index){
|
|
return <div className='phb' id={`p${index + 1}`} key={index}>
|
|
<i className='fas fa-spinner fa-spin' />
|
|
</div>;
|
|
},
|
|
|
|
renderPage : function(pageText, index){
|
|
if(this.state.renderer == 'legacy')
|
|
return <div className='phb' id={`p${index + 1}`} dangerouslySetInnerHTML={{ __html: MarkdownLegacy.render(pageText) }} key={index} />;
|
|
else
|
|
return <div className='phb3' id={`p${index + 1}`} dangerouslySetInnerHTML={{ __html: Markdown.render(pageText) }} key={index} />;
|
|
},
|
|
|
|
renderPages : function(){
|
|
if(this.state.usePPR){
|
|
return _.map(this.state.pages, (page, index)=>{
|
|
if(this.shouldRender(page, index) && typeof window !== 'undefined'){
|
|
return this.renderPage(page, index);
|
|
} else {
|
|
return this.renderDummyPage(index);
|
|
}
|
|
});
|
|
}
|
|
if(this.props.errors && this.props.errors.length) return this.lastRender;
|
|
this.lastRender = _.map(this.state.pages, (page, index)=>{
|
|
if(typeof window !== 'undefined') {
|
|
return this.renderPage(page, index);
|
|
} else {
|
|
return this.renderDummyPage(index);
|
|
}
|
|
});
|
|
return this.lastRender;
|
|
},
|
|
|
|
frameDidMount : function(){ //This triggers when iFrame finishes internal "componentDidMount"
|
|
setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame
|
|
this.updateSize();
|
|
window.addEventListener('resize', this.updateSize);
|
|
this.renderPages(); //Make sure page is renderable before showing
|
|
this.setState({
|
|
isMounted : true,
|
|
visibility : 'visible'
|
|
});
|
|
}, 100);
|
|
},
|
|
|
|
render : function(){
|
|
//render in iFrame so broken code doesn't crash the site.
|
|
//Also render dummy page while iframe is mounting.
|
|
|
|
return (
|
|
<React.Fragment>
|
|
{!this.state.isMounted
|
|
? <div className='brewRenderer' onScroll={this.handleScroll}>
|
|
<div className='pages' ref='pages'>
|
|
{this.renderDummyPage(1)}
|
|
</div>
|
|
</div>
|
|
: null}
|
|
|
|
<Frame initialContent={this.state.initialContent} style={{ width: '100%', height: '100%', visibility: this.state.visibility }} contentDidMount={this.frameDidMount}>
|
|
<div className={cx('brewRenderer', this.state.renderer)}
|
|
onScroll={this.handleScroll}
|
|
style={{ height: this.state.height }}>
|
|
|
|
<ErrorBar errors={this.props.errors} />
|
|
<div className='popups'>
|
|
<RenderWarnings />
|
|
<NotificationPopup />
|
|
</div>
|
|
|
|
<div className='pages' ref='pages'>
|
|
{this.state.isMounted
|
|
? this.renderPages()
|
|
: null}
|
|
</div>
|
|
</div>
|
|
</Frame>
|
|
{this.renderPageInfo()}
|
|
{this.renderPPRmsg()}
|
|
</React.Fragment>
|
|
);
|
|
}
|
|
});
|
|
|
|
module.exports = BrewRenderer;
|