|
|
@@ -1,223 +0,0 @@
|
|
|
-import React from 'react';
|
|
|
-
|
|
|
-import { useTranslation } from 'next-i18next';
|
|
|
-import PropTypes from 'prop-types';
|
|
|
-import { CopyToClipboard } from 'react-copy-to-clipboard';
|
|
|
-import {
|
|
|
- Collapse,
|
|
|
- UncontrolledTooltip,
|
|
|
-} from 'reactstrap';
|
|
|
-
|
|
|
-import AppContainer from '~/client/services/AppContainer';
|
|
|
-import GrowiRenderer from '~/services/renderer/growi-renderer';
|
|
|
-import { useDraftRenderer } from '~/stores/renderer';
|
|
|
-
|
|
|
-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.growiRenderer;
|
|
|
-
|
|
|
- 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 } = window;
|
|
|
- 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,
|
|
|
- growiRenderer: PropTypes.instanceOf(GrowiRenderer).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();
|
|
|
- const { data: growiRenderer } = useDraftRenderer();
|
|
|
- if (growiRenderer == null) {
|
|
|
- return <></>;
|
|
|
- }
|
|
|
-
|
|
|
- return <Draft t={t} growiRenderer={growiRenderer} {...props} />;
|
|
|
-};
|
|
|
-
|
|
|
-/**
|
|
|
- * Wrapper component for using unstated
|
|
|
- */
|
|
|
-const DraftWrapper = withUnstatedContainers(DraftWrapperFC, [AppContainer]);
|
|
|
-
|
|
|
-export default DraftWrapper;
|