Page.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import RevisionBody from './Page/RevisionBody';
  4. export default class Page extends React.Component {
  5. constructor(props) {
  6. super(props);
  7. this.state = {
  8. html: '',
  9. };
  10. this.appendEditSectionButtons = this.appendEditSectionButtons.bind(this);
  11. this.renderHtml = this.renderHtml.bind(this);
  12. this.getHighlightedBody = this.getHighlightedBody.bind(this);
  13. }
  14. componentWillMount() {
  15. this.renderHtml(this.props.markdown, this.props.highlightKeywords);
  16. }
  17. componentDidUpdate() {
  18. this.appendEditSectionButtons();
  19. }
  20. componentWillReceiveProps(nextProps) {
  21. this.renderHtml(nextProps.markdown, nextProps.highlightKeywords);
  22. }
  23. setMarkdown(markdown) {
  24. this.setState({ markdown });
  25. this.renderHtml(markdown, this.props.highlightKeywords);
  26. }
  27. /**
  28. * Add edit section buttons to headers
  29. * This invoke `appendEditSectionButtons` method of `legacy/crowi.js`
  30. */
  31. appendEditSectionButtons(parentElement) {
  32. if (this.props.showHeadEditButton) {
  33. const crowiForJquery = this.props.crowi.getCrowiForJquery();
  34. crowiForJquery.appendEditSectionButtons(this.revisionBodyElement);
  35. }
  36. }
  37. /**
  38. * transplanted from legacy code -- Yuki Takei
  39. * @param {string} body html strings
  40. * @param {string} keywords
  41. */
  42. getHighlightedBody(body, keywords) {
  43. let returnBody = body;
  44. keywords.replace(/"/g, '').split(' ').forEach((keyword) => {
  45. if (keyword === '') {
  46. return;
  47. }
  48. const k = keyword
  49. .replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
  50. .replace(/(^"|"$)/g, ''); // for phrase (quoted) keyword
  51. const keywordExp = new RegExp(`(${k}(?!(.*?")))`, 'ig');
  52. returnBody = returnBody.replace(keywordExp, '<em class="highlighted">$&</em>');
  53. });
  54. return returnBody;
  55. }
  56. renderHtml(markdown, highlightKeywords) {
  57. var context = {
  58. markdown,
  59. dom: this.revisionBodyElement,
  60. currentPagePath: this.props.pagePath,
  61. };
  62. const crowiRenderer = this.props.crowiRenderer;
  63. const interceptorManager = this.props.crowi.interceptorManager;
  64. interceptorManager.process('preRenderPreview', context)
  65. .then(() => interceptorManager.process('prePreProcess', context))
  66. .then(() => {
  67. context.markdown = crowiRenderer.preProcess(context.markdown);
  68. })
  69. .then(() => interceptorManager.process('postPreProcess', context))
  70. .then(() => {
  71. var parsedHTML = crowiRenderer.process(context.markdown);
  72. context['parsedHTML'] = parsedHTML;
  73. })
  74. .then(() => interceptorManager.process('prePostProcess', context))
  75. .then(() => {
  76. context.parsedHTML = crowiRenderer.postProcess(context.parsedHTML, context.dom);
  77. // highlight
  78. if (highlightKeywords != null) {
  79. context.parsedHTML = this.getHighlightedBody(context.parsedHTML, highlightKeywords);
  80. }
  81. })
  82. .then(() => interceptorManager.process('postPostProcess', context))
  83. .then(() => interceptorManager.process('preRenderPreviewHtml', context))
  84. .then(() => {
  85. this.setState({ html: context.parsedHTML });
  86. })
  87. // process interceptors for post rendering
  88. .then(() => interceptorManager.process('postRenderPreviewHtml', context));
  89. }
  90. render() {
  91. const config = this.props.crowi.getConfig();
  92. const isMathJaxEnabled = !!config.env.MATHJAX;
  93. return (
  94. <RevisionBody html={this.state.html}
  95. inputRef={el => this.revisionBodyElement = el}
  96. isMathJaxEnabled={isMathJaxEnabled}
  97. renderMathJaxOnInit={true}
  98. />
  99. )
  100. }
  101. }
  102. Page.propTypes = {
  103. crowi: PropTypes.object.isRequired,
  104. crowiRenderer: PropTypes.object.isRequired,
  105. markdown: PropTypes.string.isRequired,
  106. pagePath: PropTypes.string.isRequired,
  107. showHeadEditButton: PropTypes.bool,
  108. highlightKeywords: PropTypes.string,
  109. };