jam411 3 лет назад
Родитель
Сommit
4fd25894d0

+ 17 - 0
packages/app/public/static/locales/en_US/commons.json

@@ -59,6 +59,23 @@
     "cancel": "Cancel"
   },
 
+  "handsontable_modal": {
+    "title": "Edit Table",
+    "data_import": "Data Import",
+    "save": "Save",
+    "reset": "Reset",
+    "cancel": "Cancel",
+    "done": "Done",
+    "data_import_form": {
+      "select_data_format": "Select Data Format",
+      "import_data": "Import Data",
+      "paste_table_data": "Paste table data",
+      "parse_error": "Parse Error",
+      "cancel": "Cancel",
+      "import": "Import"
+    }
+  },
+
   "not_found_page": {
     "page_not_exist": "This page does not exist."
   }

+ 17 - 0
packages/app/public/static/locales/ja_JP/commons.json

@@ -59,6 +59,23 @@
     "cancel": "キャンセル"
   },
 
+  "handsontable_modal": {
+    "title": "テーブル編集",
+    "data_import": "データインポート",
+    "save": "保存",
+    "reset": "リセット",
+    "cancel": "キャンセル",
+    "done": "完了",
+    "data_import_form": {
+      "select_data_format": "データフォーマット",
+      "import_data": "インポートデータ",
+      "paste_table_data": "デーブルデータを貼り付け",
+      "parse_error": "パーザーエラー",
+      "cancel": "キャンセル",
+      "import": "インポート"
+    }
+  },
+
   "not_found_page": {
     "page_not_exist": "このページは存在しません。"
   }

+ 17 - 0
packages/app/public/static/locales/zh_CN/commons.json

@@ -59,6 +59,23 @@
     "cancel": "取消"
   },
 
+  "handsontable_modal": {
+    "title": "编辑表格",
+    "data_import": "数据导入",
+    "save": "节省",
+    "reset": "重启",
+    "cancel": "取消",
+    "done": "完毕",
+    "data_import_form": {
+      "select_data_format": "数据格式",
+      "import_data": "导入数据",
+      "paste_table_data": "粘贴表格数据",
+      "parse_error": "解析错误",
+      "cancel": "取消",
+      "import": "导入"
+    }
+  },
+
   "not_found_page": {
     "page_not_exist": "该页面不存在"
   }

+ 41 - 62
packages/app/src/components/PageEditor/HandsontableModal.tsx

@@ -2,6 +2,7 @@ import React, { useState } from 'react';
 
 import { HotTable } from '@handsontable/react';
 import Handsontable from 'handsontable';
+import { useTranslation } from 'next-i18next';
 import {
   Collapse,
   Modal, ModalHeader, ModalBody, ModalFooter,
@@ -13,11 +14,12 @@ import { useHandsontableModal } from '~/stores/modal';
 
 import ExpandOrContractButton from '../ExpandOrContractButton';
 
-import MarkdownTableDataImportForm from './MarkdownTableDataImportForm';
+import { MarkdownTableDataImportForm } from './MarkdownTableDataImportForm';
 
 import styles from './HandsontableModal.module.scss';
 import 'handsontable/dist/handsontable.full.min.css';
 
+
 const DEFAULT_HOT_HEIGHT = 300;
 const MARKDOWNTABLE_TO_HANDSONTABLE_ALIGNMENT_SYMBOL_MAPPING = {
   r: 'htRight',
@@ -26,14 +28,9 @@ const MARKDOWNTABLE_TO_HANDSONTABLE_ALIGNMENT_SYMBOL_MAPPING = {
   '': '',
 };
 
-export type HandsontableModalProps = {
-  // ref: any,
-  // onSave: (markdownTable: MarkdownTable) => Promise<void>,
-  // autoFormatMarkdownTable: boolean,
-}
-
-export const HandsontableModal = (props: HandsontableModalProps): JSX.Element => {
+export const HandsontableModal = (): JSX.Element => {
 
+  const { t } = useTranslation('commons');
   const { data: handsontableModalData, close: closeHandsontableModal, onSave } = useHandsontableModal();
   const isOpened = handsontableModalData?.isOpened ?? false;
   const autoFormatMarkdownTable = handsontableModalData?.autoFormatMarkdownTable;
@@ -65,7 +62,7 @@ export const HandsontableModal = (props: HandsontableModalProps): JSX.Element =>
     };
   };
 
-  // a Set instance that stores column indices which are resized manually.
+  // A Set instance that stores column indices which are resized manually.
   // these columns will NOT be determined the width automatically by 'modifyColWidthHandler'
   const manuallyResizedColumnIndicesSet = new Set();
 
@@ -83,7 +80,6 @@ export const HandsontableModal = (props: HandsontableModalProps): JSX.Element =>
    */
   const [hotTable, setHotTable] = useState<HotTable | null>();
   const [hotTableContainer, setHotTableContainer] = useState<HTMLDivElement | null>();
-  // const [isShow, setIsShow] = useState<boolean>(false);
   const [isDataImportAreaExpanded, setIsDataImportAreaExpanded] = useState<boolean>(false);
   const [isWindowExpanded, setIsWindowExpanded] = useState<boolean>(false);
   const [markdownTableOnInit, setMarkdownTableOnInit] = useState<MarkdownTable>(() => defaultMarkdownTable());
@@ -110,41 +106,31 @@ export const HandsontableModal = (props: HandsontableModalProps): JSX.Element =>
 
   const cancel = () => {
     closeHandsontableModal();
-    // hide()
     setIsDataImportAreaExpanded(false);
     setIsWindowExpanded(false);
   };
 
-  // const show = () => {
-  //   init(markdownTable);
-  //   setIsShow(true);
-  // };
-
-  // const hide = () => {
-  //   setIsShow(false);
-  //   setIsDataImportAreaExpanded(false);
-  //   setIsWindowExpanded(false);
-  // };
-
-  const save = () => {
-    if (hotTable == null) {
-      return;
-    }
-
-    const markdownTableOption = () => {
+  const markdownTableOption = {
+    get latest() {
       return {
         align: [].concat(markdownTable.options.align),
         pad: autoFormatMarkdownTable !== false,
       };
-    };
+    },
+  };
+
+  const save = async() => {
+    if (hotTable == null) {
+      return;
+    }
 
-    const markdownTable = new MarkdownTable(
+    const updateMarkdownTable = new MarkdownTable(
       hotTable.hotInstance.getData(),
-      markdownTableOption,
+      markdownTableOption.latest,
     ).normalizeCells();
 
     if (onSave != null) {
-      onSave(editor, markdownTable);
+      onSave(editor, updateMarkdownTable);
     }
 
     cancel();
@@ -375,15 +361,13 @@ export const HandsontableModal = (props: HandsontableModalProps): JSX.Element =>
     }
   };
 
-  // create debounced method for expanding HotTable
-  const expandHotTableHeightWithDebounce = debounce(100, expandHotTableHeight);
-
   const expandWindow = () => {
     setIsWindowExpanded(true);
 
+    // create debounced method for expanding HotTable
     // invoke updateHotTableHeight method with delay
     // cz. Resizing this.refs.hotTableContainer is completed after a little delay after 'isWindowExpanded' set with 'true'
-    expandHotTableHeightWithDebounce();
+    debounce(100, expandHotTableHeight);
   };
 
   const contractWindow = () => {
@@ -391,26 +375,6 @@ export const HandsontableModal = (props: HandsontableModalProps): JSX.Element =>
     setHandsontableHeight(DEFAULT_HOT_HEIGHT);
   };
 
-  const renderCloseButton = () => {
-    return (
-      <button type="button" className="close" onClick={cancel} aria-label="Close">
-        <span aria-hidden="true">&times;</span>
-      </button>
-    );
-  };
-
-  const buttons = (
-    <span>
-      {/* change order because of `float: right` by '.close' class */}
-      {renderCloseButton()}
-      <ExpandOrContractButton
-        isWindowExpanded={isWindowExpanded}
-        contractWindow={contractWindow}
-        expandWindow={expandWindow}
-      />
-    </span>
-  );
-
   const createCustomizedContextMenu = () => {
     return {
       items: {
@@ -452,6 +416,20 @@ export const HandsontableModal = (props: HandsontableModalProps): JSX.Element =>
     contextMenu: createCustomizedContextMenu(),
   });
 
+  const closeButton = (
+    <span>
+      {/* change order because of `float: right` by '.close' class */}
+      <button type="button" className="close" onClick={cancel} aria-label="Close">
+        <span aria-hidden="true">&times;</span>
+      </button>
+      <ExpandOrContractButton
+        isWindowExpanded={isWindowExpanded}
+        contractWindow={contractWindow}
+        expandWindow={expandWindow}
+      />
+    </span>
+  );
+
   return (
     <Modal
       isOpen={isOpened}
@@ -462,8 +440,8 @@ export const HandsontableModal = (props: HandsontableModalProps): JSX.Element =>
       wrapClassName={`${styles['grw-handsontable']}`}
       className={`handsontable-modal ${isWindowExpanded && 'grw-modal-expanded'}`}
     >
-      <ModalHeader tag="h4" toggle={cancel} close={buttons} className="bg-primary text-light">
-          Edit Table
+      <ModalHeader tag="h4" toggle={cancel} close={closeButton} className="bg-primary text-light">
+        {t('handsontable_modal.title')}
       </ModalHeader>
       <ModalBody className="p-0 d-flex flex-column">
         <div className="grw-hot-modal-navbar px-4 py-3 border-bottom">
@@ -475,7 +453,8 @@ export const HandsontableModal = (props: HandsontableModalProps): JSX.Element =>
             aria-expanded={isDataImportAreaExpanded}
             onClick={toggleDataImportArea}
           >
-            <span className="mr-3">Data Import</span><i className={isDataImportAreaExpanded ? 'fa fa-angle-up' : 'fa fa-angle-down'}></i>
+            <span className="mr-3">{t('handsontable_modal.data_import')}</span>
+            <i className={isDataImportAreaExpanded ? 'fa fa-angle-up' : 'fa fa-angle-down'}></i>
           </button>
           <div role="group" className="btn-group">
             <button type="button" className="btn btn-secondary" onClick={() => { alignButtonHandler('l') }}>
@@ -510,10 +489,10 @@ export const HandsontableModal = (props: HandsontableModalProps): JSX.Element =>
         </div>
       </ModalBody>
       <ModalFooter className="grw-modal-footer">
-        <button type="button" className="btn btn-danger" onClick={reset}>Reset</button>
+        <button type="button" className="btn btn-danger" onClick={reset}>{t('handsontable_modal.reset')}</button>
         <div className="ml-auto">
-          <button type="button" className="mr-2 btn btn-secondary" onClick={cancel}>Cancel</button>
-          <button type="button" className="btn btn-primary" onClick={save}>Done</button>
+          <button type="button" className="mr-2 btn btn-secondary" onClick={cancel}>{t('handsontable_modal.cancel')}</button>
+          <button type="button" className="btn btn-primary" onClick={save}>{t('handsontable_modal.done')}</button>
         </div>
       </ModalFooter>
     </Modal>

+ 0 - 103
packages/app/src/components/PageEditor/MarkdownTableDataImportForm.jsx

@@ -1,103 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import {
-  Button,
-  Collapse,
-} from 'reactstrap';
-
-import MarkdownTable from '~/client/models/MarkdownTable';
-
-export default class MarkdownTableDataImportForm extends React.Component {
-
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      dataFormat: 'csv',
-      data: '',
-      parserErrorMessage: null,
-    };
-
-    this.importButtonHandler = this.importButtonHandler.bind(this);
-  }
-
-  importButtonHandler() {
-    try {
-      const markdownTable = this.convertFormDataToMarkdownTable();
-      this.props.onImport(markdownTable);
-      this.setState({ parserErrorMessage: null });
-    }
-    catch (e) {
-      this.setState({ parserErrorMessage: e.message });
-    }
-  }
-
-  convertFormDataToMarkdownTable() {
-    let result;
-    switch (this.state.dataFormat) {
-      case 'csv':
-        result = MarkdownTable.fromDSV(this.state.data, ',');
-        break;
-      case 'tsv':
-        result = MarkdownTable.fromDSV(this.state.data, '\t');
-        break;
-      case 'html':
-        result = MarkdownTable.fromHTMLTableTag(this.state.data);
-        break;
-    }
-    return result.normalizeCells();
-  }
-
-  render() {
-    return (
-      <form className="data-import-form">
-        <div className="form-group">
-          <label htmlFor="data-import-form-type-select">Select Data Format</label>
-          <select
-            id="data-import-form-type-select"
-            className="form-control"
-            placeholder="select"
-            value={this.state.dataFormat}
-            onChange={(e) => { return this.setState({ dataFormat: e.target.value }) }}
-          >
-            <option value="csv">CSV</option>
-            <option value="tsv">TSV</option>
-            <option value="html">HTML</option>
-          </select>
-        </div>
-        <div className="form-group">
-          <label htmlFor="data-import-form-type-textarea">Import Data</label>
-          <textarea
-            id="data-import-form-type-textarea"
-            className="form-control"
-            placeholder="Paste table data"
-            rows="8"
-            onChange={(e) => { return this.setState({ data: e.target.value }) }}
-          />
-        </div>
-        <Collapse isOpen={this.state.parserErrorMessage != null}>
-          <div className="form-group">
-            <label htmlFor="data-import-form-type-textarea-alert">Parse Error</label>
-            <textarea
-              id="data-import-form-type-textarea-alert"
-              className="form-control"
-              rows="4"
-              value={this.state.parserErrorMessage || ''}
-              readOnly
-            />
-          </div>
-        </Collapse>
-        <div className="d-flex justify-content-end">
-          <Button color="secondary mr-2" onClick={this.props.onCancel}>Cancel</Button>
-          <Button color="primary" onClick={this.importButtonHandler}>Import</Button>
-        </div>
-      </form>
-    );
-  }
-
-}
-
-MarkdownTableDataImportForm.propTypes = {
-  onCancel: PropTypes.func,
-  onImport: PropTypes.func,
-};

+ 98 - 0
packages/app/src/components/PageEditor/MarkdownTableDataImportForm.tsx

@@ -0,0 +1,98 @@
+import React, { useState } from 'react';
+
+import { useTranslation } from 'next-i18next';
+import {
+  Button,
+  Collapse,
+} from 'reactstrap';
+
+import MarkdownTable from '~/client/models/MarkdownTable';
+
+type MarkdownTableDataImportFormProps = {
+  onCancel: () => void,
+  onImport: (table: MarkdownTable) => void,
+}
+
+export const MarkdownTableDataImportForm = (props: MarkdownTableDataImportFormProps): JSX.Element => {
+
+  const { onCancel, onImport } = props;
+
+  const { t } = useTranslation('commons', { keyPrefix: 'handsontable_modal.data_import_form' });
+
+  const [dataFormat, setDataFormat] = useState<string>('csv');
+  const [data, setData] = useState<string>('');
+  const [parserErrorMessage, setParserErrorMessage] = useState(null);
+
+  const convertFormDataToMarkdownTable = () => {
+    let result;
+    switch (dataFormat) {
+      case 'csv':
+        result = MarkdownTable.fromDSV(data, ',');
+        break;
+      case 'tsv':
+        result = MarkdownTable.fromDSV(data, '\t');
+        break;
+      case 'html':
+        result = MarkdownTable.fromHTMLTableTag(data);
+        break;
+    }
+    return result.normalizeCells();
+  };
+
+  const importButtonHandler = () => {
+    try {
+      const markdownTable = convertFormDataToMarkdownTable();
+      onImport(markdownTable);
+      setParserErrorMessage(null);
+    }
+    catch (e) {
+      setParserErrorMessage(e.message);
+    }
+  };
+
+  return (
+    <form className="data-import-form">
+      <div className="form-group">
+        <label htmlFor="data-import-form-type-select">{t('select_data_format')}</label>
+        <select
+          id="data-import-form-type-select"
+          className="form-control"
+          placeholder="select"
+          value={dataFormat}
+          onChange={(e) => { return setDataFormat(e.target.value) }}
+        >
+          <option value="csv">CSV</option>
+          <option value="tsv">TSV</option>
+          <option value="html">HTML</option>
+        </select>
+      </div>
+      <div className="form-group">
+        <label htmlFor="data-import-form-type-textarea">{t('import_data')}</label>
+        <textarea
+          id="data-import-form-type-textarea"
+          className="form-control"
+          placeholder={t('paste_table_data')}
+          rows={8}
+          onChange={(e) => { return setData(e.target.value) }}
+        />
+      </div>
+      <Collapse isOpen={parserErrorMessage != null}>
+        <div className="form-group">
+          <label htmlFor="data-import-form-type-textarea-alert">{t('parse_error')}</label>
+          <textarea
+            id="data-import-form-type-textarea-alert"
+            className="form-control"
+            rows={4}
+            value={parserErrorMessage || ''}
+            readOnly
+          />
+        </div>
+      </Collapse>
+      <div className="d-flex justify-content-end">
+        <Button color="secondary mr-2" onClick={onCancel}>{t('cancel')}</Button>
+        <Button color="primary" onClick={importButtonHandler}>{t('import')}</Button>
+      </div>
+    </form>
+  );
+
+};

+ 3 - 11
packages/app/src/stores/modal.tsx

@@ -491,8 +491,6 @@ type HandsontableModalStatusUtils = {
   open(table: MarkdownTable, editor: any, autoFormatMarkdownTable: boolean): Promise<HandsontableModalStatus | undefined>
   close(): Promise<HandsontableModalStatus | undefined>
   onSave(editor:any, tables: MarkdownTable): void
-  // updateEditor(editor: any): Promise<HandsontableModalStatus | undefined>
-  // updateAutoFormatMarkdownTable(autoFormatMarkdownTable: boolean): Promise<HandsontableModalStatus | undefined>
 }
 
 export const useHandsontableModal = (status?: HandsontableModalStatus): SWRResponse<HandsontableModalStatus, Error> & HandsontableModalStatusUtils => {
@@ -507,20 +505,14 @@ export const useHandsontableModal = (status?: HandsontableModalStatus): SWRRespo
   const close = () => swrResponse.mutate({
     isOpened: false, table: new MarkdownTable(), editor: '', autoFormatMarkdownTable: false,
   });
-  const onSave = (editor: any, tables: MarkdownTable) => mtu.replaceFocusedMarkdownTableWithEditor(editor, tables);
-  // const updateEditor = (editor: any) => swrResponse.mutate({
-  //   isOpened: true, table: new MarkdownTable(), editor, autoFormatMarkdownTable: false,
-  // });
-  // const updateAutoFormatMarkdownTable = (autoFormatMarkdownTable: boolean) => swrResponse.mutate({
-  //   isOpened: true, table: new MarkdownTable(), editor: '', autoFormatMarkdownTable,
-  // });
+  const onSave = (editor: any, tables: MarkdownTable) => {
+    mtu.replaceFocusedMarkdownTableWithEditor(editor, tables);
+  };
 
   return {
     ...swrResponse,
     open,
     close,
     onSave,
-    // updateEditor,
-    // updateAutoFormatMarkdownTable,
   };
 };