| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- import React from 'react';
- import PropTypes from 'prop-types';
- import { CopyToClipboard } from 'react-copy-to-clipboard';
- import { useTranslation } from 'react-i18next';
- import {
- Collapse,
- UncontrolledTooltip,
- } from 'reactstrap';
- import AppContainer from '~/client/services/AppContainer';
- import RevisionBody from '../Page/RevisionBody';
- import { withUnstatedContainers } from '../UnstatedUtils';
- class Draft extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- html: '',
- isRendered: false,
- isPanelExpanded: false,
- showCopiedMessage: false,
- };
- this.growiRenderer = this.props.appContainer.getRenderer('draft');
- this.changeToolTipLabel = this.changeToolTipLabel.bind(this);
- this.expandPanelHandler = this.expandPanelHandler.bind(this);
- this.collapsePanelHandler = this.collapsePanelHandler.bind(this);
- this.renderHtml = this.renderHtml.bind(this);
- this.renderAccordionTitle = this.renderAccordionTitle.bind(this);
- }
- changeToolTipLabel() {
- this.setState({ showCopiedMessage: true });
- setTimeout(() => {
- this.setState({ showCopiedMessage: false });
- }, 1000);
- }
- expandPanelHandler() {
- this.setState({ isPanelExpanded: true });
- if (!this.state.isRendered) {
- this.renderHtml();
- }
- }
- collapsePanelHandler() {
- this.setState({ isPanelExpanded: false });
- }
- async renderHtml() {
- const context = {
- markdown: this.props.markdown,
- };
- const growiRenderer = this.growiRenderer;
- const interceptorManager = this.props.appContainer.interceptorManager;
- await interceptorManager.process('prePreProcess', context)
- .then(() => {
- context.markdown = growiRenderer.preProcess(context.markdown, context);
- })
- .then(() => { return interceptorManager.process('postPreProcess', context) })
- .then(() => {
- const parsedHTML = growiRenderer.process(context.markdown, context);
- context.parsedHTML = parsedHTML;
- })
- .then(() => { return interceptorManager.process('prePostProcess', context) })
- .then(() => {
- context.parsedHTML = growiRenderer.postProcess(context.parsedHTML, context);
- })
- .then(() => { return interceptorManager.process('postPostProcess', context) })
- .then(() => {
- this.setState({ html: context.parsedHTML, isRendered: true });
- });
- }
- renderAccordionTitle(isExist) {
- const { isPanelExpanded } = this.state;
- const { t } = this.props;
- const iconClass = isPanelExpanded ? 'fa-rotate-90' : '';
- return (
- <span>
- <span className="mr-2 draft-path" onClick={() => this.setState({ isPanelExpanded: !isPanelExpanded })}>
- <i className={`fa fa-fw fa-angle-right mr-2 ${iconClass}`}></i>
- {this.props.path}
- </span>
- { isExist && (
- <span className="badge badge-warning">{t('page exists')}</span>
- ) }
- { !isExist && (
- <span className="badge badge-info">draft</span>
- ) }
- <a className="ml-2" href={this.props.path}><i className="icon icon-login"></i></a>
- </span>
- );
- }
- renderControls() {
- const { t, path, index } = this.props;
- const tooltipTargetId = `draft-copied-tooltip_${index}`;
- return (
- <div className="icon-container">
- {this.props.isExist
- ? null
- : (
- <a
- href={`${path}#edit`}
- target="_blank"
- rel="noopener noreferrer"
- data-toggle="tooltip"
- title={this.props.t('Edit')}
- >
- <i className="mx-2 icon-note" />
- </a>
- )
- }
- <span id={tooltipTargetId}>
- <CopyToClipboard text={this.props.markdown} onCopy={this.changeToolTipLabel}>
- <a
- className="text-center draft-copy"
- >
- <i className="mx-2 ti-clipboard" />
- </a>
- </CopyToClipboard>
- </span>
- <UncontrolledTooltip placement="top" target={tooltipTargetId} fade={false} trigger="hover">
- { this.state.showCopiedMessage && (
- <strong>copied!</strong>
- ) }
- { !this.state.showCopiedMessage && (
- <span>{this.props.t('Copy')}</span>
- ) }
- </UncontrolledTooltip>
- <a
- className="text-danger text-center"
- data-toggle="tooltip"
- data-placement="top"
- title={t('Delete')}
- onClick={() => { return this.props.clearDraft(this.props.path) }}
- >
- <i className="mx-2 icon-trash" />
- </a>
- </div>
- );
- }
- render() {
- const { isPanelExpanded } = this.state;
- return (
- <div className="accordion draft-list-item" role="tablist">
- <div className="card">
- <div className="card-header d-flex" role="tab">
- {this.renderAccordionTitle(this.props.isExist)}
- <div className="flex-grow-1"></div>
- {this.renderControls()}
- </div>
- <Collapse isOpen={isPanelExpanded} onEntering={this.expandPanelHandler} onExiting={this.collapsePanelHandler}>
- <div className="card-body">
- {/* loading spinner */}
- { this.state.isPanelExpanded && !this.state.isRendered && (
- <div className="text-center">
- <i className="fa fa-lg fa-spinner fa-pulse mx-auto text-muted"></i>
- </div>
- ) }
- {/* contents */}
- { this.state.isPanelExpanded && this.state.isRendered && (
- <RevisionBody html={this.state.html} />
- ) }
- </div>
- </Collapse>
- </div>
- </div>
- );
- }
- }
- Draft.propTypes = {
- t: PropTypes.func.isRequired,
- appContainer: PropTypes.instanceOf(AppContainer).isRequired,
- index: PropTypes.number.isRequired,
- path: PropTypes.string.isRequired,
- markdown: PropTypes.string.isRequired,
- isExist: PropTypes.bool.isRequired,
- clearDraft: PropTypes.func.isRequired,
- };
- const DraftWrapperFC = (props) => {
- const { t } = useTranslation();
- return <Draft t={t} {...props} />;
- };
- /**
- * Wrapper component for using unstated
- */
- const DraftWrapper = withUnstatedContainers(DraftWrapperFC, [AppContainer]);
- export default DraftWrapper;
|