RevisionRenderer.jsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { createSubscribedElement } from '../UnstatedUtils';
  4. import AppContainer from '../../services/AppContainer';
  5. import PageContainer from '../../services/PageContainer';
  6. import GrowiRenderer from '../../util/GrowiRenderer';
  7. import RevisionBody from './RevisionBody';
  8. class RevisionRenderer extends React.Component {
  9. constructor(props) {
  10. super(props);
  11. this.state = {
  12. html: '',
  13. };
  14. this.renderHtml = this.renderHtml.bind(this);
  15. this.getHighlightedBody = this.getHighlightedBody.bind(this);
  16. }
  17. componentWillMount() {
  18. this.renderHtml(this.props.markdown, this.props.highlightKeywords);
  19. }
  20. componentWillReceiveProps(nextProps) {
  21. this.renderHtml(nextProps.markdown, this.props.highlightKeywords);
  22. }
  23. /**
  24. * transplanted from legacy code -- Yuki Takei
  25. * @param {string} body html strings
  26. * @param {string} keywords
  27. */
  28. getHighlightedBody(body, keywords) {
  29. let returnBody = body;
  30. keywords.replace(/"/g, '').split(' ').forEach((keyword) => {
  31. if (keyword === '') {
  32. return;
  33. }
  34. const k = keyword
  35. .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
  36. .replace(/(^"|"$)/g, ''); // for phrase (quoted) keyword
  37. const keywordExp = new RegExp(`(${k}(?!(.*?")))`, 'ig');
  38. returnBody = returnBody.replace(keywordExp, '<em class="highlighted">$&</em>');
  39. });
  40. return returnBody;
  41. }
  42. renderHtml(markdown) {
  43. const { pageContainer } = this.props;
  44. const context = {
  45. markdown,
  46. currentPagePath: pageContainer.state.path,
  47. };
  48. const growiRenderer = this.props.growiRenderer;
  49. const interceptorManager = this.props.appContainer.interceptorManager;
  50. interceptorManager.process('preRender', context)
  51. .then(() => { return interceptorManager.process('prePreProcess', context) })
  52. .then(() => {
  53. context.markdown = growiRenderer.preProcess(context.markdown);
  54. })
  55. .then(() => { return interceptorManager.process('postPreProcess', context) })
  56. .then(() => {
  57. context.parsedHTML = growiRenderer.process(context.markdown);
  58. })
  59. .then(() => { return interceptorManager.process('prePostProcess', context) })
  60. .then(() => {
  61. context.parsedHTML = growiRenderer.postProcess(context.parsedHTML);
  62. // highlight
  63. if (this.props.highlightKeywords != null) {
  64. context.parsedHTML = this.getHighlightedBody(context.parsedHTML, this.props.highlightKeywords);
  65. }
  66. })
  67. .then(() => { return interceptorManager.process('postPostProcess', context) })
  68. .then(() => { return interceptorManager.process('preRenderHtml', context) })
  69. .then(() => {
  70. this.setState({ html: context.parsedHTML });
  71. })
  72. // process interceptors for post rendering
  73. .then(() => { return interceptorManager.process('postRenderHtml', context) });
  74. }
  75. render() {
  76. const config = this.props.appContainer.getConfig();
  77. const isMathJaxEnabled = !!config.env.MATHJAX;
  78. return (
  79. <RevisionBody
  80. html={this.state.html}
  81. isMathJaxEnabled={isMathJaxEnabled}
  82. renderMathJaxOnInit
  83. />
  84. );
  85. }
  86. }
  87. /**
  88. * Wrapper component for using unstated
  89. */
  90. const RevisionRendererWrapper = (props) => {
  91. return createSubscribedElement(RevisionRenderer, props, [AppContainer, PageContainer]);
  92. };
  93. RevisionRenderer.propTypes = {
  94. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  95. pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  96. growiRenderer: PropTypes.instanceOf(GrowiRenderer).isRequired,
  97. markdown: PropTypes.string.isRequired,
  98. highlightKeywords: PropTypes.string,
  99. };
  100. export default RevisionRendererWrapper;