Просмотр исходного кода

Merge pull request #6269 from weseek/imprv/100507-refactor-Draft.jsx

Imprv/100507 refactor draft.jsx
yuken 3 лет назад
Родитель
Сommit
2e24a245e9

+ 0 - 223
packages/app/src/components/MyDraftList/Draft.jsx

@@ -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;

+ 144 - 0
packages/app/src/components/MyDraftList/Draft.tsx

@@ -0,0 +1,144 @@
+import React, { useState } from 'react';
+
+import { useTranslation } from 'next-i18next';
+import { CopyToClipboard } from 'react-copy-to-clipboard';
+import ReactMarkdown from 'react-markdown';
+import {
+  Collapse,
+  UncontrolledTooltip,
+} from 'reactstrap';
+
+import { useDraftOptions } from '~/stores/renderer';
+
+type DraftProps = {
+  path: string,
+  isExist: boolean,
+  index: number,
+  markdown: string,
+  clearDraft: (path: string) => void,
+}
+
+export const Draft = (props: DraftProps): JSX.Element => {
+
+  const {
+    path, isExist, index, markdown, clearDraft,
+  } = props;
+  const { t } = useTranslation();
+  const { data: rendererOptions } = useDraftOptions();
+  const [isPanelExpanded, setIsPanelExpanded] = useState(false);
+  const [showCopiedMessage, setShowCopiedMessage] = useState(false);
+
+  const changeToolTipLabel = () => {
+    setShowCopiedMessage(true);
+    setTimeout(() => {
+      setShowCopiedMessage(false);
+    }, 1000);
+  };
+
+  const collapsePanelHandler = () => {
+    setIsPanelExpanded(false);
+  };
+
+  const expandPanelHandler = () => {
+    setIsPanelExpanded(true);
+  };
+
+  const Controls = () => {
+
+    const tooltipTargetId = `draft-copied-tooltip_${index}`;
+
+    return (
+      <div className="icon-container">
+        {isExist
+          ? null
+          : (
+            <a
+              href={`${path}#edit`}
+              target="_blank"
+              rel="noopener noreferrer"
+              data-toggle="tooltip"
+              title={t('Edit')}
+            >
+              <i className="mx-2 icon-note" />
+            </a>
+          )
+        }
+        <span id={tooltipTargetId}>
+          <CopyToClipboard text={markdown} onCopy={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">
+          { showCopiedMessage && (
+            <strong>copied!</strong>
+          ) }
+          { !showCopiedMessage && (
+            <span>{t('Copy')}</span>
+          ) }
+        </UncontrolledTooltip>
+        <a
+          className="text-danger text-center"
+          data-toggle="tooltip"
+          data-placement="top"
+          title={t('Delete')}
+          onClick={() => { return clearDraft(path) }}
+        >
+          <i className="mx-2 icon-trash" />
+        </a>
+      </div>
+    );
+  };
+
+  const AccordionTitle = () => {
+    const iconClass = isPanelExpanded ? 'fa-rotate-90' : '';
+
+    return (
+      <span>
+
+        <span className="mr-2 draft-path" onClick={() => setIsPanelExpanded(!isPanelExpanded)}>
+          <i className={`fa fa-fw fa-angle-right mr-2 ${iconClass}`}></i>
+          {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={path}><i className="icon icon-login"></i></a>
+      </span>
+    );
+  };
+
+
+  return (
+    <div className="accordion draft-list-item" role="tablist">
+      <div className="card">
+
+        <div className="card-header d-flex" role="tab">
+          <AccordionTitle/>
+
+          <div className="flex-grow-1"></div>
+
+          <Controls/>
+        </div>
+
+        <Collapse isOpen={isPanelExpanded} onEntering={expandPanelHandler} onExiting={collapsePanelHandler}>
+          <div className="card-body">
+            { isPanelExpanded && (
+              <ReactMarkdown {...rendererOptions} className='wiki'>
+                {markdown}
+              </ReactMarkdown>
+            ) }
+          </div>
+        </Collapse>
+
+      </div>
+    </div>
+  );
+};

+ 1 - 1
packages/app/src/components/MyDraftList/MyDraftList.jsx

@@ -10,7 +10,7 @@ import { apiGet } from '~/client/util/apiv1-client';
 import PaginationWrapper from '../PaginationWrapper';
 import { withUnstatedContainers } from '../UnstatedUtils';
 
-import Draft from './Draft';
+import { Draft } from './Draft';
 
 class MyDraftList extends React.Component {