|
@@ -4,6 +4,8 @@ import PropTypes from 'prop-types';
|
|
|
import Modal from 'react-bootstrap/es/Modal';
|
|
import Modal from 'react-bootstrap/es/Modal';
|
|
|
import Button from 'react-bootstrap/es/Button';
|
|
import Button from 'react-bootstrap/es/Button';
|
|
|
import ButtonGroup from 'react-bootstrap/es/ButtonGroup';
|
|
import ButtonGroup from 'react-bootstrap/es/ButtonGroup';
|
|
|
|
|
+
|
|
|
|
|
+import { debounce } from 'throttle-debounce';
|
|
|
import Collapse from 'react-bootstrap/es/Collapse';
|
|
import Collapse from 'react-bootstrap/es/Collapse';
|
|
|
import FormGroup from 'react-bootstrap/es/FormGroup';
|
|
import FormGroup from 'react-bootstrap/es/FormGroup';
|
|
|
import ControlLabel from 'react-bootstrap/es/ControlLabel';
|
|
import ControlLabel from 'react-bootstrap/es/ControlLabel';
|
|
@@ -15,15 +17,21 @@ import { HotTable } from '@handsontable/react';
|
|
|
import MarkdownTable from '../../models/MarkdownTable';
|
|
import MarkdownTable from '../../models/MarkdownTable';
|
|
|
import HandsontableUtil from './HandsontableUtil';
|
|
import HandsontableUtil from './HandsontableUtil';
|
|
|
|
|
|
|
|
|
|
+const DEFAULT_HOT_HEIGHT = 300;
|
|
|
|
|
+
|
|
|
export default class HandsontableModal extends React.Component {
|
|
export default class HandsontableModal extends React.Component {
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
constructor(props) {
|
|
constructor(props) {
|
|
|
super(props);
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
|
this.state = {
|
|
|
show: false,
|
|
show: false,
|
|
|
isDataImportAreaExpanded: false,
|
|
isDataImportAreaExpanded: false,
|
|
|
|
|
+ isWindowExpanded: false,
|
|
|
markdownTableOnInit: HandsontableModal.getDefaultMarkdownTable(),
|
|
markdownTableOnInit: HandsontableModal.getDefaultMarkdownTable(),
|
|
|
markdownTable: HandsontableModal.getDefaultMarkdownTable(),
|
|
markdownTable: HandsontableModal.getDefaultMarkdownTable(),
|
|
|
|
|
+ handsontableHeight: DEFAULT_HOT_HEIGHT,
|
|
|
handsontableSetting: HandsontableModal.getDefaultHandsontableSetting()
|
|
handsontableSetting: HandsontableModal.getDefaultHandsontableSetting()
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -32,6 +40,11 @@ export default class HandsontableModal extends React.Component {
|
|
|
this.cancel = this.cancel.bind(this);
|
|
this.cancel = this.cancel.bind(this);
|
|
|
this.save = this.save.bind(this);
|
|
this.save = this.save.bind(this);
|
|
|
this.toggleDataImportArea = this.toggleDataImportArea.bind(this);
|
|
this.toggleDataImportArea = this.toggleDataImportArea.bind(this);
|
|
|
|
|
+ this.expandWindow = this.expandWindow.bind(this);
|
|
|
|
|
+ this.contractWindow = this.contractWindow.bind(this);
|
|
|
|
|
+
|
|
|
|
|
+ // create debounced method for expanding HotTable
|
|
|
|
|
+ this.expandHotTableHeightWithDebounce = debounce(100, this.expandHotTableHeight);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
init(markdownTable) {
|
|
init(markdownTable) {
|
|
@@ -101,13 +114,54 @@ export default class HandsontableModal extends React.Component {
|
|
|
this.setState({ isDataImportAreaExpanded: !this.state.isDataImportAreaExpanded });
|
|
this.setState({ isDataImportAreaExpanded: !this.state.isDataImportAreaExpanded });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ expandWindow() {
|
|
|
|
|
+ this.setState({ isWindowExpanded: true });
|
|
|
|
|
+
|
|
|
|
|
+ // invoke updateHotTableHeight method with delay
|
|
|
|
|
+ // cz. Resizing this.refs.hotTableContainer is completeted after a little delay after 'isWindowExpanded' set with 'true'
|
|
|
|
|
+ this.expandHotTableHeightWithDebounce();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ contractWindow() {
|
|
|
|
|
+ this.setState({ isWindowExpanded: false, handsontableHeight: DEFAULT_HOT_HEIGHT });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Expand the height of the Handsontable
|
|
|
|
|
+ * by updating 'handsontableHeight' state
|
|
|
|
|
+ * according to the height of this.refs.hotTableContainer
|
|
|
|
|
+ */
|
|
|
|
|
+ expandHotTableHeight() {
|
|
|
|
|
+ if (this.state.isWindowExpanded && this.refs.hotTableContainer != null) {
|
|
|
|
|
+ const height = this.refs.hotTableContainer.getBoundingClientRect().height;
|
|
|
|
|
+ this.setState({ handsontableHeight: height });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ renderExpandOrContractButton() {
|
|
|
|
|
+ const iconClassName = this.state.isWindowExpanded ? 'icon-size-actual' : 'icon-size-fullscreen';
|
|
|
|
|
+ return (
|
|
|
|
|
+ <button className="close mr-3" onClick={this.state.isWindowExpanded ? this.contractWindow : this.expandWindow}>
|
|
|
|
|
+ <i className={iconClassName} style={{ fontSize: '0.8em' }} aria-hidden="true"></i>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
render() {
|
|
render() {
|
|
|
|
|
+ const dialogClassNames = ['handsontable-modal'];
|
|
|
|
|
+ if (this.state.isWindowExpanded) {
|
|
|
|
|
+ dialogClassNames.push('handsontable-modal-expanded');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const dialogClassName = dialogClassNames.join(' ');
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
- <Modal show={this.state.show} onHide={this.cancel} bsSize="large" dialogClassName="handsontable-modal">
|
|
|
|
|
|
|
+ <Modal show={this.state.show} onHide={this.cancel} bsSize="large" dialogClassName={dialogClassName}>
|
|
|
<Modal.Header closeButton>
|
|
<Modal.Header closeButton>
|
|
|
|
|
+ { this.renderExpandOrContractButton() }
|
|
|
<Modal.Title>Edit Table</Modal.Title>
|
|
<Modal.Title>Edit Table</Modal.Title>
|
|
|
</Modal.Header>
|
|
</Modal.Header>
|
|
|
- <Modal.Body className="p-0">
|
|
|
|
|
|
|
+ <Modal.Body className="p-0 d-flex flex-column">
|
|
|
<div className="px-4 py-3 modal-navbar">
|
|
<div className="px-4 py-3 modal-navbar">
|
|
|
<Button className="m-r-20 data-import-button" onClick={this.toggleDataImportArea}>
|
|
<Button className="m-r-20 data-import-button" onClick={this.toggleDataImportArea}>
|
|
|
Data Import<i className={this.state.isDataImportAreaExpanded ? 'fa fa-angle-up' : 'fa fa-angle-down' }></i>
|
|
Data Import<i className={this.state.isDataImportAreaExpanded ? 'fa fa-angle-up' : 'fa fa-angle-down' }></i>
|
|
@@ -140,8 +194,8 @@ export default class HandsontableModal extends React.Component {
|
|
|
</div>
|
|
</div>
|
|
|
</Collapse>
|
|
</Collapse>
|
|
|
</div>
|
|
</div>
|
|
|
- <div className="p-4">
|
|
|
|
|
- <HotTable ref='hotTable' data={this.state.markdownTable.table} settings={this.state.handsontableSetting} />
|
|
|
|
|
|
|
+ <div ref="hotTableContainer" className="m-4 hot-table-container">
|
|
|
|
|
+ <HotTable ref='hotTable' data={this.state.markdownTable.table} settings={this.state.handsontableSetting} height={this.state.handsontableHeight} />
|
|
|
</div>
|
|
</div>
|
|
|
</Modal.Body>
|
|
</Modal.Body>
|
|
|
<Modal.Footer>
|
|
<Modal.Footer>
|
|
@@ -172,9 +226,19 @@ export default class HandsontableModal extends React.Component {
|
|
|
|
|
|
|
|
static getDefaultHandsontableSetting() {
|
|
static getDefaultHandsontableSetting() {
|
|
|
return {
|
|
return {
|
|
|
- height: 300,
|
|
|
|
|
rowHeaders: true,
|
|
rowHeaders: true,
|
|
|
colHeaders: true,
|
|
colHeaders: true,
|
|
|
|
|
+ manualRowMove: true,
|
|
|
|
|
+ manualRowResize: true,
|
|
|
|
|
+ manualColumnMove: true,
|
|
|
|
|
+ manualColumnResize: true,
|
|
|
|
|
+ selectionMode: 'multiple',
|
|
|
|
|
+ outsideClickDeselects: false,
|
|
|
|
|
+
|
|
|
|
|
+ modifyColWidth: function(width) {
|
|
|
|
|
+ return Math.max(80, Math.min(400, width));
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
contextMenu: {
|
|
contextMenu: {
|
|
|
items: {
|
|
items: {
|
|
|
'row_above': {}, 'row_below': {}, 'col_left': {}, 'col_right': {},
|
|
'row_above': {}, 'row_below': {}, 'col_left': {}, 'col_right': {},
|
|
@@ -205,16 +269,6 @@ export default class HandsontableModal extends React.Component {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- },
|
|
|
|
|
- selectionMode: 'multiple',
|
|
|
|
|
- outsideClickDeselects: false,
|
|
|
|
|
- modifyColWidth: function(width) {
|
|
|
|
|
- if (width < 100) {
|
|
|
|
|
- return 100;
|
|
|
|
|
- }
|
|
|
|
|
- if (width > 300) {
|
|
|
|
|
- return 300;
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|