import React, { Suspense } from 'react'; import PropTypes from 'prop-types'; import { MarkdownViewer } from '@seafile/seafile-editor'; import { I18nextProvider } from 'react-i18next'; import i18n from '../../_i18n/i18n-seafile-editor'; import { gettext, mediaUrl, serviceURL, sharedToken, slug } from '../../utils/constants'; import { Utils } from '../../utils/utils'; import Loading from '../loading'; import './style.css'; const propTypes = { isWiki: PropTypes.bool, path: PropTypes.string, repoID: PropTypes.string, isTOCShow: PropTypes.bool, children: PropTypes.object, isFileLoading: PropTypes.bool.isRequired, containerClassName: PropTypes.string, markdownContent: PropTypes.string.isRequired, latestContributor: PropTypes.string.isRequired, lastModified: PropTypes.string.isRequired, onLinkClick: PropTypes.func.isRequired, }; class SeafileMarkdownViewer extends React.Component { constructor(props) { super(props); this.scrollRef = React.createRef(); } onLinkClick = (link) => { this.props.onLinkClick(link); }; changeInlineNode = (item) => { const { repoID } = this.props; let url, imagePath; // isPublicWiki: in the old version, only public wiki need replace image url if (item.type == 'image') { // change image url url = item.data.src; const re = new RegExp(serviceURL + '/lib/' + repoID +'/file.*raw=1'); // different repo if (re.test(url)) { // get image path let index = url.indexOf('/file'); let index2 = url.indexOf('?'); imagePath = url.substring(index + 5, index2); } else if (/^\.\.\/*/.test(url) || /^\.\/*/.test(url)) { const path = this.props.path; const originalPath = path.slice(0, path.lastIndexOf('/')) + '/' + url; imagePath = Utils.pathNormalize(originalPath); } else { return; } item.data.src = serviceURL + '/view-image-via-public-wiki/?slug=' + slug + '&path=' + imagePath; } else if (item.type == 'link') { // change link url url = item.url; if (Utils.isInternalFileLink(url, repoID)) { // change file url if (Utils.isInternalMarkdownLink(url, repoID)) { let path = Utils.getPathFromInternalMarkdownLink(url, repoID); // replace url item.url = serviceURL + '/published/' + slug + path; } else { item.url = url.replace(/(.*)lib\/([-0-9a-f]{36})\/file(.*)/g, (match, p1, p2, p3) => { return `${p1}d/${sharedToken}/files/?p=${p3}&dl=1`; }); } } else if (Utils.isInternalDirLink(url, repoID)) { // change dir url let path = Utils.getPathFromInternalDirLink(url, repoID); // replace url item.url = serviceURL + '/published/' + slug + path; } } return item; }; modifyValueBeforeRender = (value) => { let newNodes = Utils.changeMarkdownNodes(value, this.changeInlineNode); return newNodes; }; renderMarkdown = () => { const { isTOCShow = true, isWiki, markdownContent } = this.props; const props = { isShowOutline: isTOCShow, mathJaxSource: `${mediaUrl}js/mathjax/tex-svg.js`, value: markdownContent, scrollRef: this.scrollRef, onLinkClick: this.onLinkClick, ...(isWiki && {beforeRenderCallback: this.modifyValueBeforeRender}) }; return ( }> ); }; render() { if (this.props.isFileLoading) { return ; } const { isWiki, containerClassName = '' } = this.props; const containerClass = `wiki-page-container ${containerClassName}`; // In dir-column-file width is 100%; // In wiki-viewer width isn't 100% const contentClassName = `wiki-page-content ${isWiki ? '' : 'w-100'}`; return (
{this.props.children} {this.renderMarkdown()}

{gettext('Last modified by')} {this.props.latestContributor}, {this.props.lastModified}

); } } const defaultProps = { isWiki: false, }; SeafileMarkdownViewer.propTypes = propTypes; SeafileMarkdownViewer.defaultProps = defaultProps; export default SeafileMarkdownViewer;