From 4bb2ae2ba04c62dc19e50de447a1bb85d55cdf5d Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 28 Jan 2018 21:53:33 +0800 Subject: [PATCH 001/576] fix typo --- packages/react-bootstrap-table2-paginator/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-bootstrap-table2-paginator/README.md b/packages/react-bootstrap-table2-paginator/README.md index 9350be4ee..ff0c917a6 100644 --- a/packages/react-bootstrap-table2-paginator/README.md +++ b/packages/react-bootstrap-table2-paginator/README.md @@ -1,6 +1,6 @@ -# react-bootstrap-table2-pagination +# react-bootstrap-table2-paginator -`react-bootstrap-table2` separate the pagination code base to [`react-bootstrap-table2-pagination`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/develop/packages/react-bootstrap-table2-paginator), so there's a little bit different when you use pagination. In the following, we are going to show you how to enable and configure the a pagination table +`react-bootstrap-table2` separate the pagination code base to [`react-bootstrap-table2-paginator`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/develop/packages/react-bootstrap-table2-paginator), so there's a little bit different when you use pagination. In the following, we are going to show you how to enable and configure the a pagination table **[Live Demo For Pagination](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Pagination)** @@ -11,7 +11,7 @@ ## Install ```sh -$ npm install react-bootstrap-table2-pagination --save +$ npm install react-bootstrap-table2-paginator --save ``` ## Add CSS From fc813e80b64436717137c9a34557cd736a95ea6d Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 28 Jan 2018 21:57:30 +0800 Subject: [PATCH 002/576] fix #172 --- packages/react-bootstrap-table2/src/row.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/react-bootstrap-table2/src/row.js b/packages/react-bootstrap-table2/src/row.js index 24f443ae6..fa723af65 100644 --- a/packages/react-bootstrap-table2/src/row.js +++ b/packages/react-bootstrap-table2/src/row.js @@ -1,4 +1,5 @@ /* eslint react/prop-types: 0 */ +/* eslint react/no-array-index-key: 0 */ import React, { Component } from 'react'; import PropTypes from 'prop-types'; @@ -126,7 +127,7 @@ class Row extends Component { } return ( Date: Sun, 28 Jan 2018 22:09:00 +0800 Subject: [PATCH 003/576] fix #180 --- .../src/row-selection/selection-cell.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/react-bootstrap-table2/src/row-selection/selection-cell.js b/packages/react-bootstrap-table2/src/row-selection/selection-cell.js index bc7e0c522..bba789e94 100644 --- a/packages/react-bootstrap-table2/src/row-selection/selection-cell.js +++ b/packages/react-bootstrap-table2/src/row-selection/selection-cell.js @@ -13,12 +13,13 @@ export default class SelectionCell extends Component { selected: PropTypes.bool, onRowSelect: PropTypes.func, disabled: PropTypes.bool, - rowIndex: PropTypes.number + rowIndex: PropTypes.number, + clickToSelect: PropTypes.bool } constructor() { super(); - this.handleRowClick = this.handleRowClick.bind(this); + this.handleClick = this.handleClick.bind(this); } shouldComponentUpdate(nextProps) { @@ -27,17 +28,19 @@ export default class SelectionCell extends Component { return nextProps.selected !== selected; } - handleRowClick() { + handleClick() { const { mode: inputType, rowKey, selected, onRowSelect, disabled, - rowIndex + rowIndex, + clickToSelect } = this.props; if (disabled) return; + if (clickToSelect) return; const checked = inputType === Const.ROW_SELECT_SINGLE ? true @@ -54,7 +57,7 @@ export default class SelectionCell extends Component { } = this.props; return ( - + Date: Sun, 28 Jan 2018 23:12:54 +0800 Subject: [PATCH 004/576] implement select filter --- .../react-bootstrap-table2-filter/index.js | 6 + .../src/components/select.js | 132 ++++++++++++++++++ .../src/const.js | 3 +- .../src/wrapper.js | 6 +- 4 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 packages/react-bootstrap-table2-filter/src/components/select.js diff --git a/packages/react-bootstrap-table2-filter/index.js b/packages/react-bootstrap-table2-filter/index.js index f6335a875..068b50812 100644 --- a/packages/react-bootstrap-table2-filter/index.js +++ b/packages/react-bootstrap-table2-filter/index.js @@ -1,4 +1,5 @@ import TextFilter from './src/components/text'; +import SelectFilter from './src/components/select'; import wrapperFactory from './src/wrapper'; import * as Comparison from './src/comparison'; @@ -13,3 +14,8 @@ export const textFilter = (props = {}) => ({ Filter: TextFilter, props }); + +export const selectFilter = (props = {}) => ({ + Filter: SelectFilter, + props +}); diff --git a/packages/react-bootstrap-table2-filter/src/components/select.js b/packages/react-bootstrap-table2-filter/src/components/select.js new file mode 100644 index 000000000..0374280f2 --- /dev/null +++ b/packages/react-bootstrap-table2-filter/src/components/select.js @@ -0,0 +1,132 @@ +/* eslint react/require-default-props: 0 */ +/* eslint no-return-assign: 0 */ +/* eslint react/no-unused-prop-types: 0 */ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { LIKE, EQ } from '../comparison'; +import { FILTER_TYPE } from '../const'; + +function optionsEquals(currOpts, prevOpts) { + const keys = Object.keys(currOpts); + for (let i = 0; i < keys.length; i += 1) { + if (currOpts[keys[i]] !== prevOpts[keys[i]]) { + return false; + } + } + return Object.keys(currOpts).length === Object.keys(prevOpts).length; +} + +class SelectFilter extends Component { + constructor(props) { + super(props); + this.filter = this.filter.bind(this); + const isSelected = props.options[props.defaultValue] !== undefined; + this.state = { isSelected }; + } + + componentDidMount() { + const value = this.selectInput.value; + if (value && value !== '') { + this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + } + } + + componentDidUpdate(prevProps) { + let needFilter = false; + if (this.props.defaultValue !== prevProps.defaultValue) { + needFilter = true; + } else if (!optionsEquals(this.props.options, prevProps.options)) { + needFilter = true; + } + if (needFilter) { + const value = this.selectInput.value; + if (value) { + this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + } + } + } + + getOptions() { + const optionTags = []; + const { options, placeholder, column, withoutEmptyOption } = this.props; + if (!withoutEmptyOption) { + optionTags.push(( + + )); + } + Object.keys(options).forEach(key => + optionTags.push() + ); + return optionTags; + } + + cleanFiltered() { + const value = (this.props.defaultValue !== undefined) ? this.props.defaultValue : ''; + this.setState(() => ({ isSelected: value !== '' })); + this.selectInput.value = value; + this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + } + + applyFilter(value) { + this.selectInput.value = value; + this.setState(() => ({ isSelected: value !== '' })); + this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + } + + filter(e) { + const { value } = e.target; + this.setState(() => ({ isSelected: value !== '' })); + this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + } + + render() { + const { + style, + className, + defaultValue, + onFilter, + column, + options, + comparator, + withoutEmptyOption, + ...rest + } = this.props; + + const selectClass = + `filter select-filter form-control ${className} ${this.state.isSelected ? '' : 'placeholder-selected'}`; + + return ( + + ); + } +} + +SelectFilter.propTypes = { + onFilter: PropTypes.func.isRequired, + column: PropTypes.object.isRequired, + options: PropTypes.object.isRequired, + comparator: PropTypes.oneOf([LIKE, EQ]), + placeholder: PropTypes.string, + style: PropTypes.object, + className: PropTypes.string, + withoutEmptyOption: PropTypes.bool, + defaultValue: PropTypes.any +}; + +SelectFilter.defaultProps = { + defaultValue: '', + className: '', + withoutEmptyOption: false, + comparator: EQ +}; + +export default SelectFilter; diff --git a/packages/react-bootstrap-table2-filter/src/const.js b/packages/react-bootstrap-table2-filter/src/const.js index 25faae05f..64e83614b 100644 --- a/packages/react-bootstrap-table2-filter/src/const.js +++ b/packages/react-bootstrap-table2-filter/src/const.js @@ -1,5 +1,6 @@ export const FILTER_TYPE = { - TEXT: 'TEXT' + TEXT: 'TEXT', + SELECT: 'SELECT' }; export const FILTER_DELAY = 500; diff --git a/packages/react-bootstrap-table2-filter/src/wrapper.js b/packages/react-bootstrap-table2-filter/src/wrapper.js index 7e197fabd..3e6822a53 100644 --- a/packages/react-bootstrap-table2-filter/src/wrapper.js +++ b/packages/react-bootstrap-table2-filter/src/wrapper.js @@ -3,7 +3,8 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { filters } from './filter'; -import { LIKE } from './comparison'; +import { LIKE, EQ } from './comparison'; +import { FILTER_TYPE } from './const'; export default (Base, { _, @@ -47,7 +48,8 @@ export default (Base, { if (!_.isDefined(filterVal) || filterVal === '') { delete currFilters[dataField]; } else { - const { comparator = LIKE } = filter.props; + // select default comparator is EQ, others are LIKE + const { comparator = (filterType === FILTER_TYPE.SELECT ? EQ : LIKE) } = filter.props; currFilters[dataField] = { filterVal, filterType, comparator }; } store.filters = currFilters; From 094a0682f16ce6e30fd19759565f37a505e15e67 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 28 Jan 2018 23:13:10 +0800 Subject: [PATCH 005/576] add select filter stories --- .../column-filter/custom-select-filter.js | 80 +++++++++++++++++++ .../select-filter-default-value.js | 70 ++++++++++++++++ .../select-filter-like-comparator.js | 69 ++++++++++++++++ .../examples/column-filter/select-filter.js | 68 ++++++++++++++++ .../src/utils/common.js | 7 ++ .../stories/index.js | 8 ++ 6 files changed, 302 insertions(+) create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/custom-select-filter.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/select-filter-default-value.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/select-filter-like-comparator.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/select-filter.js diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/custom-select-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/custom-select-filter.js new file mode 100644 index 000000000..be7a3661a --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/custom-select-filter.js @@ -0,0 +1,80 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsQualityGenerator } from 'utils/common'; + +const products = productsQualityGenerator(6); + +const selectOptions = { + 0: 'good', + 1: 'Bad', + 2: 'unknown' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'quality', + text: 'Product Quailty', + formatter: cell => selectOptions[cell], + filter: selectFilter({ + options: selectOptions, + withoutEmptyOption: true, + style: { + backgroundColor: 'pink' + }, + className: 'test-classname', + datamycustomattr: 'datamycustomattr' + }) +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; + +const selectOptions = { + 0: 'good', + 1: 'Bad', + 2: 'unknown' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'quality', + text: 'Product Quailty', + formatter: cell => selectOptions[cell], + filter: selectFilter({ + options: selectOptions, + withoutEmptyOption: true, + style: { + backgroundColor: 'pink' + }, + className: 'test-classname', + datamycustomattr: 'datamycustomattr' + }) +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/select-filter-default-value.js b/packages/react-bootstrap-table2-example/examples/column-filter/select-filter-default-value.js new file mode 100644 index 000000000..848766a5a --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/select-filter-default-value.js @@ -0,0 +1,70 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsQualityGenerator } from 'utils/common'; + +const products = productsQualityGenerator(6); + +const selectOptions = { + 0: 'good', + 1: 'Bad', + 2: 'unknown' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'quality', + text: 'Product Quailty', + formatter: cell => selectOptions[cell], + filter: selectFilter({ + options: selectOptions, + defaultValue: 2 + }) +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; + +const selectOptions = { + 0: 'good', + 1: 'Bad', + 2: 'unknown' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'quality', + text: 'Product Quailty', + formatter: cell => selectOptions[cell], + filter: selectFilter({ + options: selectOptions, + defaultValue: 2 + }) +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/select-filter-like-comparator.js b/packages/react-bootstrap-table2-example/examples/column-filter/select-filter-like-comparator.js new file mode 100644 index 000000000..306bdc8e1 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/select-filter-like-comparator.js @@ -0,0 +1,69 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(6); + +const selectOptions = { + '03': '03', + '04': '04', + '01': '01' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: selectFilter({ + options: selectOptions, + comparator: Comparator.LIKE // default is Comparator.EQ + }) +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; + +const selectOptions = { + '03': '03', + '04': '04', + '01': '01' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: selectFilter({ + options: selectOptions, + comparator: Comparator.LIKE // default is Comparator.EQ + }) +}]; + + +`; + +export default () => ( +
+

Select Filter with LIKE Comparator

+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/select-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/select-filter.js new file mode 100644 index 000000000..6acf84901 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/select-filter.js @@ -0,0 +1,68 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsQualityGenerator } from 'utils/common'; + +const products = productsQualityGenerator(6); + +const selectOptions = { + 0: 'good', + 1: 'Bad', + 2: 'unknown' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'quality', + text: 'Product Quailty', + formatter: cell => selectOptions[cell], + filter: selectFilter({ + options: selectOptions + }) +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; + +const selectOptions = { + 0: 'good', + 1: 'Bad', + 2: 'unknown' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'quality', + text: 'Product Quailty', + formatter: cell => selectOptions[cell], + filter: selectFilter({ + options: selectOptions + }) +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/src/utils/common.js b/packages/react-bootstrap-table2-example/src/utils/common.js index 0d5ad841d..0f1c9f141 100644 --- a/packages/react-bootstrap-table2-example/src/utils/common.js +++ b/packages/react-bootstrap-table2-example/src/utils/common.js @@ -20,6 +20,13 @@ export const productsGenerator = (quantity = 5, callback) => { ); }; +export const productsQualityGenerator = (quantity = 5) => + Array.from({ length: quantity }, (value, index) => ({ + id: index, + name: `Item name ${index}`, + quality: index % 3 + })); + export const jobsGenerator = (quantity = 5) => Array.from({ length: quantity }, (value, index) => ({ id: index, diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 8037edb05..8cf4a01da 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -39,6 +39,10 @@ import TextFilterWithDefaultValue from 'examples/column-filter/text-filter-defau import TextFilterComparator from 'examples/column-filter/text-filter-eq-comparator'; import CustomTextFilter from 'examples/column-filter/custom-text-filter'; import CustomFilterValue from 'examples/column-filter/custom-filter-value'; +import SelectFilter from 'examples/column-filter/select-filter'; +import SelectFilterWithDefaultValue from 'examples/column-filter/select-filter-default-value'; +import SelectFilterComparator from 'examples/column-filter/select-filter-like-comparator'; +import CustomSelectFilter from 'examples/column-filter/custom-select-filter'; // work on rows import RowStyleTable from 'examples/rows/row-style'; @@ -140,6 +144,10 @@ storiesOf('Column Filter', module) .add('Text Filter with Comparator', () => ) .add('Custom Text Filter', () => ) // add another filter type example right here. + .add('Select Filter', () => ) + .add('Select Filter with Default Value', () => ) + .add('Select Filter with Comparator', () => ) + .add('Custom Select Filter', () => ) .add('Custom Filter Value', () => ); storiesOf('Work on Rows', module) From 81e0080aa681100a1c4e9cd10ad7c34d88caa8e3 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Mon, 29 Jan 2018 22:57:08 +0800 Subject: [PATCH 006/576] add styles for filter modules --- gulpfile.babel.js | 1 + .../.storybook/webpack.config.js | 3 ++- .../stories/index.js | 1 + .../style/react-bootstrap-table2-filter.scss | 14 ++++++++++++++ 4 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss diff --git a/gulpfile.babel.js b/gulpfile.babel.js index f124ae9cd..77b5c9f9a 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -24,6 +24,7 @@ const JS_SKIPS = `+(${TEST}|${LIB}|${DIST}|${NODE_MODULES})`; const STYLE_PKGS = [ 'react-bootstrap-table2', + 'react-bootstrap-table2-filter', 'react-bootstrap-table2-paginator' ].reduce((pkg, curr) => `${curr}|${pkg}`, ''); diff --git a/packages/react-bootstrap-table2-example/.storybook/webpack.config.js b/packages/react-bootstrap-table2-example/.storybook/webpack.config.js index 166aef5c2..a2c12e20c 100644 --- a/packages/react-bootstrap-table2-example/.storybook/webpack.config.js +++ b/packages/react-bootstrap-table2-example/.storybook/webpack.config.js @@ -7,6 +7,7 @@ const filterSourcePath = path.join(__dirname, '../../react-bootstrap-table2-filt const editorSourcePath = path.join(__dirname, '../../react-bootstrap-table2-editor/index.js'); const sourceStylePath = path.join(__dirname, '../../react-bootstrap-table2/style'); const paginationStylePath = path.join(__dirname, '../../react-bootstrap-table2-paginator/style'); +const filterStylePath = path.join(__dirname, '../../react-bootstrap-table2-filter/style'); const storyPath = path.join(__dirname, '../stories'); const examplesPath = path.join(__dirname, '../examples'); const srcPath = path.join(__dirname, '../src'); @@ -40,7 +41,7 @@ const loaders = [{ }, { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'], - include: [storyPath, sourceStylePath, paginationStylePath], + include: [storyPath, sourceStylePath, paginationStylePath, filterStylePath], }, { test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/, loader: 'url-loader?limit=100000', diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 8cf4a01da..f5e3db7b7 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -102,6 +102,7 @@ import 'stories/stylesheet/tomorrow.min.css'; import 'stories/stylesheet/storybook.scss'; import '../../react-bootstrap-table2/style/react-bootstrap-table2.scss'; import '../../react-bootstrap-table2-paginator/style/react-bootstrap-table2-paginator.scss'; +import '../../react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss'; // import { action } from '@storybook/addon-actions'; diff --git a/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss b/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss new file mode 100644 index 000000000..16aa6dd52 --- /dev/null +++ b/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss @@ -0,0 +1,14 @@ +.react-bootstrap-table > table > thead > tr > th .filter { + font-weight: normal; +} + +.react-bootstrap-table > table > thead > tr > th .select-filter option[value=''], +.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected { + color: lightgrey; + font-style: italic; +} + +.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected option:not([value='']) { + color: initial; + font-style: initial; +} \ No newline at end of file From 2533a63430f6b85f4541322390c79584c91dda63 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Tue, 30 Jan 2018 23:16:10 +0800 Subject: [PATCH 007/576] patch test for select component --- .../test/components/select.test.js | 296 ++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 packages/react-bootstrap-table2-filter/test/components/select.test.js diff --git a/packages/react-bootstrap-table2-filter/test/components/select.test.js b/packages/react-bootstrap-table2-filter/test/components/select.test.js new file mode 100644 index 000000000..2ed39a623 --- /dev/null +++ b/packages/react-bootstrap-table2-filter/test/components/select.test.js @@ -0,0 +1,296 @@ +import 'jsdom-global/register'; +import React from 'react'; +import sinon from 'sinon'; +import { mount } from 'enzyme'; +import SelectFilter from '../../src/components/select'; +import { FILTER_TYPE } from '../../src/const'; + + +describe('Select Filter', () => { + let wrapper; + let instance; + const onFilter = sinon.stub(); + const column = { + dataField: 'quality', + text: 'Product Quality' + }; + const options = { + 0: 'Bad', + 1: 'Good', + 2: 'Unknow' + }; + + afterEach(() => { + onFilter.reset(); + }); + + describe('initialization', () => { + beforeEach(() => { + wrapper = mount( + + ); + instance = wrapper.instance(); + }); + + it('should have correct state', () => { + expect(instance.state.isSelected).toBeFalsy(); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('select')).toHaveLength(1); + expect(wrapper.find('.select-filter')).toHaveLength(1); + expect(wrapper.find('.placeholder-selected')).toHaveLength(1); + }); + + it('should rendering select options correctly', () => { + const select = wrapper.find('select'); + expect(select.find('option')).toHaveLength(Object.keys(options).length + 1); + expect(select.childAt(0).text()).toEqual(`Select ${column.text}...`); + + Object.keys(options).forEach((key, i) => { + expect(select.childAt(i + 1).prop('value')).toEqual(key); + expect(select.childAt(i + 1).text()).toEqual(options[key]); + }); + }); + }); + + describe('when defaultValue is defined', () => { + let defaultValue; + + describe('and it is valid', () => { + beforeEach(() => { + defaultValue = '0'; + wrapper = mount( + + ); + instance = wrapper.instance(); + }); + + it('should have correct state', () => { + expect(instance.state.isSelected).toBeTruthy(); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('.placeholder-selected')).toHaveLength(0); + }); + + it('should calling onFilter on componentDidMount', () => { + expect(onFilter.calledOnce).toBeTruthy(); + expect(onFilter.calledWith(column, defaultValue, FILTER_TYPE.SELECT)).toBeTruthy(); + }); + }); + }); + + describe('when placeholder is defined', () => { + const placeholder = 'test'; + beforeEach(() => { + wrapper = mount( + + ); + instance = wrapper.instance(); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + const select = wrapper.find('select'); + expect(select.childAt(0).text()).toEqual(placeholder); + }); + }); + + describe('when style is defined', () => { + const style = { backgroundColor: 'red' }; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('select').prop('style')).toEqual(style); + }); + }); + + describe('when withoutEmptyOption is defined', () => { + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering select without default empty option', () => { + const select = wrapper.find('select'); + expect(select.find('option')).toHaveLength(Object.keys(options).length); + }); + }); + + describe('componentDidUpdate', () => { + let prevProps; + + describe('when props.defaultValue is diff from prevProps.defaultValue', () => { + beforeEach(() => { + wrapper = mount( + + ); + prevProps = { + column, + options, + defaultValue: '1' + }; + instance = wrapper.instance(); + instance.componentDidUpdate(prevProps); + }); + + it('should update', () => { + expect(onFilter.callCount).toBe(2); + expect(onFilter.calledWith( + column, instance.props.defaultValue, FILTER_TYPE.SELECT)).toBeTruthy(); + }); + }); + + describe('when props.options is diff from prevProps.options', () => { + beforeEach(() => { + wrapper = mount( + + ); + prevProps = { + column, + options + }; + instance = wrapper.instance(); + instance.componentDidUpdate(prevProps); + }); + + it('should update', () => { + expect(onFilter.callCount).toBe(2); + expect(onFilter.calledWith( + column, instance.props.defaultValue, FILTER_TYPE.SELECT)).toBeTruthy(); + }); + }); + }); + + describe('cleanFiltered', () => { + describe('when props.defaultValue is defined', () => { + const defaultValue = '0'; + beforeEach(() => { + wrapper = mount( + + ); + instance = wrapper.instance(); + instance.cleanFiltered(); + }); + + it('should setting state correctly', () => { + expect(instance.state.isSelected).toBeTruthy(); + }); + + it('should calling onFilter correctly', () => { + expect(onFilter.callCount).toBe(2); + expect(onFilter.calledWith(column, defaultValue, FILTER_TYPE.SELECT)).toBeTruthy(); + }); + }); + + describe('when props.defaultValue is not defined', () => { + beforeEach(() => { + wrapper = mount( + + ); + instance = wrapper.instance(); + instance.cleanFiltered(); + }); + + it('should setting state correctly', () => { + expect(instance.state.isSelected).toBeFalsy(); + }); + + it('should calling onFilter correctly', () => { + expect(onFilter.callCount).toBe(1); + }); + }); + }); + + describe('applyFilter', () => { + const value = '2'; + beforeEach(() => { + wrapper = mount( + + ); + instance = wrapper.instance(); + instance.applyFilter(value); + }); + + it('should setting state correctly', () => { + expect(instance.state.isSelected).toBeTruthy(); + }); + + it('should calling onFilter correctly', () => { + expect(onFilter.callCount).toBe(1); + expect(onFilter.calledWith(column, value, FILTER_TYPE.SELECT)).toBeTruthy(); + }); + }); + + describe('filter', () => { + const event = { target: { value: 'tester' } }; + + beforeEach(() => { + wrapper = mount( + + ); + instance = wrapper.instance(); + instance.filter(event); + }); + + it('should setting state correctly', () => { + expect(instance.state.isSelected).toBeTruthy(); + }); + + it('should calling onFilter correctly', () => { + expect(onFilter.callCount).toBe(1); + expect(onFilter.calledWith(column, event.target.value, FILTER_TYPE.SELECT)).toBeTruthy(); + }); + }); +}); From 9a354444d0c84e4aac766eb7e7557e8967b0df77 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Tue, 30 Jan 2018 23:25:58 +0800 Subject: [PATCH 008/576] fix bug for wrap not existing method --- .../test/row-selection/selection-cell.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js b/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js index bcb5799a0..c0069e206 100644 --- a/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js +++ b/packages/react-bootstrap-table2/test/row-selection/selection-cell.test.js @@ -34,12 +34,12 @@ describe('', () => { }); }); - describe('handleRowClick', () => { + describe('handleClick', () => { describe('when was been clicked', () => { const rowKey = 1; const selected = true; let mockOnRowSelect; - const spy = sinon.spy(SelectionCell.prototype, 'handleRowClick'); + const spy = sinon.spy(SelectionCell.prototype, 'handleClick'); beforeEach(() => { mockOnRowSelect = sinon.stub(); From 8fa6389c81ad0128ad170360d492551cc672d00b Mon Sep 17 00:00:00 2001 From: AllenFang Date: Tue, 30 Jan 2018 23:39:18 +0800 Subject: [PATCH 009/576] patch docs --- docs/columns.md | 1 + docs/migration.md | 3 +- .../react-bootstrap-table2-filter/README.md | 46 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/docs/columns.md b/docs/columns.md index a18a073de..cf546a872 100644 --- a/docs/columns.md +++ b/docs/columns.md @@ -542,6 +542,7 @@ Or take a callback function Configure `column.filter` will able to setup a column level filter on the header column. Currently, `react-bootstrap-table2` support following filters: * Text(`textFilter`) +* Select(`selectFilter`) We have a quick example to show you how to use `column.filter`: diff --git a/docs/migration.md b/docs/migration.md index f66b7f796..fb294c300 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -83,7 +83,8 @@ Please see [available filter configuration](https://react-bootstrap-table.github - [x] Remote Filter - [ ] Custom Filter Component - [ ] Regex Filter -- [ ] Select Filter +- [x] Select Filter +- [x] Custom Select Filter - [ ] Number Filter - [ ] Date Filter - [ ] Array Filter diff --git a/packages/react-bootstrap-table2-filter/README.md b/packages/react-bootstrap-table2-filter/README.md index f8b6788fc..74192b5e8 100644 --- a/packages/react-bootstrap-table2-filter/README.md +++ b/packages/react-bootstrap-table2-filter/README.md @@ -17,6 +17,7 @@ $ npm install react-bootstrap-table2-filter --save You can get all types of filters via import and these filters are a factory function to create a individual filter instance. Currently, we support following filters: * TextFilter +* SelectFilter * **Coming soon!** ## Text Filter @@ -51,5 +52,50 @@ const priceFilter = textFilter({ delay: 1000 // how long will trigger filtering after user typing, default is 500 ms }); +// omit... +``` + +## Select Filter +A quick example: + +```js +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; + +// omit... +const selectOptions = { + 0: 'good', + 1: 'Bad', + 2: 'unknown' +}; + +const columns = [ + ..., { + dataField: 'quality', + text: 'Product Quailty', + formatter: cell => selectOptions[cell], + filter: selectFilter({ + options: selectOptions + }) +}]; + + +``` + +Following is an example for custom select filter: + +```js +import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter'; +// omit... + +const qualityFilter = selectFilter({ + options: selectOptions, + placeholder: 'My Custom PlaceHolder', // custom the input placeholder + className: 'my-custom-text-filter', // custom classname on input + defaultValue: '2', // default filtering value + comparator: Comparator.LIKE, // default is Comparator.EQ + style: { ... }, // your custom styles on input + withoutEmptyOption: true // hide the default select option +}); + // omit... ``` \ No newline at end of file From 8bfbc14bd928ca8c81a7766086727652f8d0b774 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Wed, 31 Jan 2018 00:01:04 +0800 Subject: [PATCH 010/576] fix #185 --- .../src/props-resolver/column-resolver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js b/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js index e963f5117..584649896 100644 --- a/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js +++ b/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js @@ -1,6 +1,6 @@ export default ExtendBase => class ColumnResolver extends ExtendBase { visibleColumnSize() { - return this.props.columns.length; + return this.props.columns.filter(c => !c.hidden).length; } }; From feedcb9f4bafef77a5f87cf4f228a82445f1825c Mon Sep 17 00:00:00 2001 From: Parth Prajapati Date: Wed, 31 Jan 2018 07:43:05 +0530 Subject: [PATCH 011/576] Solves #179 --- .../examples/rows/row-event.js | 8 ++++---- packages/react-bootstrap-table2/src/row.js | 12 ++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/rows/row-event.js b/packages/react-bootstrap-table2-example/examples/rows/row-event.js index 915f9af57..d65d99ad3 100644 --- a/packages/react-bootstrap-table2-example/examples/rows/row-event.js +++ b/packages/react-bootstrap-table2-example/examples/rows/row-event.js @@ -20,8 +20,8 @@ const columns = [{ }]; const rowEvents = { - onClick: (e) => { - alert('click on row'); + onClick: (e, rowIndex) => { + alert(`clicked on row with index: ${rowIndex}`); } }; @@ -40,8 +40,8 @@ const columns = [{ }]; const rowEvents = { - onClick: (e) => { - alert('click on row'); + onClick: (e, rowIndex) => { + alert(\`clicked on row with index: \${rowIndex}\`); } }; diff --git a/packages/react-bootstrap-table2/src/row.js b/packages/react-bootstrap-table2/src/row.js index 24f443ae6..6edaac9f7 100644 --- a/packages/react-bootstrap-table2/src/row.js +++ b/packages/react-bootstrap-table2/src/row.js @@ -12,6 +12,7 @@ class Row extends Component { super(props); this.clickNum = 0; this.handleRowClick = this.handleRowClick.bind(this); + this.handleSimpleRowClick = this.handleSimpleRowClick.bind(this); } handleRowClick(e) { @@ -56,6 +57,15 @@ class Row extends Component { } } + handleSimpleRowClick(e) { + const { + rowIndex, + attrs + } = this.props; + + attrs.onClick(e, rowIndex); + } + render() { const { row, @@ -89,6 +99,8 @@ class Row extends Component { const trAttrs = { ...attrs }; if (clickToSelect) { trAttrs.onClick = this.handleRowClick; + } else { + trAttrs.onClick = this.handleSimpleRowClick; } return ( From 38bb2290dc8570dd64f753224ade0467b799de28 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Wed, 31 Jan 2018 23:50:02 +0800 Subject: [PATCH 012/576] README --- packages/react-bootstrap-table2-filter/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/react-bootstrap-table2-filter/README.md b/packages/react-bootstrap-table2-filter/README.md index 74192b5e8..755741926 100644 --- a/packages/react-bootstrap-table2-filter/README.md +++ b/packages/react-bootstrap-table2-filter/README.md @@ -20,6 +20,16 @@ You can get all types of filters via import and these filters are a factory func * SelectFilter * **Coming soon!** +## Add CSS + +```js +// es5 +require('react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min.css'); + +// es6 +import 'react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min.css'; +``` + ## Text Filter Following is a quick demo for enable the column filter on **Product Price** column!! From c4f14e2b69f9390b6fb827c89f39d34b563fa254 Mon Sep 17 00:00:00 2001 From: Parth Prajapati Date: Thu, 1 Feb 2018 06:20:50 +0530 Subject: [PATCH 013/576] Added row object to onClick - attach onClick only if defined --- .../examples/rows/row-event.js | 2 +- packages/react-bootstrap-table2/src/row.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/rows/row-event.js b/packages/react-bootstrap-table2-example/examples/rows/row-event.js index d65d99ad3..0fb8db10b 100644 --- a/packages/react-bootstrap-table2-example/examples/rows/row-event.js +++ b/packages/react-bootstrap-table2-example/examples/rows/row-event.js @@ -20,7 +20,7 @@ const columns = [{ }]; const rowEvents = { - onClick: (e, rowIndex) => { + onClick: (e, row, rowIndex) => { alert(`clicked on row with index: ${rowIndex}`); } }; diff --git a/packages/react-bootstrap-table2/src/row.js b/packages/react-bootstrap-table2/src/row.js index 6edaac9f7..42f235e60 100644 --- a/packages/react-bootstrap-table2/src/row.js +++ b/packages/react-bootstrap-table2/src/row.js @@ -36,7 +36,7 @@ class Row extends Component { const clickFn = () => { if (attrs.onClick) { - attrs.onClick(e); + attrs.onClick(e, row, rowIndex); } if (selectable) { const key = _.get(row, keyField); @@ -59,11 +59,12 @@ class Row extends Component { handleSimpleRowClick(e) { const { + row, rowIndex, attrs } = this.props; - attrs.onClick(e, rowIndex); + attrs.onClick(e, row, rowIndex); } render() { @@ -99,7 +100,7 @@ class Row extends Component { const trAttrs = { ...attrs }; if (clickToSelect) { trAttrs.onClick = this.handleRowClick; - } else { + } else if (attrs.onClick) { trAttrs.onClick = this.handleSimpleRowClick; } From 577973a147ceab68ad4370c003bcd1351154b9b0 Mon Sep 17 00:00:00 2001 From: Parth Prajapati Date: Thu, 1 Feb 2018 06:27:49 +0530 Subject: [PATCH 014/576] Updated storybook example --- .../react-bootstrap-table2-example/examples/rows/row-event.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2-example/examples/rows/row-event.js b/packages/react-bootstrap-table2-example/examples/rows/row-event.js index 0fb8db10b..1a57fb64f 100644 --- a/packages/react-bootstrap-table2-example/examples/rows/row-event.js +++ b/packages/react-bootstrap-table2-example/examples/rows/row-event.js @@ -40,7 +40,7 @@ const columns = [{ }]; const rowEvents = { - onClick: (e, rowIndex) => { + onClick: (e, row, rowIndex) => { alert(\`clicked on row with index: \${rowIndex}\`); } }; From 88234fead09b85f2edf01de85c88d779d76c83dc Mon Sep 17 00:00:00 2001 From: AllenFang Date: Thu, 1 Feb 2018 23:17:40 +0800 Subject: [PATCH 015/576] Publish - react-bootstrap-table2-editor@0.1.1 - react-bootstrap-table2-example@0.1.1 - react-bootstrap-table2-filter@0.1.2 - react-bootstrap-table2-overlay@0.1.1 - react-bootstrap-table2-paginator@0.1.1 - react-bootstrap-table-next@0.1.2 --- packages/react-bootstrap-table2-filter/package.json | 2 +- packages/react-bootstrap-table2/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-bootstrap-table2-filter/package.json b/packages/react-bootstrap-table2-filter/package.json index 7bf9940d9..0b1a96957 100644 --- a/packages/react-bootstrap-table2-filter/package.json +++ b/packages/react-bootstrap-table2-filter/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-filter", - "version": "0.1.1", + "version": "0.1.2", "description": "it's a column filter addon for react-bootstrap-table2", "main": "./lib/index.js", "repository": { diff --git a/packages/react-bootstrap-table2/package.json b/packages/react-bootstrap-table2/package.json index bf4489c3c..29fb85305 100644 --- a/packages/react-bootstrap-table2/package.json +++ b/packages/react-bootstrap-table2/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table-next", - "version": "0.1.1", + "version": "0.1.2", "description": "Next generation of react-bootstrap-table", "main": "./lib/index.js", "repository": { From 4d7378e3f101040ea39ce522d1db172deef469d3 Mon Sep 17 00:00:00 2001 From: Allen Date: Thu, 1 Feb 2018 23:41:30 +0800 Subject: [PATCH 016/576] create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..4386ac1bb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 react-bootstrap-table2 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From ca32eee28e7a574d38ce40ce425352017afb2f61 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 4 Feb 2018 21:41:52 +0800 Subject: [PATCH 017/576] patch rowEvents docs --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 828cae19d..096ca24bb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -145,7 +145,7 @@ Custom the events on row: ```js const rowEvents = { - onClick: (e) => { + onClick: (e, row, rowIndex) => { .... } }; From 28a1077badc537bf5a9fcc32f2ed2e2e27d7477a Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 10 Feb 2018 15:43:22 +0800 Subject: [PATCH 018/576] implement number filter --- .../react-bootstrap-table2-filter/index.js | 6 + .../src/comparison.js | 5 + .../src/components/number.js | 249 ++++++++++++++++++ .../src/const.js | 3 +- .../src/filter.js | 67 ++++- .../style/react-bootstrap-table2-filter.scss | 19 +- 6 files changed, 346 insertions(+), 3 deletions(-) create mode 100644 packages/react-bootstrap-table2-filter/src/components/number.js diff --git a/packages/react-bootstrap-table2-filter/index.js b/packages/react-bootstrap-table2-filter/index.js index 068b50812..a2bc66655 100644 --- a/packages/react-bootstrap-table2-filter/index.js +++ b/packages/react-bootstrap-table2-filter/index.js @@ -1,5 +1,6 @@ import TextFilter from './src/components/text'; import SelectFilter from './src/components/select'; +import NumberFilter from './src/components/number'; import wrapperFactory from './src/wrapper'; import * as Comparison from './src/comparison'; @@ -19,3 +20,8 @@ export const selectFilter = (props = {}) => ({ Filter: SelectFilter, props }); + +export const numberFilter = (props = {}) => ({ + Filter: NumberFilter, + props +}); diff --git a/packages/react-bootstrap-table2-filter/src/comparison.js b/packages/react-bootstrap-table2-filter/src/comparison.js index cc242141a..7e599e738 100644 --- a/packages/react-bootstrap-table2-filter/src/comparison.js +++ b/packages/react-bootstrap-table2-filter/src/comparison.js @@ -1,2 +1,7 @@ export const LIKE = 'LIKE'; export const EQ = '='; +export const NE = '!='; +export const GT = '>'; +export const GE = '>='; +export const LT = '<'; +export const LE = '<='; diff --git a/packages/react-bootstrap-table2-filter/src/components/number.js b/packages/react-bootstrap-table2-filter/src/components/number.js new file mode 100644 index 000000000..3c2b61286 --- /dev/null +++ b/packages/react-bootstrap-table2-filter/src/components/number.js @@ -0,0 +1,249 @@ +/* eslint no-return-assign: 0 */ + +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import * as Comparator from '../comparison'; +import { FILTER_TYPE, FILTER_DELAY } from '../const'; + +const legalComparators = [ + Comparator.EQ, + Comparator.NE, + Comparator.GT, + Comparator.GE, + Comparator.LT, + Comparator.LE +]; + +class NumberFilter extends Component { + constructor(props) { + super(props); + this.comparators = props.comparators || legalComparators; + this.timeout = null; + let isSelected = props.defaultValue !== undefined && props.defaultValue.number !== undefined; + if (props.options && isSelected) { + isSelected = props.options.indexOf(props.defaultValue.number) > -1; + } + this.state = { isSelected }; + this.onChangeNumber = this.onChangeNumber.bind(this); + this.onChangeNumberSet = this.onChangeNumberSet.bind(this); + this.onChangeComparator = this.onChangeComparator.bind(this); + } + + componentDidMount() { + const { column, onFilter } = this.props; + const comparator = this.numberFilterComparator.value; + const number = this.numberFilter.value; + if (comparator && number) { + onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER); + } + } + + componentWillUnmount() { + clearTimeout(this.timeout); + } + + onChangeNumber(e) { + const { delay, column, onFilter } = this.props; + const comparator = this.numberFilterComparator.value; + if (comparator === '') { + return; + } + if (this.timeout) { + clearTimeout(this.timeout); + } + const filterValue = e.target.value; + this.timeout = setTimeout(() => { + onFilter(column, { number: filterValue, comparator }, FILTER_TYPE.NUMBER); + }, delay); + } + + onChangeNumberSet(e) { + const { column, onFilter } = this.props; + const comparator = this.numberFilterComparator.value; + const { value } = e.target; + this.setState(() => ({ isSelected: (value !== '') })); + // if (comparator === '') { + // return; + // } + onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER); + } + + onChangeComparator(e) { + const { column, onFilter } = this.props; + const value = this.numberFilter.value; + const comparator = e.target.value; + // if (value === '') { + // return; + // } + onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER); + } + + getComparatorOptions() { + const optionTags = []; + const { withoutEmptyComparatorOption } = this.props; + if (!withoutEmptyComparatorOption) { + optionTags.push( + ); + } + return optionTags; + } + + getNumberOptions() { + const optionTags = []; + const { options, column, withoutEmptyNumberOption } = this.props; + if (!withoutEmptyNumberOption) { + optionTags.push( + + ); + } + for (let i = 0; i < options.length; i += 1) { + optionTags.push(); + } + return optionTags; + } + + applyFilter(filterObj) { + const { column, onFilter } = this.props; + const { number, comparator } = filterObj; + this.setState(() => ({ isSelected: (number !== '') })); + this.numberFilterComparator.value = comparator; + this.numberFilter.value = number; + onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER); + } + + cleanFiltered() { + const { column, onFilter, defaultValue } = this.props; + const value = defaultValue ? defaultValue.number : ''; + const comparator = defaultValue ? defaultValue.comparator : ''; + this.setState(() => ({ isSelected: (value !== '') })); + this.numberFilterComparator.value = comparator; + this.numberFilter.value = value; + onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER); + } + + render() { + const { isSelected } = this.state; + const { + defaultValue, + column, + options, + style, + className, + numberStyle, + numberClassName, + comparatorStyle, + comparatorClassName, + placeholder + } = this.props; + const selectClass = ` + select-filter + number-filter-input + form-control + ${numberClassName} + ${!isSelected ? 'placeholder-selected' : ''} + `; + + return ( +
+ + { + options ? + : + this.numberFilter = n } + type="number" + style={ numberStyle } + className={ `number-filter-input form-control ${numberClassName}` } + placeholder={ placeholder || `Enter ${column.text}...` } + onChange={ this.onChangeNumber } + defaultValue={ defaultValue ? defaultValue.number : '' } + /> + } +
+ ); + } +} + +NumberFilter.propTypes = { + onFilter: PropTypes.func.isRequired, + column: PropTypes.object.isRequired, + options: PropTypes.arrayOf(PropTypes.number), + defaultValue: PropTypes.shape({ + number: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + comparator: PropTypes.oneOf([...legalComparators, '']) + }), + delay: PropTypes.number, + /* eslint consistent-return: 0 */ + comparators: (props, propName) => { + if (!props[propName]) { + return; + } + for (let i = 0; i < props[propName].length; i += 1) { + let comparatorIsValid = false; + for (let j = 0; j < legalComparators.length; j += 1) { + if (legalComparators[j] === props[propName][i] || props[propName][i] === '') { + comparatorIsValid = true; + break; + } + } + if (!comparatorIsValid) { + return new Error(`Number comparator provided is not supported. + Use only ${legalComparators}`); + } + } + }, + placeholder: PropTypes.string, + withoutEmptyComparatorOption: PropTypes.bool, + withoutEmptyNumberOption: PropTypes.bool, + style: PropTypes.object, + className: PropTypes.string, + comparatorStyle: PropTypes.object, + comparatorClassName: PropTypes.string, + numberStyle: PropTypes.object, + numberClassName: PropTypes.string +}; + +NumberFilter.defaultProps = { + delay: FILTER_DELAY, + options: undefined, + defaultValue: { + number: undefined, + comparator: '' + }, + withoutEmptyComparatorOption: false, + withoutEmptyNumberOption: false, + comparators: legalComparators, + placeholder: undefined, + style: undefined, + className: '', + comparatorStyle: undefined, + comparatorClassName: '', + numberStyle: undefined, + numberClassName: '' +}; + +export default NumberFilter; diff --git a/packages/react-bootstrap-table2-filter/src/const.js b/packages/react-bootstrap-table2-filter/src/const.js index 64e83614b..a459270fd 100644 --- a/packages/react-bootstrap-table2-filter/src/const.js +++ b/packages/react-bootstrap-table2-filter/src/const.js @@ -1,6 +1,7 @@ export const FILTER_TYPE = { TEXT: 'TEXT', - SELECT: 'SELECT' + SELECT: 'SELECT', + NUMBER: 'NUMBER' }; export const FILTER_DELAY = 500; diff --git a/packages/react-bootstrap-table2-filter/src/filter.js b/packages/react-bootstrap-table2-filter/src/filter.js index 03914a86f..95d020056 100644 --- a/packages/react-bootstrap-table2-filter/src/filter.js +++ b/packages/react-bootstrap-table2-filter/src/filter.js @@ -1,5 +1,7 @@ +/* eslint eqeqeq: 0 */ +/* eslint no-console: 0 */ import { FILTER_TYPE } from './const'; -import { LIKE, EQ } from './comparison'; +import { LIKE, EQ, NE, GT, GE, LT, LE } from './comparison'; export const filterByText = _ => ( data, @@ -19,12 +21,75 @@ export const filterByText = _ => ( return cellStr.indexOf(filterVal) > -1; }); +export const filterByNumber = _ => ( + data, + dataField, + { filterVal: { comparator, number } }, + customFilterValue +) => + data.filter((row) => { + if (number === '' || !comparator) return true; + let valid = true; + let cell = _.get(row, dataField); + if (customFilterValue) { + cell = customFilterValue(cell, row); + } + + switch (comparator) { + case EQ: { + if (cell != number) { + valid = false; + } + break; + } + case GT: { + if (cell <= number) { + valid = false; + } + break; + } + case GE: { + if (cell < number) { + valid = false; + } + break; + } + case LT: { + if (cell >= number) { + valid = false; + } + break; + } + case LE: { + if (cell > number) { + valid = false; + } + break; + } + case NE: { + if (cell == number) { + valid = false; + } + break; + } + default: { + console.error('Number comparator provided is not supported'); + break; + } + } + return valid; + }); + export const filterFactory = _ => (filterType) => { let filterFn; switch (filterType) { case FILTER_TYPE.TEXT: + case FILTER_TYPE.SELECT: filterFn = filterByText(_); break; + case FILTER_TYPE.NUMBER: + filterFn = filterByNumber(_); + break; default: filterFn = filterByText(_); } diff --git a/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss b/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss index 16aa6dd52..70d4a0317 100644 --- a/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss +++ b/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss @@ -3,7 +3,9 @@ } .react-bootstrap-table > table > thead > tr > th .select-filter option[value=''], -.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected { +.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected, +.react-bootstrap-table > table > thead > tr > th .filter::-webkit-input-placeholder, +.react-bootstrap-table > table > thead > tr > th .number-filter-input::-webkit-input-placeholder { color: lightgrey; font-style: italic; } @@ -11,4 +13,19 @@ .react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected option:not([value='']) { color: initial; font-style: initial; +} + +.react-bootstrap-table > table > thead > tr > th .number-filter { + display: flex; +} + +.react-bootstrap-table > table > thead > tr > th .number-filter-input { + margin-left: 5px; + float: left; + width: calc(100% - 67px - 5px); +} + +.react-bootstrap-table > table > thead > tr > th .number-filter-comparator { + width: 67px; + float: left; } \ No newline at end of file From b0f411e93467e0962c3ea36a1b0a07a3060c6171 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 10 Feb 2018 15:43:59 +0800 Subject: [PATCH 019/576] add number filter stories --- .../column-filter/custom-number-filter.js | 74 +++++++++++++++++++ .../number-filter-default-value.js | 54 ++++++++++++++ .../examples/column-filter/number-filter.js | 50 +++++++++++++ .../stories/index.js | 8 +- 4 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/custom-number-filter.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/number-filter-default-value.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/number-filter.js diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/custom-number-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/custom-number-filter.js new file mode 100644 index 000000000..29c361d76 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/custom-number-filter.js @@ -0,0 +1,74 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(8); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: numberFilter({ + options: [2100, 2103, 2105], + delay: 600, + placeholder: 'custom placeholder', + withoutEmptyComparatorOption: true, + comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], + style: { display: 'inline-grid' }, + className: 'custom-numberfilter-class', + comparatorStyle: { backgroundColor: 'antiquewhite' }, + comparatorClassName: 'custom-comparator-class', + numberStyle: { backgroundColor: 'cadetblue', margin: '0px' }, + numberClassName: 'custom-number-class' + }) +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: numberFilter({ + options: [2100, 2103, 2105], + delay: 600, + placeholder: 'custom placeholder', + withoutEmptyComparatorOption: true, + comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], + style: { display: 'inline-grid' }, + className: 'custom-numberfilter-class', + comparatorStyle: { backgroundColor: 'antiquewhite' }, + comparatorClassName: 'custom-comparator-class', + numberStyle: { backgroundColor: 'cadetblue', margin: '0px' }, + numberClassName: 'custom-number-class' + }) +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/number-filter-default-value.js b/packages/react-bootstrap-table2-example/examples/column-filter/number-filter-default-value.js new file mode 100644 index 000000000..463b4729c --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/number-filter-default-value.js @@ -0,0 +1,54 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(8); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: numberFilter({ + defaultValue: { number: 2103, comparator: Comparator.GT } + }) +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: numberFilter({ + defaultValue: { number: 2103, comparator: Comparator.GT } + }) +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/number-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/number-filter.js new file mode 100644 index 000000000..b01167fec --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/number-filter.js @@ -0,0 +1,50 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(8); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: numberFilter() +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: numberFilter() +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index f5e3db7b7..f4a000a73 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -43,6 +43,9 @@ import SelectFilter from 'examples/column-filter/select-filter'; import SelectFilterWithDefaultValue from 'examples/column-filter/select-filter-default-value'; import SelectFilterComparator from 'examples/column-filter/select-filter-like-comparator'; import CustomSelectFilter from 'examples/column-filter/custom-select-filter'; +import NumberFilter from 'examples/column-filter/number-filter'; +import NumberFilterWithDefaultValue from 'examples/column-filter/number-filter-default-value'; +import CustomNumberFilter from 'examples/column-filter/custom-number-filter'; // work on rows import RowStyleTable from 'examples/rows/row-style'; @@ -143,12 +146,15 @@ storiesOf('Column Filter', module) .add('Text Filter', () => ) .add('Text Filter with Default Value', () => ) .add('Text Filter with Comparator', () => ) - .add('Custom Text Filter', () => ) // add another filter type example right here. .add('Select Filter', () => ) .add('Select Filter with Default Value', () => ) .add('Select Filter with Comparator', () => ) + .add('Number Filter', () => ) + .add('Number Filter with Default Value', () => ) + .add('Custom Text Filter', () => ) .add('Custom Select Filter', () => ) + .add('Custom Number Filter', () => ) .add('Custom Filter Value', () => ); storiesOf('Work on Rows', module) From fc34ea12e668b60292ba73aca2a0d69c643e141a Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 10 Feb 2018 15:44:11 +0800 Subject: [PATCH 020/576] patch test for number filter --- .../test/components/number.test.js | 310 ++++++++++++++++++ .../test/filter.test.js | 114 ++++++- 2 files changed, 422 insertions(+), 2 deletions(-) create mode 100644 packages/react-bootstrap-table2-filter/test/components/number.test.js diff --git a/packages/react-bootstrap-table2-filter/test/components/number.test.js b/packages/react-bootstrap-table2-filter/test/components/number.test.js new file mode 100644 index 000000000..6ba66f7aa --- /dev/null +++ b/packages/react-bootstrap-table2-filter/test/components/number.test.js @@ -0,0 +1,310 @@ +import 'jsdom-global/register'; +import React from 'react'; +import sinon from 'sinon'; +import { mount } from 'enzyme'; +import NumberFilter from '../../src/components/number'; +import { FILTER_TYPE } from '../../src/const'; +import * as Comparator from '../../src/comparison'; + + +describe('Number Filter', () => { + let wrapper; + const onFilter = sinon.stub(); + const column = { + dataField: 'price', + text: 'Product Price' + }; + + afterEach(() => { + onFilter.reset(); + }); + + describe('initialization', () => { + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should have correct state', () => { + expect(wrapper.state().isSelected).toBeFalsy(); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('select')).toHaveLength(1); + expect(wrapper.find('input[type="number"]')).toHaveLength(1); + expect(wrapper.find('.number-filter')).toHaveLength(1); + }); + + it('should rendering comparator options correctly', () => { + const select = wrapper.find('select'); + expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length + 1); + }); + }); + + describe('when withoutEmptyComparatorOption prop is true', () => { + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering comparator options correctly', () => { + const select = wrapper.find('select'); + expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length); + }); + }); + + describe('when defaultValue.number props is defined', () => { + const number = 203; + + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering input successfully', () => { + expect(wrapper).toHaveLength(1); + const input = wrapper.find('input[type="number"]'); + expect(input).toHaveLength(1); + expect(input.props().defaultValue).toEqual(number); + }); + }); + + describe('when defaultValue.comparator props is defined', () => { + const comparator = Comparator.EQ; + + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering comparator select successfully', () => { + expect(wrapper).toHaveLength(1); + const select = wrapper.find('.number-filter-comparator'); + expect(select).toHaveLength(1); + expect(select.props().defaultValue).toEqual(comparator); + }); + }); + + describe('when defaultValue.number and defaultValue.comparator props is defined', () => { + const number = 203; + const comparator = Comparator.EQ; + + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should have correct state', () => { + expect(wrapper.state().isSelected).toBeTruthy(); + }); + + it('should calling onFilter on componentDidMount', () => { + expect(onFilter.calledOnce).toBeTruthy(); + expect(onFilter.calledWith( + column, { number: `${number}`, comparator }, FILTER_TYPE.NUMBER)).toBeTruthy(); + }); + }); + + describe('when options props is defined', () => { + const options = [2100, 2103, 2105]; + + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering number options instead of number input', () => { + expect(wrapper).toHaveLength(1); + const select = wrapper.find('.select-filter.placeholder-selected'); + expect(select).toHaveLength(1); + expect(select.find('option')).toHaveLength(options.length + 1); + }); + + describe('when withoutEmptyNumberOption props is defined', () => { + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering number options instead of number input', () => { + const select = wrapper.find('.select-filter.placeholder-selected'); + expect(select).toHaveLength(1); + expect(select.find('option')).toHaveLength(options.length); + }); + }); + + describe('when defaultValue.number props is defined', () => { + const number = 203; + + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering number options successfully', () => { + const select = wrapper.find('.select-filter.placeholder-selected'); + expect(select).toHaveLength(1); + expect(select.props().defaultValue).toEqual(number); + }); + }); + + describe('when defaultValue.number and defaultValue.comparator props is defined', () => { + const number = options[1]; + const comparator = Comparator.EQ; + + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering number options successfully', () => { + let select = wrapper.find('.placeholder-selected'); + expect(select).toHaveLength(0); + + select = wrapper.find('.select-filter'); + expect(select).toHaveLength(1); + }); + }); + }); + + describe('when style props is defined', () => { + const style = { backgroundColor: 'red' }; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('.number-filter').prop('style')).toEqual(style); + }); + }); + + describe('when numberStyle props is defined', () => { + const numberStyle = { backgroundColor: 'red' }; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('.number-filter-input').prop('style')).toEqual(numberStyle); + }); + }); + + describe('when comparatorStyle props is defined', () => { + const comparatorStyle = { backgroundColor: 'red' }; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('select').prop('style')).toEqual(comparatorStyle); + }); + }); + + describe('when className props is defined', () => { + const className = 'test'; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.hasClass(className)).toBeTruthy(); + }); + }); + + describe('when numberClassName props is defined', () => { + const className = 'test'; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('.number-filter-input').prop('className').indexOf(className) > -1).toBeTruthy(); + }); + }); + + describe('when comparatorClassName props is defined', () => { + const className = 'test'; + beforeEach(() => { + wrapper = mount( + + ); + }); + + it('should rendering component successfully', () => { + expect(wrapper).toHaveLength(1); + expect(wrapper.find('select').prop('className').indexOf(className) > -1).toBeTruthy(); + }); + }); +}); diff --git a/packages/react-bootstrap-table2-filter/test/filter.test.js b/packages/react-bootstrap-table2-filter/test/filter.test.js index e834f17b8..28be4a561 100644 --- a/packages/react-bootstrap-table2-filter/test/filter.test.js +++ b/packages/react-bootstrap-table2-filter/test/filter.test.js @@ -4,7 +4,7 @@ import Store from 'react-bootstrap-table-next/src/store'; import { filters } from '../src/filter'; import { FILTER_TYPE } from '../src/const'; -import { LIKE, EQ } from '../src/comparison'; +import { LIKE, EQ, GT, GE, LT, LE, NE } from '../src/comparison'; const data = []; for (let i = 0; i < 20; i += 1) { @@ -37,7 +37,7 @@ describe('filter', () => { }]; }); - describe('text filter', () => { + describe('filterByText', () => { beforeEach(() => { filterFn = filters(store, columns, _); }); @@ -91,4 +91,114 @@ describe('filter', () => { }); }); }); + + describe('filterByNumber', () => { + beforeEach(() => { + filterFn = filters(store, columns, _); + }); + + describe('when currFilters.filterVal.comparator is empty', () => { + it('should returning correct result', () => { + currFilters.price = { + filterVal: { comparator: '', number: '203' }, + filterType: FILTER_TYPE.NUMBER + }; + + let result = filterFn(currFilters); + expect(result).toHaveLength(data.length); + + currFilters.price.filterVal.comparator = undefined; + result = filterFn(currFilters); + expect(result).toHaveLength(data.length); + }); + }); + + describe('when currFilters.filterVal.number is empty', () => { + it('should returning correct result', () => { + currFilters.price = { + filterVal: { comparator: EQ, number: '' }, + filterType: FILTER_TYPE.NUMBER + }; + + const result = filterFn(currFilters); + expect(result).toHaveLength(data.length); + }); + }); + + describe(`when currFilters.filterVal.comparator is ${EQ}`, () => { + it('should returning correct result', () => { + currFilters.price = { + filterVal: { comparator: EQ, number: '203' }, + filterType: FILTER_TYPE.NUMBER + }; + + let result = filterFn(currFilters); + expect(result).toHaveLength(1); + + currFilters.price.filterVal.number = '0'; + result = filterFn(currFilters); + expect(result).toHaveLength(0); + }); + }); + + describe(`when currFilters.filterVal.comparator is ${GT}`, () => { + it('should returning correct result', () => { + currFilters.price = { + filterVal: { comparator: GT, number: '203' }, + filterType: FILTER_TYPE.NUMBER + }; + + const result = filterFn(currFilters); + expect(result).toHaveLength(16); + }); + }); + + describe(`when currFilters.filterVal.comparator is ${GE}`, () => { + it('should returning correct result', () => { + currFilters.price = { + filterVal: { comparator: GE, number: '203' }, + filterType: FILTER_TYPE.NUMBER + }; + + const result = filterFn(currFilters); + expect(result).toHaveLength(17); + }); + }); + + describe(`when currFilters.filterVal.comparator is ${LT}`, () => { + it('should returning correct result', () => { + currFilters.price = { + filterVal: { comparator: LT, number: '203' }, + filterType: FILTER_TYPE.NUMBER + }; + + const result = filterFn(currFilters); + expect(result).toHaveLength(3); + }); + }); + + describe(`when currFilters.filterVal.comparator is ${LE}`, () => { + it('should returning correct result', () => { + currFilters.price = { + filterVal: { comparator: LE, number: '203' }, + filterType: FILTER_TYPE.NUMBER + }; + + const result = filterFn(currFilters); + expect(result).toHaveLength(4); + }); + }); + + describe(`when currFilters.filterVal.comparator is ${NE}`, () => { + it('should returning correct result', () => { + currFilters.price = { + filterVal: { comparator: NE, number: '203' }, + filterType: FILTER_TYPE.NUMBER + }; + + const result = filterFn(currFilters); + expect(result).toHaveLength(19); + }); + }); + }); }); From f9217930e7b14583bec39adb503273de6fa6ab11 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 10 Feb 2018 16:04:17 +0800 Subject: [PATCH 021/576] patch docs for number filter --- docs/migration.md | 2 +- .../react-bootstrap-table2-filter/README.md | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/docs/migration.md b/docs/migration.md index fb294c300..65d104072 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -85,7 +85,7 @@ Please see [available filter configuration](https://react-bootstrap-table.github - [ ] Regex Filter - [x] Select Filter - [x] Custom Select Filter -- [ ] Number Filter +- [X] Number Filter - [ ] Date Filter - [ ] Array Filter - [ ] Programmatically Filter diff --git a/packages/react-bootstrap-table2-filter/README.md b/packages/react-bootstrap-table2-filter/README.md index 755741926..f98ecc799 100644 --- a/packages/react-bootstrap-table2-filter/README.md +++ b/packages/react-bootstrap-table2-filter/README.md @@ -18,6 +18,7 @@ You can get all types of filters via import and these filters are a factory func * TextFilter * SelectFilter +* NumberFilter * **Coming soon!** ## Add CSS @@ -107,5 +108,44 @@ const qualityFilter = selectFilter({ withoutEmptyOption: true // hide the default select option }); +// omit... +``` + +## Number Filter + +```js +import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter'; + +const columns = [..., { + dataField: 'price', + text: 'Product Price', + filter: numberFilter() +}]; + + +``` + +Numner filter is same as other filter, you can custom the number filter via `numberFilter` factory function: + +```js +import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter'; +// omit... + +const numberFilter = numberFilter({ + options: [2100, 2103, 2105], // if options defined, will render number select instead of number input + delay: 600, // how long will trigger filtering after user typing, default is 500 ms + placeholder: 'custom placeholder', // placeholder for number input + withoutEmptyComparatorOption: true, // dont render empty option for comparator + withoutEmptyNumberOption: true, // dont render empty option for numner select if it is defined + comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], // Custom the comparators + style: { display: 'inline-grid' }, // custom the style on number filter + className: 'custom-numberfilter-class', // custom the class on number filter + comparatorStyle: { backgroundColor: 'antiquewhite' }, // custom the style on comparator select + comparatorClassName: 'custom-comparator-class', // custom the class on comparator select + numberStyle: { backgroundColor: 'cadetblue', margin: '0px' }, // custom the style on number input/select + numberClassName: 'custom-number-class', // custom the class on ber input/select + defaultValue: { number: 2103, comparator: Comparator.GT } // default value +}) + // omit... ``` \ No newline at end of file From 65a596a0e95e0b524c096c8f764d683833501c5c Mon Sep 17 00:00:00 2001 From: makenova Date: Sat, 10 Feb 2018 00:17:45 -0800 Subject: [PATCH 022/576] case insensitive text filter (#190) * case insensitive text filter * optional case insensitive filter --- .../examples/column-filter/custom-text-filter.js | 4 ++-- .../src/components/text.js | 16 +++++++++++++--- .../react-bootstrap-table2-filter/src/filter.js | 7 +++++-- .../react-bootstrap-table2-filter/src/wrapper.js | 7 +++++-- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/custom-text-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/custom-text-filter.js index e4be0a81e..10e97d889 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/custom-text-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/custom-text-filter.js @@ -13,7 +13,7 @@ const columns = [{ }, { dataField: 'name', text: 'Product Name', - filter: textFilter() + filter: textFilter({ caseSensitive: true }) }, { dataField: 'price', text: 'Product Price', @@ -38,7 +38,7 @@ const columns = [{ }, { dataField: 'name', text: 'Product Name', - filter: textFilter() + filter: textFilter({ caseSensitive: true }) }, { dataField: 'price', text: 'Product Price', diff --git a/packages/react-bootstrap-table2-filter/src/components/text.js b/packages/react-bootstrap-table2-filter/src/components/text.js index 1c102c323..caa81994f 100644 --- a/packages/react-bootstrap-table2-filter/src/components/text.js +++ b/packages/react-bootstrap-table2-filter/src/components/text.js @@ -69,7 +69,15 @@ class TextFilter extends Component { } render() { - const { placeholder, column: { text }, style, className, onFilter, ...rest } = this.props; + const { + placeholder, + column: { text }, + style, + className, + onFilter, + caseSensitive, + ...rest + } = this.props; // stopPropagation for onClick event is try to prevent sort was triggered. return ( ( data, dataField, - { filterVal, comparator = LIKE }, + { filterVal, comparator = LIKE, caseSensitive }, customFilterValue ) => data.filter((row) => { @@ -18,7 +18,10 @@ export const filterByText = _ => ( if (comparator === EQ) { return cellStr === filterVal; } - return cellStr.indexOf(filterVal) > -1; + if (caseSensitive) { + return cellStr.toLocaleUpperCase().includes(filterVal.toLocaleUpperCase()); + } + return cellStr.includes(filterVal); }); export const filterByNumber = _ => ( diff --git a/packages/react-bootstrap-table2-filter/src/wrapper.js b/packages/react-bootstrap-table2-filter/src/wrapper.js index 3e6822a53..f48e0316d 100644 --- a/packages/react-bootstrap-table2-filter/src/wrapper.js +++ b/packages/react-bootstrap-table2-filter/src/wrapper.js @@ -49,8 +49,11 @@ export default (Base, { delete currFilters[dataField]; } else { // select default comparator is EQ, others are LIKE - const { comparator = (filterType === FILTER_TYPE.SELECT ? EQ : LIKE) } = filter.props; - currFilters[dataField] = { filterVal, filterType, comparator }; + const { + comparator = (filterType === FILTER_TYPE.SELECT ? EQ : LIKE), + caseSensitive = false + } = filter.props; + currFilters[dataField] = { filterVal, filterType, comparator, caseSensitive }; } store.filters = currFilters; From 865be93ef729ca53b58d1bca90dd3a92f86cbc2e Mon Sep 17 00:00:00 2001 From: Allen Date: Sat, 10 Feb 2018 16:54:01 +0800 Subject: [PATCH 023/576] refine caseSensitive for filter (#201) --- .../column-filter/custom-text-filter.js | 4 +- .../text-filter-caseSensitive.js | 51 +++++++++++++++++++ .../stories/index.js | 2 + .../react-bootstrap-table2-filter/README.md | 1 + .../src/components/select.js | 7 ++- .../src/filter.js | 6 +-- .../test/filter.test.js | 14 +++++ 7 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/text-filter-caseSensitive.js diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/custom-text-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/custom-text-filter.js index 10e97d889..e4be0a81e 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/custom-text-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/custom-text-filter.js @@ -13,7 +13,7 @@ const columns = [{ }, { dataField: 'name', text: 'Product Name', - filter: textFilter({ caseSensitive: true }) + filter: textFilter() }, { dataField: 'price', text: 'Product Price', @@ -38,7 +38,7 @@ const columns = [{ }, { dataField: 'name', text: 'Product Name', - filter: textFilter({ caseSensitive: true }) + filter: textFilter() }, { dataField: 'price', text: 'Product Price', diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/text-filter-caseSensitive.js b/packages/react-bootstrap-table2-example/examples/column-filter/text-filter-caseSensitive.js new file mode 100644 index 000000000..aa1f42135 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/text-filter-caseSensitive.js @@ -0,0 +1,51 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(8); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name', + filter: textFilter({ caseSensitive: true }) +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name', + filter: textFilter({ caseSensitive: true }) +}, { + dataField: 'price', + text: 'Product Price' +}]; + + +`; + +export default () => ( +
+

Product Name is case sensitive

+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index f4a000a73..39b52311a 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -37,6 +37,7 @@ import HeaderColumnAttrsTable from 'examples/header-columns/column-attrs-table'; import TextFilter from 'examples/column-filter/text-filter'; import TextFilterWithDefaultValue from 'examples/column-filter/text-filter-default-value'; import TextFilterComparator from 'examples/column-filter/text-filter-eq-comparator'; +import TextFilterCaseSensitive from 'examples/column-filter/text-filter-caseSensitive'; import CustomTextFilter from 'examples/column-filter/custom-text-filter'; import CustomFilterValue from 'examples/column-filter/custom-filter-value'; import SelectFilter from 'examples/column-filter/select-filter'; @@ -146,6 +147,7 @@ storiesOf('Column Filter', module) .add('Text Filter', () => ) .add('Text Filter with Default Value', () => ) .add('Text Filter with Comparator', () => ) + .add('Text Filter with Case Sensitive', () => ) // add another filter type example right here. .add('Select Filter', () => ) .add('Select Filter with Default Value', () => ) diff --git a/packages/react-bootstrap-table2-filter/README.md b/packages/react-bootstrap-table2-filter/README.md index f98ecc799..07561bfbd 100644 --- a/packages/react-bootstrap-table2-filter/README.md +++ b/packages/react-bootstrap-table2-filter/README.md @@ -59,6 +59,7 @@ const priceFilter = textFilter({ className: 'my-custom-text-filter', // custom classname on input defaultValue: 'test', // default filtering value comparator: Comparator.EQ, // default is Comparator.LIKE + caseSensitive: true, // default is false, and true will only work when comparator is LIKE style: { ... }, // your custom styles on input delay: 1000 // how long will trigger filtering after user typing, default is 500 ms }); diff --git a/packages/react-bootstrap-table2-filter/src/components/select.js b/packages/react-bootstrap-table2-filter/src/components/select.js index 0374280f2..7e17afd7a 100644 --- a/packages/react-bootstrap-table2-filter/src/components/select.js +++ b/packages/react-bootstrap-table2-filter/src/components/select.js @@ -89,6 +89,7 @@ class SelectFilter extends Component { options, comparator, withoutEmptyOption, + caseSensitive, ...rest } = this.props; @@ -119,14 +120,16 @@ SelectFilter.propTypes = { style: PropTypes.object, className: PropTypes.string, withoutEmptyOption: PropTypes.bool, - defaultValue: PropTypes.any + defaultValue: PropTypes.any, + caseSensitive: PropTypes.bool }; SelectFilter.defaultProps = { defaultValue: '', className: '', withoutEmptyOption: false, - comparator: EQ + comparator: EQ, + caseSensitive: true }; export default SelectFilter; diff --git a/packages/react-bootstrap-table2-filter/src/filter.js b/packages/react-bootstrap-table2-filter/src/filter.js index 7ac043ed9..f16674228 100644 --- a/packages/react-bootstrap-table2-filter/src/filter.js +++ b/packages/react-bootstrap-table2-filter/src/filter.js @@ -6,7 +6,7 @@ import { LIKE, EQ, NE, GT, GE, LT, LE } from './comparison'; export const filterByText = _ => ( data, dataField, - { filterVal, comparator = LIKE, caseSensitive }, + { filterVal = '', comparator = LIKE, caseSensitive }, customFilterValue ) => data.filter((row) => { @@ -19,9 +19,9 @@ export const filterByText = _ => ( return cellStr === filterVal; } if (caseSensitive) { - return cellStr.toLocaleUpperCase().includes(filterVal.toLocaleUpperCase()); + return cellStr.includes(filterVal); } - return cellStr.includes(filterVal); + return cellStr.toLocaleUpperCase().includes(filterVal.toLocaleUpperCase()); }); export const filterByNumber = _ => ( diff --git a/packages/react-bootstrap-table2-filter/test/filter.test.js b/packages/react-bootstrap-table2-filter/test/filter.test.js index 28be4a561..ae66a38c9 100644 --- a/packages/react-bootstrap-table2-filter/test/filter.test.js +++ b/packages/react-bootstrap-table2-filter/test/filter.test.js @@ -55,6 +55,20 @@ describe('filter', () => { }); }); + describe('when caseSensitive is true', () => { + it('should returning correct result', () => { + currFilters.name = { + filterVal: 'NAME', + caseSensitive: true, + filterType: FILTER_TYPE.TEXT + }; + + const result = filterFn(currFilters); + expect(result).toBeDefined(); + expect(result).toHaveLength(0); + }); + }); + describe(`when default comparator is ${EQ}`, () => { it('should returning correct result', () => { currFilters.name = { From a0af964d76c3643c212a81c68e91970afd16d536 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 10 Feb 2018 17:00:29 +0800 Subject: [PATCH 024/576] fix #195 --- packages/react-bootstrap-table2-filter/src/components/text.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-bootstrap-table2-filter/src/components/text.js b/packages/react-bootstrap-table2-filter/src/components/text.js index caa81994f..ffbe70272 100644 --- a/packages/react-bootstrap-table2-filter/src/components/text.js +++ b/packages/react-bootstrap-table2-filter/src/components/text.js @@ -76,6 +76,7 @@ class TextFilter extends Component { className, onFilter, caseSensitive, + defaultValue, ...rest } = this.props; // stopPropagation for onClick event is try to prevent sort was triggered. From e7ccd4781733ec4fd120c12b6a55d0457bb96ff5 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 10 Feb 2018 17:42:44 +0800 Subject: [PATCH 025/576] implement sort events listener --- docs/columns.md | 14 ++++ docs/migration.md | 1 + .../react-bootstrap-table2/src/header-cell.js | 1 + .../src/sort/wrapper.js | 8 +++ .../test/sort/wrapper.test.js | 71 ++++++++++++++++--- 5 files changed, 84 insertions(+), 11 deletions(-) diff --git a/docs/columns.md b/docs/columns.md index cf546a872..b80c48a67 100644 --- a/docs/columns.md +++ b/docs/columns.md @@ -12,6 +12,7 @@ Available properties in a column object: * [formatExtraData](#formatExtraData) * [sort](#sort) * [sortFunc](#sortFunc) +* [onSort](#onSort) * [classes](#classes) * [style](#style) * [title](#title) @@ -122,6 +123,19 @@ Enable the column sort via a `true` value given. ``` > The possible value of `order` argument is **`asc`** and **`desc`**. +## column.onSort - [Function] +`column.onSort` is an event listener for sort change event: + +```js +{ + // omit... + sort: true, + onSort: (field, order) => { + // .... + } +} +``` + ## column.classes - [String | Function] It's availabe to have custom class on table column: diff --git a/docs/migration.md b/docs/migration.md index 65d104072..ae009e4f3 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -60,6 +60,7 @@ Please see [Work with table sort](https://react-bootstrap-table.github.io/react- - [x] Default Sort - [x] Remote mode - [x] Custom the sorting header +- [x] Sort event listener - [ ] Custom the sort caret - [ ] Sort management - [ ] Multi sort diff --git a/packages/react-bootstrap-table2/src/header-cell.js b/packages/react-bootstrap-table2/src/header-cell.js index d5dd47b92..b6af21eeb 100644 --- a/packages/react-bootstrap-table2/src/header-cell.js +++ b/packages/react-bootstrap-table2/src/header-cell.js @@ -131,6 +131,7 @@ HeaderCell.propTypes = { attrs: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), sort: PropTypes.bool, sortFunc: PropTypes.func, + onSort: PropTypes.func, editable: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]), editCellStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), editCellClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), diff --git a/packages/react-bootstrap-table2/src/sort/wrapper.js b/packages/react-bootstrap-table2/src/sort/wrapper.js index 45414e31f..90a9bb92b 100644 --- a/packages/react-bootstrap-table2/src/sort/wrapper.js +++ b/packages/react-bootstrap-table2/src/sort/wrapper.js @@ -25,6 +25,10 @@ export default Base => if (column.length > 0) { store.setSort(column[0], order); + if (column[0].onSort) { + column[0].onSort(store.sortField, store.sortOrder); + } + if (this.isRemoteSort() || this.isRemotePagination()) { this.handleSortChange(); } else { @@ -48,6 +52,10 @@ export default Base => const { store } = this.props; store.setSort(column); + if (column.onSort) { + column.onSort(store.sortField, store.sortOrder); + } + if (this.isRemoteSort() || this.isRemotePagination()) { this.handleSortChange(); } else { diff --git a/packages/react-bootstrap-table2/test/sort/wrapper.test.js b/packages/react-bootstrap-table2/test/sort/wrapper.test.js index d8a3ce702..1c28b8ca1 100644 --- a/packages/react-bootstrap-table2/test/sort/wrapper.test.js +++ b/packages/react-bootstrap-table2/test/sort/wrapper.test.js @@ -10,16 +10,7 @@ import wrapperFactory from '../../src/sort/wrapper'; describe('SortWrapper', () => { let wrapper; - - const columns = [{ - dataField: 'id', - text: 'ID', - sort: true - }, { - dataField: 'name', - text: 'Name', - sort: true - }]; + let columns; const data = [{ id: 1, @@ -37,6 +28,15 @@ describe('SortWrapper', () => { const SortWrapper = wrapperFactory(BootstrapTable); beforeEach(() => { + columns = [{ + dataField: 'id', + text: 'ID', + sort: true + }, { + dataField: 'name', + text: 'Name', + sort: true + }]; wrapper = shallow( { describe('call handleSort function', () => { let sortBySpy; - const sortColumn = columns[0]; + let sortColumn; beforeEach(() => { + sortColumn = columns[0]; store = new Store(keyField); store.data = data; sortBySpy = sinon.spy(store, 'sortBy'); @@ -130,6 +131,32 @@ describe('SortWrapper', () => { expect(onTableChangeCB.calledOnce).toBeTruthy(); }); }); + + describe('when column.onSort prop is defined', () => { + const onSortCB = jest.fn(); + + beforeEach(() => { + columns[0].onSort = onSortCB; + wrapper = shallow( + + ); + wrapper.instance().handleSort(sortColumn); + }); + + it('should calling column.onSort function correctly', () => { + expect(onSortCB).toHaveBeenCalledTimes(1); + expect(onSortCB).toHaveBeenCalledWith(columns[0].dataField, Const.SORT_DESC); + + wrapper.instance().handleSort(sortColumn); + expect(onSortCB).toHaveBeenCalledTimes(2); + expect(onSortCB).toHaveBeenCalledWith(columns[0].dataField, Const.SORT_ASC); + }); + }); }); describe('when defaultSorted prop is defined', () => { @@ -161,6 +188,28 @@ describe('SortWrapper', () => { it('should update store.sortOrder correctly', () => { expect(store.sortOrder).toEqual(defaultSorted[0].order); }); + + describe('when column.onSort prop is defined', () => { + const onSortCB = jest.fn(); + + beforeEach(() => { + columns[1].onSort = onSortCB; + wrapper = shallow( + + ); + }); + + it('should calling column.onSort function correctly', () => { + expect(onSortCB).toHaveBeenCalledTimes(1); + expect(onSortCB).toHaveBeenCalledWith(defaultSorted[0].dataField, defaultSorted[0].order); + }); + }); }); describe('componentWillReceiveProps', () => { From ba24990994148e8221d656bd484c3e9e986843b1 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 10 Feb 2018 17:42:59 +0800 Subject: [PATCH 026/576] add story for sort event listener --- .../examples/sort/sort-events.js | 58 +++++++++++++++++++ .../stories/index.js | 2 + 2 files changed, 60 insertions(+) create mode 100644 packages/react-bootstrap-table2-example/examples/sort/sort-events.js diff --git a/packages/react-bootstrap-table2-example/examples/sort/sort-events.js b/packages/react-bootstrap-table2-example/examples/sort/sort-events.js new file mode 100644 index 000000000..06b406ff6 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/sort/sort-events.js @@ -0,0 +1,58 @@ +/* eslint no-console: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(); + +const columns = [{ + dataField: 'id', + text: 'Product ID', + sort: true +}, { + dataField: 'name', + text: 'Product Name', + sort: true, + onSort: (field, order) => { + console.log(`Sort Field: ${field}, Sort Order: ${order}`); + } +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const defaultSorted = [{ + dataField: 'name', + order: 'desc' +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const columns = [{ + dataField: 'id', + text: 'Product ID', + sort: true +}, { + dataField: 'name', + text: 'Product Name', + sort: true, + onSort: (field, order) => { + console.log(....); + } +}, { + dataField: 'price', + text: 'Product Price' +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 39b52311a..09bce470c 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -56,6 +56,7 @@ import RowEventTable from 'examples/rows/row-event'; // table sort import EnableSortTable from 'examples/sort/enable-sort-table'; import DefaultSortTable from 'examples/sort/default-sort-table'; +import SortEvents from 'examples/sort/sort-events'; import CustomSortTable from 'examples/sort/custom-sort-table'; import HeaderSortingClassesTable from 'examples/sort/header-sorting-classes'; import HeaderSortingStyleTable from 'examples/sort/header-sorting-style'; @@ -167,6 +168,7 @@ storiesOf('Work on Rows', module) storiesOf('Sort Table', module) .add('Enable Sort', () => ) .add('Default Sort Table', () => ) + .add('Sort Events', () => ) .add('Custom Sort Fuction', () => ) .add('Custom Classes on Sorting Header Column', () => ) .add('Custom Style on Sorting Header Column', () => ); From 096799c403fd56ffb8950fa319320d849737299a Mon Sep 17 00:00:00 2001 From: AllenFang Date: Wed, 14 Feb 2018 16:33:51 +0800 Subject: [PATCH 027/576] Publish - react-bootstrap-table2-example@0.1.2 - react-bootstrap-table2-filter@0.1.3 - react-bootstrap-table-next@0.1.3 --- packages/react-bootstrap-table2-example/package.json | 2 +- packages/react-bootstrap-table2-filter/package.json | 2 +- packages/react-bootstrap-table2/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-bootstrap-table2-example/package.json b/packages/react-bootstrap-table2-example/package.json index 186886107..684997e44 100644 --- a/packages/react-bootstrap-table2-example/package.json +++ b/packages/react-bootstrap-table2-example/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-example", - "version": "0.1.1", + "version": "0.1.2", "description": "", "main": "index.js", "private": true, diff --git a/packages/react-bootstrap-table2-filter/package.json b/packages/react-bootstrap-table2-filter/package.json index 0b1a96957..77dd46812 100644 --- a/packages/react-bootstrap-table2-filter/package.json +++ b/packages/react-bootstrap-table2-filter/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-filter", - "version": "0.1.2", + "version": "0.1.3", "description": "it's a column filter addon for react-bootstrap-table2", "main": "./lib/index.js", "repository": { diff --git a/packages/react-bootstrap-table2/package.json b/packages/react-bootstrap-table2/package.json index 29fb85305..e7a5a1910 100644 --- a/packages/react-bootstrap-table2/package.json +++ b/packages/react-bootstrap-table2/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table-next", - "version": "0.1.2", + "version": "0.1.3", "description": "Next generation of react-bootstrap-table", "main": "./lib/index.js", "repository": { From a8083ac17d4a19e9feb25e32ceb33177998d270f Mon Sep 17 00:00:00 2001 From: Parth Prajapati Date: Sat, 24 Feb 2018 20:23:52 +0530 Subject: [PATCH 028/576] Fixes #186 (#219) * Fixes #186 * Solved lint error --- packages/react-bootstrap-table2/src/bootstrap-table.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index 4834ec01d..dae389335 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -70,10 +70,12 @@ class BootstrapTable extends PropsBaseResolver(Component) { allRowsSelected: isSelectedAll(store) }); + const tableCaption = (caption && { caption }); + return (
- + { tableCaption }
Date: Sat, 24 Feb 2018 23:03:09 +0800 Subject: [PATCH 029/576] fix #221 --- packages/react-bootstrap-table2-editor/src/text-editor.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/react-bootstrap-table2-editor/src/text-editor.js b/packages/react-bootstrap-table2-editor/src/text-editor.js index 52233e7f4..7937282b6 100644 --- a/packages/react-bootstrap-table2-editor/src/text-editor.js +++ b/packages/react-bootstrap-table2-editor/src/text-editor.js @@ -32,9 +32,10 @@ TextEditor.propTypes = { defaultValue: PropTypes.oneOfType([ PropTypes.string, PropTypes.number - ]).isRequired + ]) }; TextEditor.defaultProps = { - className: null + className: null, + defaultValue: '' }; export default TextEditor; From 931cf8045045c3fdb7ce8e3945ebac76f9730965 Mon Sep 17 00:00:00 2001 From: Parth Prajapati Date: Sat, 24 Feb 2018 20:23:52 +0530 Subject: [PATCH 030/576] Fixes #186 (#219) * Fixes #186 * Solved lint error --- packages/react-bootstrap-table2/src/bootstrap-table.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index 4834ec01d..dae389335 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -70,10 +70,12 @@ class BootstrapTable extends PropsBaseResolver(Component) { allRowsSelected: isSelectedAll(store) }); + const tableCaption = (caption &&
); + return (
{ caption }{ caption }
- + { tableCaption }
Date: Sat, 24 Feb 2018 23:03:09 +0800 Subject: [PATCH 031/576] fix #221 --- packages/react-bootstrap-table2-editor/src/text-editor.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/react-bootstrap-table2-editor/src/text-editor.js b/packages/react-bootstrap-table2-editor/src/text-editor.js index 52233e7f4..7937282b6 100644 --- a/packages/react-bootstrap-table2-editor/src/text-editor.js +++ b/packages/react-bootstrap-table2-editor/src/text-editor.js @@ -32,9 +32,10 @@ TextEditor.propTypes = { defaultValue: PropTypes.oneOfType([ PropTypes.string, PropTypes.number - ]).isRequired + ]) }; TextEditor.defaultProps = { - className: null + className: null, + defaultValue: '' }; export default TextEditor; From a11913c49a10b80a31c35a2c2b02e075b8ed3e61 Mon Sep 17 00:00:00 2001 From: Allen Date: Sun, 4 Mar 2018 16:21:10 +0800 Subject: [PATCH 032/576] fix #210 (#232) --- .../examples/sort/enable-sort-table.js | 31 +++++++++++++++---- .../src/sort/wrapper.js | 10 +++--- .../test/sort/wrapper.test.js | 26 +++------------- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/sort/enable-sort-table.js b/packages/react-bootstrap-table2-example/examples/sort/enable-sort-table.js index 16e628f97..7d0d406c4 100644 --- a/packages/react-bootstrap-table2-example/examples/sort/enable-sort-table.js +++ b/packages/react-bootstrap-table2-example/examples/sort/enable-sort-table.js @@ -38,9 +38,28 @@ const columns = [{ `; -export default () => ( -
- - { sourceCode } -
-); +export default class Test extends React.Component { + constructor(props) { + super(props); + this.state = { data: products }; + } + + handleClick = () => { + this.setState(() => { + const newProducts = productsGenerator(21); + return { + data: newProducts + }; + }); + } + + render() { + return ( +
+ + + { sourceCode } +
+ ); + } +} diff --git a/packages/react-bootstrap-table2/src/sort/wrapper.js b/packages/react-bootstrap-table2/src/sort/wrapper.js index 90a9bb92b..71c50511c 100644 --- a/packages/react-bootstrap-table2/src/sort/wrapper.js +++ b/packages/react-bootstrap-table2/src/sort/wrapper.js @@ -39,12 +39,10 @@ export default Base => } componentWillReceiveProps(nextProps) { - if (nextProps.isDataChanged) { - const sortedColumn = nextProps.columns.find( - column => column.dataField === nextProps.store.sortField); - if (sortedColumn) { - nextProps.store.sortBy(sortedColumn); - } + const sortedColumn = nextProps.columns.find( + column => column.dataField === nextProps.store.sortField); + if (sortedColumn && sortedColumn.sort) { + nextProps.store.sortBy(sortedColumn); } } diff --git a/packages/react-bootstrap-table2/test/sort/wrapper.test.js b/packages/react-bootstrap-table2/test/sort/wrapper.test.js index 1c28b8ca1..2575e8676 100644 --- a/packages/react-bootstrap-table2/test/sort/wrapper.test.js +++ b/packages/react-bootstrap-table2/test/sort/wrapper.test.js @@ -219,30 +219,12 @@ describe('SortWrapper', () => { nextProps = { columns, store }; store.sortField = columns[1].dataField; store.sortOrder = Const.SORT_DESC; + store.sortBy = sinon.stub(); }); - describe('if nextProps.isDataChanged is true', () => { - beforeEach(() => { - nextProps.isDataChanged = true; - store.sortBy = sinon.stub(); - }); - - it('should sorting again', () => { - wrapper.instance().componentWillReceiveProps(nextProps); - expect(store.sortBy.calledOnce).toBeTruthy(); - }); - }); - - describe('if nextProps.isDataChanged is false', () => { - beforeEach(() => { - nextProps.isDataChanged = false; - store.sortBy = sinon.stub(); - }); - - it('should not sorting', () => { - wrapper.instance().componentWillReceiveProps(nextProps); - expect(store.sortBy.calledOnce).toBeFalsy(); - }); + it('should sorting again', () => { + wrapper.instance().componentWillReceiveProps(nextProps); + expect(store.sortBy.calledOnce).toBeTruthy(); }); }); }); From 9382ed587b3bf30623a03c6a0b11f05d7013b065 Mon Sep 17 00:00:00 2001 From: Allen Date: Sun, 4 Mar 2018 17:22:52 +0800 Subject: [PATCH 033/576] implement row event delegater (#233) --- .../src/row-event-delegater.js | 84 +++++++++++++++++++ packages/react-bootstrap-table2/src/row.js | 72 +--------------- .../react-bootstrap-table2/test/row.test.js | 6 +- 3 files changed, 92 insertions(+), 70 deletions(-) create mode 100644 packages/react-bootstrap-table2/src/row-event-delegater.js diff --git a/packages/react-bootstrap-table2/src/row-event-delegater.js b/packages/react-bootstrap-table2/src/row-event-delegater.js new file mode 100644 index 000000000..a35de461e --- /dev/null +++ b/packages/react-bootstrap-table2/src/row-event-delegater.js @@ -0,0 +1,84 @@ +import _ from './utils'; + +const events = [ + 'onClick', + 'onMouseEnter', + 'onMouseLeave' +]; + +export default ExtendBase => + class RowEventDelegater extends ExtendBase { + constructor(props) { + super(props); + this.clickNum = 0; + this.createDefaultEventHandler = this.createDefaultEventHandler.bind(this); + this.createClickEventHandler = this.createClickEventHandler.bind(this); + } + + createDefaultEventHandler(cb) { + return (e) => { + const { row, rowIndex } = this.props; + cb(e, row, rowIndex); + }; + } + + createClickEventHandler(cb) { + return (e) => { + const { + row, + selected, + keyField, + selectable, + rowIndex, + selectRow: { + onRowSelect, + clickToEdit + }, + cellEdit: { + mode, + DBCLICK_TO_CELL_EDIT, + DELAY_FOR_DBCLICK + } + } = this.props; + + const clickFn = () => { + if (cb) { + cb(e, row, rowIndex); + } + if (selectable) { + const key = _.get(row, keyField); + onRowSelect(key, !selected, rowIndex); + } + }; + + if (mode === DBCLICK_TO_CELL_EDIT && clickToEdit) { + this.clickNum += 1; + _.debounce(() => { + if (this.clickNum === 1) { + clickFn(); + } + this.clickNum = 0; + }, DELAY_FOR_DBCLICK)(); + } else { + clickFn(); + } + }; + } + + delegate(attrs = {}) { + const newAttrs = {}; + if (this.props.selectRow && this.props.selectRow.clickToSelect) { + newAttrs.onClick = this.createClickEventHandler(attrs.onClick); + } + Object.keys(attrs).forEach((attr) => { + if (!newAttrs[attr]) { + if (events.includes(attr)) { + newAttrs[attr] = this.createDefaultEventHandler(attrs[attr]); + } else { + newAttrs[attr] = attrs[attr]; + } + } + }); + return newAttrs; + } + }; diff --git a/packages/react-bootstrap-table2/src/row.js b/packages/react-bootstrap-table2/src/row.js index 1b5562864..7b1df3750 100644 --- a/packages/react-bootstrap-table2/src/row.js +++ b/packages/react-bootstrap-table2/src/row.js @@ -6,68 +6,10 @@ import PropTypes from 'prop-types'; import _ from './utils'; import Cell from './cell'; import SelectionCell from './row-selection/selection-cell'; +import eventDelegater from './row-event-delegater'; import Const from './const'; -class Row extends Component { - constructor(props) { - super(props); - this.clickNum = 0; - this.handleRowClick = this.handleRowClick.bind(this); - this.handleSimpleRowClick = this.handleSimpleRowClick.bind(this); - } - - handleRowClick(e) { - const { - row, - selected, - keyField, - selectable, - rowIndex, - selectRow: { - onRowSelect, - clickToEdit - }, - cellEdit: { - mode, - DBCLICK_TO_CELL_EDIT, - DELAY_FOR_DBCLICK - }, - attrs - } = this.props; - - const clickFn = () => { - if (attrs.onClick) { - attrs.onClick(e, row, rowIndex); - } - if (selectable) { - const key = _.get(row, keyField); - onRowSelect(key, !selected, rowIndex); - } - }; - - if (mode === DBCLICK_TO_CELL_EDIT && clickToEdit) { - this.clickNum += 1; - _.debounce(() => { - if (this.clickNum === 1) { - clickFn(); - } - this.clickNum = 0; - }, DELAY_FOR_DBCLICK)(); - } else { - clickFn(); - } - } - - handleSimpleRowClick(e) { - const { - row, - rowIndex, - attrs - } = this.props; - - attrs.onClick(e, row, rowIndex); - } - +class Row extends eventDelegater(Component) { render() { const { row, @@ -96,14 +38,8 @@ class Row extends Component { } = cellEdit; const key = _.get(row, keyField); - const { clickToSelect, hideSelectColumn } = selectRow; - - const trAttrs = { ...attrs }; - if (clickToSelect) { - trAttrs.onClick = this.handleRowClick; - } else if (attrs.onClick) { - trAttrs.onClick = this.handleSimpleRowClick; - } + const { hideSelectColumn } = selectRow; + const trAttrs = this.delegate(attrs); return (
diff --git a/packages/react-bootstrap-table2/test/row.test.js b/packages/react-bootstrap-table2/test/row.test.js index 955a42151..02cc06837 100644 --- a/packages/react-bootstrap-table2/test/row.test.js +++ b/packages/react-bootstrap-table2/test/row.test.js @@ -799,8 +799,10 @@ describe('Row', () => { selected selectable />); - wrapper.instance().handleRowClick(); - wrapper.instance().handleRowClick(); + // console.log(wrapper.instance()); + const rowClick = wrapper.instance().createClickEventHandler(); + rowClick(); + rowClick(); }); it('should increase clickNum as 2', () => { From a5cb806d9851c1f45c2cf770e4d4e036f8ea2a0d Mon Sep 17 00:00:00 2001 From: Allen Date: Mon, 5 Mar 2018 22:27:46 +0800 Subject: [PATCH 034/576] implement default selection (#234) --- docs/row-selection.md | 11 ++++ .../examples/row-selection/default-select.js | 59 +++++++++++++++++++ .../stories/index.js | 2 + .../src/row-selection/wrapper.js | 11 ++++ .../test/row-selection/wrapper.test.js | 36 +++++++++-- 5 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/row-selection/default-select.js diff --git a/docs/row-selection.md b/docs/row-selection.md index e50ef838c..c877e6b19 100644 --- a/docs/row-selection.md +++ b/docs/row-selection.md @@ -6,6 +6,7 @@ * [mode (**required**)](#mode) ## Optional +* [selected](#selected) * [style](#style) * [classes)](#classes) * [bgColor](#bgColor) @@ -52,6 +53,16 @@ const selectRow = { /> ``` +### selectRow.selected - [Array] +`selectRow.selected` allow you have default selections on table. + +```js +const selectRow = { + mode: 'checkbox', + selected: [1, 3] // should be a row keys array +}; +``` + ### selectRow.style - [Object | Function] `selectRow.style` allow you to have custom style on selected rows: diff --git a/packages/react-bootstrap-table2-example/examples/row-selection/default-select.js b/packages/react-bootstrap-table2-example/examples/row-selection/default-select.js new file mode 100644 index 000000000..d11a68831 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/row-selection/default-select.js @@ -0,0 +1,59 @@ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const selectRow = { + mode: 'checkbox', + clickToSelect: true, + selected: [1, 3] +}; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const selectRow = { + mode: 'checkbox', + clickToSelect: true, + selected: [1, 3] +}; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 09bce470c..b7444a741 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -77,6 +77,7 @@ import CellEditClassTable from 'examples/cell-edit/cell-edit-class-table'; import SingleSelectionTable from 'examples/row-selection/single-selection'; import MultipleSelectionTable from 'examples/row-selection/multiple-selection'; import ClickToSelectTable from 'examples/row-selection/click-to-select'; +import DefaultSelectTable from 'examples/row-selection/default-select'; import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-select-with-cell-edit'; import SelectionStyleTable from 'examples/row-selection/selection-style'; import SelectionClassTable from 'examples/row-selection/selection-class'; @@ -189,6 +190,7 @@ storiesOf('Row Selection', module) .add('Single Selection', () => ) .add('Multiple Selection', () => ) .add('Click to Select', () => ) + .add('Default Select', () => ) .add('Click to Select and Edit Cell', () => ) .add('Selection Style', () => ) .add('Selection Class', () => ) diff --git a/packages/react-bootstrap-table2/src/row-selection/wrapper.js b/packages/react-bootstrap-table2/src/row-selection/wrapper.js index 442cb18cb..b8c79bd97 100644 --- a/packages/react-bootstrap-table2/src/row-selection/wrapper.js +++ b/packages/react-bootstrap-table2/src/row-selection/wrapper.js @@ -1,3 +1,4 @@ +/* eslint no-param-reassign: 0 */ import React, { Component } from 'react'; import PropTypes from 'prop-types'; @@ -21,11 +22,21 @@ export default Base => super(props); this.handleRowSelect = this.handleRowSelect.bind(this); this.handleAllRowsSelect = this.handleAllRowsSelect.bind(this); + props.store.selected = this.props.selectRow.selected || []; this.state = { selectedRowKeys: props.store.selected }; } + componentWillReceiveProps(nextProps) { + if (nextProps.selectRow) { + this.store.selected = nextProps.selectRow.selected || []; + this.setState(() => ({ + selectedRowKeys: this.store.selected + })); + } + } + /** * row selection handler * @param {String} rowKey - row key of what was selected. diff --git a/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js b/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js index fba2c676c..278a54e52 100644 --- a/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js +++ b/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js @@ -8,6 +8,7 @@ import wrapperFactory from '../../src/row-selection/wrapper'; describe('RowSelectionWrapper', () => { let wrapper; + let selectRow; const columns = [{ dataField: 'id', @@ -25,10 +26,6 @@ describe('RowSelectionWrapper', () => { name: 'B' }]; - const selectRow = { - mode: 'radio' - }; - const rowIndex = 1; const keyField = 'id'; @@ -38,6 +35,9 @@ describe('RowSelectionWrapper', () => { const RowSelectionWrapper = wrapperFactory(BootstrapTable); beforeEach(() => { + selectRow = { + mode: 'radio' + }; wrapper = shallow( { expect(wrapper.find(BootstrapTable)).toBeDefined(); }); + it('should have correct store.selected value', () => { + expect(store.selected).toEqual([]); + }); + it('should have correct state', () => { expect(wrapper.state().selectedRowKeys).toBeDefined(); expect(wrapper.state().selectedRowKeys.length).toEqual(0); @@ -64,6 +68,30 @@ describe('RowSelectionWrapper', () => { expect(wrapper.props().onAllRowsSelect).toBeDefined(); }); + describe('when selectRow.selected is defiend', () => { + beforeEach(() => { + selectRow.mode = 'checkbox'; + selectRow.selected = [1, 3]; + wrapper = shallow( + + ); + }); + + it('should have correct store.selected value', () => { + expect(store.selected).toEqual(selectRow.selected); + }); + + it('should have correct state', () => { + expect(wrapper.state().selectedRowKeys).toEqual(selectRow.selected); + }); + }); + describe('when selectRow.mode is \'radio\'', () => { const firstSelectedRow = data[0][keyField]; const secondSelectedRow = data[1][keyField]; From 4011cae18e8e8bf632671647ad950e8b3209e2c1 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Tue, 6 Mar 2018 23:59:04 +0800 Subject: [PATCH 035/576] Publish --- packages/react-bootstrap-table2-editor/package.json | 2 +- packages/react-bootstrap-table2-example/package.json | 2 +- packages/react-bootstrap-table2/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-bootstrap-table2-editor/package.json b/packages/react-bootstrap-table2-editor/package.json index 726e4345f..ded23c816 100644 --- a/packages/react-bootstrap-table2-editor/package.json +++ b/packages/react-bootstrap-table2-editor/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-editor", - "version": "0.1.1", + "version": "0.1.2", "description": "it's the editor addon for react-bootstrap-table2", "main": "./lib/index.js", "scripts": { diff --git a/packages/react-bootstrap-table2-example/package.json b/packages/react-bootstrap-table2-example/package.json index 684997e44..b7e59dd28 100644 --- a/packages/react-bootstrap-table2-example/package.json +++ b/packages/react-bootstrap-table2-example/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-example", - "version": "0.1.2", + "version": "0.1.3", "description": "", "main": "index.js", "private": true, diff --git a/packages/react-bootstrap-table2/package.json b/packages/react-bootstrap-table2/package.json index e7a5a1910..983bd57f3 100644 --- a/packages/react-bootstrap-table2/package.json +++ b/packages/react-bootstrap-table2/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table-next", - "version": "0.1.3", + "version": "0.1.4", "description": "Next generation of react-bootstrap-table", "main": "./lib/index.js", "repository": { From 9f9203bffabab94e8e7fc65eae0141eb9be21196 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sat, 10 Mar 2018 18:54:26 +0800 Subject: [PATCH 036/576] implement customized classes and id on the table --- packages/react-bootstrap-table2/src/bootstrap-table.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index dae389335..743eb3b00 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -42,6 +42,8 @@ class BootstrapTable extends PropsBaseResolver(Component) { store, columns, keyField, + id, + classes, striped, hover, bordered, @@ -58,7 +60,7 @@ class BootstrapTable extends PropsBaseResolver(Component) { 'table-hover': hover, 'table-bordered': bordered, 'table-condensed': condensed - }); + }, classes); const cellSelectionInfo = this.resolveSelectRowProps({ onRowSelect: this.props.onRowSelect @@ -74,7 +76,7 @@ class BootstrapTable extends PropsBaseResolver(Component) { return (
-
{ caption }
+
{ tableCaption }
Date: Sat, 10 Mar 2018 18:54:41 +0800 Subject: [PATCH 037/576] [test] test for customized classes and id --- .../test/bootstrap-table.test.js | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/packages/react-bootstrap-table2/test/bootstrap-table.test.js b/packages/react-bootstrap-table2/test/bootstrap-table.test.js index 3e5e0e1fa..682dc735e 100644 --- a/packages/react-bootstrap-table2/test/bootstrap-table.test.js +++ b/packages/react-bootstrap-table2/test/bootstrap-table.test.js @@ -46,8 +46,50 @@ describe('BootstrapTable', () => { expect(wrapper.state().data).toEqual(store.data); }); - it('should have table-bordered class as default', () => { - expect(wrapper.find('table.table-bordered').length).toBe(1); + it("should only have classes 'table' and 'table-bordered' as default", () => { + expect(wrapper.find('table').prop('className')).toBe('table table-bordered'); + }); + + it('should not have customized id as default', () => { + expect(wrapper.find('table').prop('id')).toBeUndefined(); + }); + }); + + describe('when props.classes was defined', () => { + const classes = 'foo'; + + beforeEach(() => { + wrapper = shallow( + ); + }); + + it('should display customized classes correctly', () => { + expect(wrapper.find(`table.${classes}`).length).toBe(1); + }); + }); + + describe('when props.id was defined', () => { + const id = 'foo'; + + beforeEach(() => { + wrapper = shallow( + ); + }); + + it('should display customized id correctly', () => { + expect(wrapper.find(`table#${id}`).length).toBe(1); }); }); From 8a8c2d49643335baafaadb58ec0eb71745c8c249 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sat, 10 Mar 2018 18:54:59 +0800 Subject: [PATCH 038/576] [example] add demo for customized classes and id table --- .../examples/basic/customized-id-classes.js | 48 +++++++++++++++++++ .../stories/index.js | 2 + .../stories/stylesheet/base-table/_index.scss | 7 +++ .../stories/stylesheet/storybook.scss | 1 + 4 files changed, 58 insertions(+) create mode 100644 packages/react-bootstrap-table2-example/examples/basic/customized-id-classes.js create mode 100644 packages/react-bootstrap-table2-example/stories/stylesheet/base-table/_index.scss diff --git a/packages/react-bootstrap-table2-example/examples/basic/customized-id-classes.js b/packages/react-bootstrap-table2-example/examples/basic/customized-id-classes.js new file mode 100644 index 000000000..d14c606a2 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/basic/customized-id-classes.js @@ -0,0 +1,48 @@ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + + + +`; + +export default () => ( +
+

Customized table ID

+ + +

Customized table className

+ + + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index b7444a741..c16dc5379 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -9,6 +9,7 @@ import BasicTable from 'examples/basic'; import BorderlessTable from 'examples/basic/borderless-table'; import StripHoverCondensedTable from 'examples/basic/striped-hover-condensed-table'; import NoDataTable from 'examples/basic/no-data-table'; +import CustomizedIdClassesTable from 'examples/basic/customized-id-classes'; import CaptionTable from 'examples/basic/caption-table'; // work on columns @@ -121,6 +122,7 @@ storiesOf('Basic Table', module) .add('striped, hover, condensed table', () => ) .add('borderless table', () => ) .add('Indication For Empty Table', () => ) + .add('Customized id and class table', () => ) .add('Table with caption', () => ); storiesOf('Work on Columns', module) diff --git a/packages/react-bootstrap-table2-example/stories/stylesheet/base-table/_index.scss b/packages/react-bootstrap-table2-example/stories/stylesheet/base-table/_index.scss new file mode 100644 index 000000000..34353eb98 --- /dev/null +++ b/packages/react-bootstrap-table2-example/stories/stylesheet/base-table/_index.scss @@ -0,0 +1,7 @@ +table.foo { + background-color: $grey-500; +} + +table#bar { + background-color: $light-blue; +} diff --git a/packages/react-bootstrap-table2-example/stories/stylesheet/storybook.scss b/packages/react-bootstrap-table2-example/stories/stylesheet/storybook.scss index cf0a024e4..c38e02cab 100644 --- a/packages/react-bootstrap-table2-example/stories/stylesheet/storybook.scss +++ b/packages/react-bootstrap-table2-example/stories/stylesheet/storybook.scss @@ -3,6 +3,7 @@ @import "base/github-corner"; @import "base/code-block"; +@import "base-table/index"; @import "welcome/index"; @import "columns/index"; @import "cell-edit/index"; From 3ed4d87b29049a2437e8f5a745d53202d2e37a28 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sat, 17 Mar 2018 15:29:09 +0800 Subject: [PATCH 039/576] correct attribute key of columns.headerEvent in column-event-tables --- .../examples/header-columns/column-event-table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2-example/examples/header-columns/column-event-table.js b/packages/react-bootstrap-table2-example/examples/header-columns/column-event-table.js index 7928a3799..d4394a7a0 100644 --- a/packages/react-bootstrap-table2-example/examples/header-columns/column-event-table.js +++ b/packages/react-bootstrap-table2-example/examples/header-columns/column-event-table.js @@ -28,7 +28,7 @@ import BootstrapTable from 'react-bootstrap-table-next'; const columns = [{ dataField: 'id', text: 'Product ID', - events: { + headerEvents: { onClick: () => alert('Click on Product ID header column') } }, { From 0eda54b772955c908c1ebea970f3c0236522e8ed Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sat, 17 Mar 2018 16:04:03 +0800 Subject: [PATCH 040/576] correct the typo of documents --- docs/README.md | 10 +++++----- docs/columns.md | 22 +++++++++++----------- docs/migration.md | 16 ++++++++-------- docs/row-selection.md | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/README.md b/docs/README.md index 096ca24bb..7871d5f39 100644 --- a/docs/README.md +++ b/docs/README.md @@ -59,14 +59,14 @@ A special case for remote pagination: remote={ { pagination: true, filter: false, sort: false } } ``` -There is a apecial case for remote pagination, even you only specified the paignation need to handle as remote, `react-bootstrap-table2` will handle all the table changes(filter, sort etc) as remote mode, because `react-bootstrap-table2` only know the data of current page, but filtering, searching or sort need to work on overall datas. +There is a special case for remote pagination, even you only specified the pagination need to handle as remote, `react-bootstrap-table2` will handle all the table changes(filter, sort etc) as remote mode, because `react-bootstrap-table2` only know the data of current page, but filtering, searching or sort need to work on overall data. ### loading - [Bool] Telling if table is loading or not, for example: waiting data loading, filtering etc. It's **only** valid when [`remote`](#remote) is enabled. When `loading` is `true`, `react-bootstrap-table2` will attend to render a overlay on table via [`overlay`](#overlay) prop, if [`overlay`](#overlay) prop is not given, `react-bootstrap-table2` will ignore the overlay rendering. ### overlay - [Function] -`overlay` accept a factory funtion which should returning a higher order component. By default, `react-bootstrap-table2-overlay` can be a good option for you: +`overlay` accept a factory function which should returning a higher order component. By default, `react-bootstrap-table2-overlay` can be a good option for you: ```sh $ npm install react-bootstrap-table2-overlay @@ -163,7 +163,7 @@ const defaultSorted = [{ ``` ### pagination - [Object] -`pagination` allow user to render a pagination panel on the bottom of table. But pagination funcitonality is separated from core of `react-bootstrap-table2` so that you are suppose to install `react-bootstrap-table2-paginator` additionaly. +`pagination` allow user to render a pagination panel on the bottom of table. But pagination functionality is separated from core of `react-bootstrap-table2` so that you are suppose to install `react-bootstrap-table2-paginator` additionally. ```sh $ npm install react-bootstrap-table2-paginator --save @@ -205,7 +205,7 @@ paginator({ prePageTitle: 'Go to previous', // the title of previous page button firstPageTitle: 'Go to first', // the title of first page button lastPageTitle: 'Go to last', // the title of last page button - hideSizePerPage: true, // hide the size per page dorpdown + hideSizePerPage: true, // hide the size per page dropdown hidePageListOnlyOnePage: true, // hide pagination bar when only one page, default is false onPageChange: (page, sizePerPage) => {}, // callback function when page was changing onSizePerPageChange: (sizePerPage, page) => {}, // callback function when page size was changing @@ -213,7 +213,7 @@ paginator({ ``` ### filter - [Object] -`filter` allow user to filter data by column. However, filter funcitonality is separated from core of `react-bootstrap-table2` so that you are suppose to install `react-bootstrap-table2-filter` firstly. +`filter` allow user to filter data by column. However, filter functionality is separated from core of `react-bootstrap-table2` so that you are suppose to install `react-bootstrap-table2-filter` firstly. ```sh $ npm install react-bootstrap-table2-filter --save diff --git a/docs/columns.md b/docs/columns.md index b80c48a67..eeab42ba2 100644 --- a/docs/columns.md +++ b/docs/columns.md @@ -137,7 +137,7 @@ Enable the column sort via a `true` value given. ``` ## column.classes - [String | Function] -It's availabe to have custom class on table column: +It's available to have custom class on table column: ```js { @@ -165,7 +165,7 @@ In addition, `classes` also accept a callback function which have more power to A new `String` will be the result as element class. ## column.headerClasses - [String | Function] -It's similar to [`column.classes`](#classes), `headerClasses` is availabe to have customized class on table header column: +It's similar to [`column.classes`](#classes), `headerClasses` is available to have customized class on table header column: ```js { @@ -190,7 +190,7 @@ Furthermore, it also accept a callback function which takes 2 arguments and a `S A new `String` will be the result of element headerClasses. ## column.style - [Object | Function] -It's availabe to have custom style on table column: +It's available to have custom style on table column: ```js { @@ -220,7 +220,7 @@ A new `Object` will be the result of element style. ## column.headerStyle - [Object | Function] -It's availabe to have customized inline-style on table header column: +It's available to have customized inline-style on table header column: ```js { @@ -278,7 +278,7 @@ A new `String` will be the result of element title. } ``` -It's also availabe to custom via a callback function: +It's also available to custom via a callback function: ```js { headerTitle: function callback(column, colIndex) { ... } @@ -401,7 +401,7 @@ A new `Object` will be the result of element HTML attributes. > Caution: -> If `column.classes`, `column.style`, `column.title`, `column.hidden` or `column.align` was given at the same time, property `attrs` has lower priorty and it will be overwrited. +> If `column.classes`, `column.style`, `column.title`, `column.hidden` or `column.align` was given at the same time, property `attrs` has lower priority and it will be overwritten. ```js { @@ -412,7 +412,7 @@ A new `Object` will be the result of element HTML attributes. ``` ## column.headerAttrs - [Object | Function] -`headerAttrs` is similiar to [`column.attrs`](#attrs) but it works for header column. +`headerAttrs` is similar to [`column.attrs`](#attrs) but it works for header column. ```js { // omit... @@ -444,7 +444,7 @@ A new `Object` will be the result of element headerAttrs. > Caution: > Same as [column.attrs](#attrs), it has lower priority and will be -> overwrited when other props related to HTML attributes were given. +> overwritten when other props related to HTML attributes were given. ### headerSortingClasses - [String | Function] @@ -467,7 +467,7 @@ const headerSortingClasses = (column, sortOrder, isLastSorting, colIndex) => { . ### headerSortingStyle - [Object | Function] -It's similiar to [headerSortingClasses](#headerSortingClasses). It allows to customize the style of header cell when this column is sorting. A style `Object` and `callback` are acceptable. `callback` takes **4** arguments and an `Object` is expected to return: +It's similar to [headerSortingClasses](#headerSortingClasses). It allows to customize the style of header cell when this column is sorting. A style `Object` and `callback` are acceptable. `callback` takes **4** arguments and an `Object` is expected to return: ```js const sortingHeaderStyle = { @@ -502,7 +502,7 @@ If a callback function given, you can control the editable level as cell level: } ``` -The return value can be a bool or an object. If your valiation is pass, return `true` explicitly. If your valiation is invalid, return following object instead: +The return value can be a bool or an object. If your validation is pass, return `true` explicitly. If your validation is invalid, return following object instead: ```js { valid: false, @@ -574,7 +574,7 @@ import { textFilter } from 'react-bootstrap-table2-filter'; For some reason of simple customization, `react-bootstrap-table2` allow you to pass some props to filter factory function. Please check [here](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/master/packages/react-bootstrap-table2-filter/README.md) for more detail tutorial. ## column.filterValue - [Function] -Sometimes, if the cell/column value that you don't want to filter on them, you can define `filterValue` to return a actual value you wanna be filterd: +Sometimes, if the cell/column value that you don't want to filter on them, you can define `filterValue` to return a actual value you wanna be filtered: **Parameters** * `cell`: The value of current cell. diff --git a/docs/migration.md b/docs/migration.md index ae009e4f3..a9d2104fe 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -1,8 +1,8 @@ # Migration Guide * Please see the [CHANGELOG](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/new-version-0.1.0.html) for `react-bootstrap-table2` first drop. -* Please see the [Roadmap](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/release-plan.html) for `react-bootstrap-table2` in 2018/Q1. -* Feel free to see the [offical docs](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/about.html), we list all the basic usage here!! +* Please see the [Road Map](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/release-plan.html) for `react-bootstrap-table2` in 2018/Q1. +* Feel free to see the [official docs](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/about.html), we list all the basic usage here!! ## Preface @@ -23,11 +23,11 @@ Currently, **I still can't implement all the mainly features in legacy `react-bo * [`react-bootstrap-table2-overlay`](https://www.npmjs.com/package/react-bootstrap-table2-overlay) * Overlay/Loading Addons -This can help your application with less bundled size and also help `react-bootstrap-table2` have clean design to avoid handling to much logic in kernal module(SRP). Hence, which means you probably need to install above addons when you need specific features. +This can help your application with less bundled size and also help `react-bootstrap-table2` have clean design to avoid handling to much logic in kernel module(SRP). Hence, which means you probably need to install above addons when you need specific features. ## Core Table Migration -There is a big chagne is that there's no `TableHeaderColumn` in the `react-bootstrap-table2`, instead you are supposed to be define the `columns` prop on `BootstrapTable`: +There is a big change is that there's no `TableHeaderColumn` in the `react-bootstrap-table2`, instead you are supposed to be define the `columns` prop on `BootstrapTable`: ```js import BootstrapTable from 'react-bootstrap-table-next'; @@ -48,8 +48,8 @@ const columns = [{ The `text` property is just same as the children for the `TableHeaderColumn`, if you want to custom the header, there's a new property is: [`headerFormatter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnheaderformatter-function). -* [`BootstrapTable` Definitation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html) -* [Column Definitation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html) +* [`BootstrapTable` Definition](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html) +* [Column Definition](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html) ## Table Sort @@ -65,7 +65,7 @@ Please see [Work with table sort](https://react-bootstrap-table.github.io/react- - [ ] Sort management - [ ] Multi sort -Due to no `TableHeaderColumn` so that no `dataSort` here, please add [`sort`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnsort-bool) property on column definitation. +Due to no `TableHeaderColumn` so that no `dataSort` here, please add [`sort`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnsort-bool) property on column definition. ## Row Selection @@ -93,7 +93,7 @@ Please see [available filter configuration](https://react-bootstrap-table.github Remember to install [`react-bootstrap-table2-filter`](https://www.npmjs.com/package/react-bootstrap-table2-filter) firstly. -Due to no `TableHeaderColumn` so that no `filter` here, please add [`filter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnfilter-object) property on column definitation and [`filter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html#filter-object) prop on `BootstrapTable`. +Due to no `TableHeaderColumn` so that no `filter` here, please add [`filter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnfilter-object) property on column definition and [`filter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html#filter-object) prop on `BootstrapTable`. ## Cell Edit diff --git a/docs/row-selection.md b/docs/row-selection.md index c877e6b19..b75aa1ff2 100644 --- a/docs/row-selection.md +++ b/docs/row-selection.md @@ -102,7 +102,7 @@ const selectRow = { ``` ### selectRow.bgColor - [String | Function] -The backgroud color when row is selected +The background color when row is selected ```js const selectRow = { From ceebdf5a139f1c3035e7910a0296bbaff835d84b Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sat, 17 Mar 2018 17:05:02 +0800 Subject: [PATCH 041/576] refine store to set selectRow when receiving props --- .../src/row-selection/wrapper.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/react-bootstrap-table2/src/row-selection/wrapper.js b/packages/react-bootstrap-table2/src/row-selection/wrapper.js index b8c79bd97..1be101e10 100644 --- a/packages/react-bootstrap-table2/src/row-selection/wrapper.js +++ b/packages/react-bootstrap-table2/src/row-selection/wrapper.js @@ -22,19 +22,17 @@ export default Base => super(props); this.handleRowSelect = this.handleRowSelect.bind(this); this.handleAllRowsSelect = this.handleAllRowsSelect.bind(this); - props.store.selected = this.props.selectRow.selected || []; + + props.store.selected = props.selectRow.selected || []; this.state = { selectedRowKeys: props.store.selected }; } componentWillReceiveProps(nextProps) { - if (nextProps.selectRow) { - this.store.selected = nextProps.selectRow.selected || []; - this.setState(() => ({ - selectedRowKeys: this.store.selected - })); - } + this.setState(() => ({ + selectedRowKeys: nextProps.store.selected + })); } /** From d80ae13513a413f7d2a611612e8cb5a48d2134b7 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sat, 17 Mar 2018 17:25:20 +0800 Subject: [PATCH 042/576] [test] test for RowSelectionWrapper#componentWillReceiveProps --- .../test/row-selection/wrapper.test.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js b/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js index 278a54e52..347b86713 100644 --- a/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js +++ b/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js @@ -68,7 +68,18 @@ describe('RowSelectionWrapper', () => { expect(wrapper.props().onAllRowsSelect).toBeDefined(); }); - describe('when selectRow.selected is defiend', () => { + describe('componentWillReceiveProps', () => { + const nextSelected = [0]; + const nextProps = { store: { selected: nextSelected } }; + + it('should update state.selectedRowKeys with next selected rows', () => { + wrapper.instance().componentWillReceiveProps(nextProps); + + expect(wrapper.state('selectedRowKeys')).toEqual(nextSelected); + }); + }); + + describe('when selectRow.selected is defined', () => { beforeEach(() => { selectRow.mode = 'checkbox'; selectRow.selected = [1, 3]; From 923439dc816bfeec9c15fe91af8e0f3edeebecff Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sat, 17 Mar 2018 17:29:30 +0800 Subject: [PATCH 043/576] correct typo --- .../test/row-selection/wrapper.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js b/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js index 347b86713..749c0e428 100644 --- a/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js +++ b/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js @@ -107,7 +107,7 @@ describe('RowSelectionWrapper', () => { const firstSelectedRow = data[0][keyField]; const secondSelectedRow = data[1][keyField]; - it('call handleRowSelect function should seting correct state.selectedRowKeys', () => { + it('call handleRowSelect function should setting correct state.selectedRowKeys', () => { wrapper.instance().handleRowSelect(firstSelectedRow, rowIndex); expect(wrapper.state('selectedRowKeys')).toEqual([firstSelectedRow]); @@ -133,7 +133,7 @@ describe('RowSelectionWrapper', () => { ); }); - it('call handleRowSelect function should seting correct state.selectedRowKeys', () => { + it('call handleRowSelect function should setting correct state.selectedRowKeys', () => { wrapper.instance().handleRowSelect(firstSelectedRow, true, rowIndex); expect(wrapper.state('selectedRowKeys')).toEqual(expect.arrayContaining([firstSelectedRow])); @@ -147,7 +147,7 @@ describe('RowSelectionWrapper', () => { expect(wrapper.state('selectedRowKeys')).toEqual([]); }); - it('call handleAllRowsSelect function should seting correct state.selectedRowKeys', () => { + it('call handleAllRowsSelect function should setting correct state.selectedRowKeys', () => { wrapper.instance().handleAllRowsSelect(); expect(wrapper.state('selectedRowKeys')).toEqual(expect.arrayContaining([firstSelectedRow, secondSelectedRow])); @@ -155,7 +155,7 @@ describe('RowSelectionWrapper', () => { expect(wrapper.state('selectedRowKeys')).toEqual([]); }); - it('call handleAllRowsSelect function with a bool args should seting correct state.selectedRowKeys', () => { + it('call handleAllRowsSelect function with a bool args should setting correct state.selectedRowKeys', () => { wrapper.instance().handleAllRowsSelect(true); expect(wrapper.state('selectedRowKeys')).toEqual(expect.arrayContaining([firstSelectedRow, secondSelectedRow])); From 55336108a05dafc0740b56136857f12ddcdcb7a7 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 18 Mar 2018 14:07:44 +0800 Subject: [PATCH 044/576] should recieve newest selectRow.selected --- .../src/row-selection/wrapper.js | 3 ++- .../test/row-selection/wrapper.test.js | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/react-bootstrap-table2/src/row-selection/wrapper.js b/packages/react-bootstrap-table2/src/row-selection/wrapper.js index 1be101e10..1a944160b 100644 --- a/packages/react-bootstrap-table2/src/row-selection/wrapper.js +++ b/packages/react-bootstrap-table2/src/row-selection/wrapper.js @@ -30,8 +30,9 @@ export default Base => } componentWillReceiveProps(nextProps) { + nextProps.store.selected = nextProps.selectRow.selected || []; this.setState(() => ({ - selectedRowKeys: nextProps.store.selected + selectedRowKeys: nextProps.selectRow.selected })); } diff --git a/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js b/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js index 749c0e428..59dc19013 100644 --- a/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js +++ b/packages/react-bootstrap-table2/test/row-selection/wrapper.test.js @@ -70,11 +70,19 @@ describe('RowSelectionWrapper', () => { describe('componentWillReceiveProps', () => { const nextSelected = [0]; - const nextProps = { store: { selected: nextSelected } }; + const nextProps = { + store: { + selected: nextSelected + }, + selectRow: { + mode: 'checkbox', + selected: nextSelected + } + }; it('should update state.selectedRowKeys with next selected rows', () => { wrapper.instance().componentWillReceiveProps(nextProps); - + expect(nextProps.store.selected).toEqual(nextSelected); expect(wrapper.state('selectedRowKeys')).toEqual(nextSelected); }); }); From c11539b9fb1c0ce87f653ea836b6cac375cd3723 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 18 Mar 2018 14:33:11 +0800 Subject: [PATCH 045/576] [docs] patch id and classes for BootstrapTable --- docs/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/README.md b/docs/README.md index 7871d5f39..34b38df98 100644 --- a/docs/README.md +++ b/docs/README.md @@ -15,6 +15,8 @@ * [bordered](#bordered) * [hover](#hover) * [condensed](#condensed) +* [id](#id) +* [classes](#classes) * [cellEdit](#cellEdit) * [selectRow](#selectRow) * [rowStyle](#rowStyle) @@ -100,6 +102,10 @@ Same as bootstrap `.table-hover` class for adding mouse hover effect (grey backg ### condensed - [Bool] Same as bootstrap `.table-condensed` class for making a table more compact by cutting cell padding in half. +### id - [String] +Customize id on `table` element. +### classes - [String] +Customize class on `table` element. ### cellEdit - [Object] Makes table cells editable, please see [cellEdit definition](./cell-edit.md) for more detail. From 6bc81dddd0fb436e4387695b718f1f033424d4fc Mon Sep 17 00:00:00 2001 From: Parth Prajapati Date: Sun, 18 Mar 2018 13:12:21 +0530 Subject: [PATCH 046/576] Fixed #237 (#261) * Fixed #237 * Solved lint errors * Removed test cases for display: none checks - added test cases for hidden columns check --- packages/react-bootstrap-table2/src/cell.js | 5 -- .../react-bootstrap-table2/src/header-cell.js | 5 -- packages/react-bootstrap-table2/src/header.js | 29 +++++---- packages/react-bootstrap-table2/src/row.js | 65 ++++++++++--------- .../react-bootstrap-table2/test/cell.test.js | 32 --------- .../test/header-cell.test.js | 18 ----- .../test/header.test.js | 23 +++++++ .../react-bootstrap-table2/test/row.test.js | 26 ++++++++ 8 files changed, 99 insertions(+), 104 deletions(-) diff --git a/packages/react-bootstrap-table2/src/cell.js b/packages/react-bootstrap-table2/src/cell.js index d50eeb44a..dc535a715 100644 --- a/packages/react-bootstrap-table2/src/cell.js +++ b/packages/react-bootstrap-table2/src/cell.js @@ -39,7 +39,6 @@ class Cell extends Component { } = this.props; const { dataField, - hidden, formatter, formatExtraData, style, @@ -80,10 +79,6 @@ class Cell extends Component { _.isFunction(align) ? align(content, row, rowIndex, columnIndex) : align; } - if (hidden) { - cellStyle.display = 'none'; - } - if (cellClasses) cellAttrs.className = cellClasses; if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle; diff --git a/packages/react-bootstrap-table2/src/header-cell.js b/packages/react-bootstrap-table2/src/header-cell.js index b6af21eeb..bb012d182 100644 --- a/packages/react-bootstrap-table2/src/header-cell.js +++ b/packages/react-bootstrap-table2/src/header-cell.js @@ -24,7 +24,6 @@ const HeaderCell = (props) => { text, sort, filter, - hidden, headerTitle, headerAlign, headerFormatter, @@ -58,10 +57,6 @@ const HeaderCell = (props) => { cellStyle.textAlign = _.isFunction(headerAlign) ? headerAlign(column, index) : headerAlign; } - if (hidden) { - cellStyle.display = 'none'; - } - if (sort) { const customClick = cellAttrs.onClick; cellAttrs.onClick = (e) => { diff --git a/packages/react-bootstrap-table2/src/header.js b/packages/react-bootstrap-table2/src/header.js index ddbc7bfa4..38b8c3a02 100644 --- a/packages/react-bootstrap-table2/src/header.js +++ b/packages/react-bootstrap-table2/src/header.js @@ -27,20 +27,23 @@ const Header = (props) => { } { columns.map((column, i) => { - const currSort = column.dataField === sortField; - const isLastSorting = column.dataField === sortField; + if (!column.hidden) { + const currSort = column.dataField === sortField; + const isLastSorting = column.dataField === sortField; - return ( - ); + return ( + ); + } + return false; }) } diff --git a/packages/react-bootstrap-table2/src/row.js b/packages/react-bootstrap-table2/src/row.js index 7b1df3750..3efb0c529 100644 --- a/packages/react-bootstrap-table2/src/row.js +++ b/packages/react-bootstrap-table2/src/row.js @@ -58,46 +58,49 @@ class Row extends eventDelegater(Component) { } { columns.map((column, index) => { - const { dataField } = column; - const content = _.get(row, dataField); - let editable = _.isDefined(column.editable) ? column.editable : true; - if (dataField === keyField || !editableRow) editable = false; - if (_.isFunction(column.editable)) { - editable = column.editable(content, row, rowIndex, index); - } - if (rowIndex === editingRowIdx && index === editingColIdx) { - let editCellstyle = column.editCellStyle || {}; - let editCellclasses = column.editCellClasses; - if (_.isFunction(column.editCellStyle)) { - editCellstyle = column.editCellStyle(content, row, rowIndex, index); + if (!column.hidden) { + const { dataField } = column; + const content = _.get(row, dataField); + let editable = _.isDefined(column.editable) ? column.editable : true; + if (dataField === keyField || !editableRow) editable = false; + if (_.isFunction(column.editable)) { + editable = column.editable(content, row, rowIndex, index); } - if (_.isFunction(column.editCellClasses)) { - editCellclasses = column.editCellClasses(content, row, rowIndex, index); + if (rowIndex === editingRowIdx && index === editingColIdx) { + let editCellstyle = column.editCellStyle || {}; + let editCellclasses = column.editCellClasses; + if (_.isFunction(column.editCellStyle)) { + editCellstyle = column.editCellStyle(content, row, rowIndex, index); + } + if (_.isFunction(column.editCellClasses)) { + editCellclasses = column.editCellClasses(content, row, rowIndex, index); + } + return ( + + ); } return ( - ); } - return ( - - ); + return false; }) } diff --git a/packages/react-bootstrap-table2/test/cell.test.js b/packages/react-bootstrap-table2/test/cell.test.js index b83bcc9bd..439a638b2 100644 --- a/packages/react-bootstrap-table2/test/cell.test.js +++ b/packages/react-bootstrap-table2/test/cell.test.js @@ -27,24 +27,6 @@ describe('Cell', () => { }); }); - describe('when column.hidden prop is true', () => { - const column = { - dataField: 'id', - text: 'ID', - hidden: true - }; - - beforeEach(() => { - wrapper = shallow(); - }); - - it('should have \'none\' value for style.display', () => { - const style = wrapper.find('td').prop('style'); - expect(style).toBeDefined(); - expect(style.display).toEqual('none'); - }); - }); - describe('when column.formatter prop is defined', () => { const rowIndex = 1; const column = { @@ -390,20 +372,6 @@ describe('Cell', () => { }); }); - describe('when column.hidden prop is defined', () => { - it('attrs.style.hidden should be overwrited', () => { - column.hidden = true; - column.attrs = { style: { hidden: true } }; - - wrapper = shallow( - ); - - const style = wrapper.find('td').prop('style'); - expect(style).toBeDefined(); - expect(style.display).toEqual('none'); - }); - }); - describe('when column.align prop is defined', () => { it('attrs.style.textAlign should be overwrited', () => { column.align = 'center'; diff --git a/packages/react-bootstrap-table2/test/header-cell.test.js b/packages/react-bootstrap-table2/test/header-cell.test.js index 598396448..535d22227 100644 --- a/packages/react-bootstrap-table2/test/header-cell.test.js +++ b/packages/react-bootstrap-table2/test/header-cell.test.js @@ -33,24 +33,6 @@ describe('HeaderCell', () => { }); }); - describe('when column.hidden props is true', () => { - const column = { - dataField: 'id', - text: 'ID', - hidden: true - }; - - beforeEach(() => { - wrapper = shallow(); - }); - - it('should have \'none\' value for style.display', () => { - const style = wrapper.find('th').prop('style'); - expect(style).toBeDefined(); - expect(style.display).toEqual('none'); - }); - }); - describe('when column.headerTitle prop is defined', () => { let column; beforeEach(() => { diff --git a/packages/react-bootstrap-table2/test/header.test.js b/packages/react-bootstrap-table2/test/header.test.js index 8ae604b0b..c50260256 100644 --- a/packages/react-bootstrap-table2/test/header.test.js +++ b/packages/react-bootstrap-table2/test/header.test.js @@ -101,6 +101,29 @@ describe('Header', () => { }); }); + describe('when column.hidden is true', () => { + beforeEach(() => { + const newColumns = [{ + dataField: 'id', + text: 'ID', + hidden: true + }, { + dataField: 'name', + text: 'Name' + }]; + wrapper = shallow( +
+ ); + }); + + it('should not render column with hidden value true', () => { + expect(wrapper.find(HeaderCell).length).toBe(1); + }); + }); + describe('when selectRow.mode is checkbox (multiple selection)', () => { beforeEach(() => { const selectRow = { mode: 'checkbox' }; diff --git a/packages/react-bootstrap-table2/test/row.test.js b/packages/react-bootstrap-table2/test/row.test.js index 02cc06837..117a24f35 100644 --- a/packages/react-bootstrap-table2/test/row.test.js +++ b/packages/react-bootstrap-table2/test/row.test.js @@ -502,6 +502,32 @@ describe('Row', () => { }); }); + describe('when cloumn.hidden is true', () => { + beforeEach(() => { + const newColumns = [{ + dataField: 'id', + text: 'ID', + hidden: true + }, { + dataField: 'name', + text: 'Name' + }, { + dataField: 'price', + text: 'Price' + }]; + wrapper = shallow( + ); + }); + + it('should not render column with hidden value true', () => { + expect(wrapper.find(Cell).length).toBe(2); + }); + }); describe('selectRow', () => { let selectRow; From 6f9361934a0bb44e6eb75172fa954975193d890d Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sun, 18 Mar 2018 16:10:06 +0800 Subject: [PATCH 047/576] set state.selectedRowKeys based on store --- packages/react-bootstrap-table2/src/row-selection/wrapper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2/src/row-selection/wrapper.js b/packages/react-bootstrap-table2/src/row-selection/wrapper.js index 1a944160b..c2880bf6c 100644 --- a/packages/react-bootstrap-table2/src/row-selection/wrapper.js +++ b/packages/react-bootstrap-table2/src/row-selection/wrapper.js @@ -32,7 +32,7 @@ export default Base => componentWillReceiveProps(nextProps) { nextProps.store.selected = nextProps.selectRow.selected || []; this.setState(() => ({ - selectedRowKeys: nextProps.selectRow.selected + selectedRowKeys: nextProps.store.selected })); } From d5ddd8c3af8947ba6dfd6f93a891e67bc9f25e5b Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 18 Mar 2018 16:44:39 +0800 Subject: [PATCH 048/576] add selection management example --- .../row-selection/selection-management.js | 144 ++++++++++++++++++ .../stories/index.js | 2 + 2 files changed, 146 insertions(+) create mode 100644 packages/react-bootstrap-table2-example/examples/row-selection/selection-management.js diff --git a/packages/react-bootstrap-table2-example/examples/row-selection/selection-management.js b/packages/react-bootstrap-table2-example/examples/row-selection/selection-management.js new file mode 100644 index 000000000..e0466a3b8 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/row-selection/selection-management.js @@ -0,0 +1,144 @@ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +class SelectionManagment extends React.Component { + constructor(props) { + super(props); + this.state = { selected: [0, 1] }; + } + + handleBtnClick = () => { + if (!this.state.selected.includes(2)) { + this.setState(() => ({ + selected: [...this.state.selected, 2] + })); + } else { + this.setState(() => ({ + selected: this.state.selected.filter(x => x !== 2) + })); + } + } + + handleOnSelect = (row, isSelect) => { + if (isSelect) { + this.setState(() => ({ + selected: [...this.state.selected, row.id] + })); + } else { + this.setState(() => ({ + selected: this.state.selected.filter(x => x !== row.id) + })); + } + } + + handleOnSelectAll = (isSelect, rows) => { + const ids = rows.map(r => r.id); + if (isSelect) { + this.setState(() => ({ + selected: ids + })); + } else { + this.setState(() => ({ + selected: [] + })); + } + } + + render() { + const selectRow = { + mode: 'checkbox', + clickToSelect: true, + selected: this.state.selected, + onSelect: this.handleOnSelect, + onSelectAll: this.handleOnSelectAll + }; + return ( +
+ + + { sourceCode } +
+ ); + } +} +`; + +export default class SelectionManagment extends React.Component { + constructor(props) { + super(props); + this.state = { selected: [0, 1] }; + } + + handleBtnClick = () => { + if (!this.state.selected.includes(2)) { + this.setState(() => ({ + selected: [...this.state.selected, 2] + })); + } else { + this.setState(() => ({ + selected: this.state.selected.filter(x => x !== 2) + })); + } + } + + handleOnSelect = (row, isSelect) => { + if (isSelect) { + this.setState(() => ({ + selected: [...this.state.selected, row.id] + })); + } else { + this.setState(() => ({ + selected: this.state.selected.filter(x => x !== row.id) + })); + } + } + + handleOnSelectAll = (isSelect, rows) => { + const ids = rows.map(r => r.id); + if (isSelect) { + this.setState(() => ({ + selected: ids + })); + } else { + this.setState(() => ({ + selected: [] + })); + } + } + + render() { + const selectRow = { + mode: 'checkbox', + clickToSelect: true, + selected: this.state.selected, + onSelect: this.handleOnSelect, + onSelectAll: this.handleOnSelectAll + }; + return ( +
+ + + { sourceCode } +
+ ); + } +} diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index c16dc5379..3f116f508 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -79,6 +79,7 @@ import SingleSelectionTable from 'examples/row-selection/single-selection'; import MultipleSelectionTable from 'examples/row-selection/multiple-selection'; import ClickToSelectTable from 'examples/row-selection/click-to-select'; import DefaultSelectTable from 'examples/row-selection/default-select'; +import SelectionManagement from 'examples/row-selection/selection-management'; import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-select-with-cell-edit'; import SelectionStyleTable from 'examples/row-selection/selection-style'; import SelectionClassTable from 'examples/row-selection/selection-class'; @@ -193,6 +194,7 @@ storiesOf('Row Selection', module) .add('Multiple Selection', () => ) .add('Click to Select', () => ) .add('Default Select', () => ) + .add('Selection Management', () => ) .add('Click to Select and Edit Cell', () => ) .add('Selection Style', () => ) .add('Selection Class', () => ) From 33a8da701b508e898d33deda157d42ecb3b77cef Mon Sep 17 00:00:00 2001 From: Parth Prajapati Date: Sun, 18 Mar 2018 14:28:27 +0530 Subject: [PATCH 049/576] Add TravisCI badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9c91f4b65..7d90d42f1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # react-bootstrap-table2 +[![Build Status](https://travis-ci.org/react-bootstrap-table/react-bootstrap-table2.svg?branch=master)](https://travis-ci.org/react-bootstrap-table/react-bootstrap-table2) Rebuilt [react-bootstrap-table](https://github.com/AllenFang/react-bootstrap-table) > `react-bootstrap-table2`'s npm module name is [**`react-bootstrap-table-next`**](https://www.npmjs.com/package/react-bootstrap-table-next) due to some guys already used it From 6de57737eafaf49156a2464725df9335e7f6ba65 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sun, 18 Mar 2018 17:35:05 +0800 Subject: [PATCH 050/576] allow travis to run test for master branch --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 02a549251..4120d0a8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,7 @@ cache: branches: only: - # skip master branch when it's under development phase - # - master + - master - develop before_install: From bd9150f88fe3b9459334bba433aa683d7c75cfb2 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 18 Mar 2018 23:07:46 +0800 Subject: [PATCH 051/576] Publish - react-bootstrap-table2-editor@0.1.3 - react-bootstrap-table2-example@0.1.4 - react-bootstrap-table-next@0.1.5 --- packages/react-bootstrap-table2-editor/package.json | 2 +- packages/react-bootstrap-table2-example/package.json | 2 +- packages/react-bootstrap-table2/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-bootstrap-table2-editor/package.json b/packages/react-bootstrap-table2-editor/package.json index ded23c816..86bb4d9a4 100644 --- a/packages/react-bootstrap-table2-editor/package.json +++ b/packages/react-bootstrap-table2-editor/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-editor", - "version": "0.1.2", + "version": "0.1.3", "description": "it's the editor addon for react-bootstrap-table2", "main": "./lib/index.js", "scripts": { diff --git a/packages/react-bootstrap-table2-example/package.json b/packages/react-bootstrap-table2-example/package.json index b7e59dd28..5a0ead8a7 100644 --- a/packages/react-bootstrap-table2-example/package.json +++ b/packages/react-bootstrap-table2-example/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-example", - "version": "0.1.3", + "version": "0.1.4", "description": "", "main": "index.js", "private": true, diff --git a/packages/react-bootstrap-table2/package.json b/packages/react-bootstrap-table2/package.json index 983bd57f3..c9fc9b89a 100644 --- a/packages/react-bootstrap-table2/package.json +++ b/packages/react-bootstrap-table2/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table-next", - "version": "0.1.4", + "version": "0.1.5", "description": "Next generation of react-bootstrap-table", "main": "./lib/index.js", "repository": { From 42dbd00fd9edbf44b66b2cb577304d36741c2276 Mon Sep 17 00:00:00 2001 From: Patrick O'Meara Date: Sun, 25 Mar 2018 19:36:58 +1100 Subject: [PATCH 052/576] fix#264: wrong col span when enable selection in a empty table (#265) * noDataIndication * use the correct amount of cells when the first row is select * storybook added for development, not necessary in docs fixes react-bootstrap-table/react-bootstrap-table2#264 * eslint complaints 4:11 error 'columnLen' is never reassigned. Use 'const' instead prefer-const 7:9 error Expected an assignment or function call and instead saw an expression no-unused-expressions * tests updated --- .../row-selection/selection-no-data.js | 62 +++++++++++++++++++ .../stories/index.js | 2 + .../src/props-resolver/column-resolver.js | 9 ++- .../src/props-resolver/index.js | 6 +- .../test/props-resolver/index.test.js | 4 +- 5 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js diff --git a/packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js b/packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js new file mode 100644 index 000000000..4867ffd9c --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js @@ -0,0 +1,62 @@ +/* eslint no-unused-vars: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import Code from 'components/common/code-block'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const selectRow1 = { + mode: 'checkbox', + clickToSelect: true +}; + +const sourceCode1 = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const selectRow = { + mode: 'checkbox', + clickToSelect: true +}; + + +`; + +export default () => ( +
+ + { sourceCode1 } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 3f116f508..f95959bb8 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -81,6 +81,7 @@ import ClickToSelectTable from 'examples/row-selection/click-to-select'; import DefaultSelectTable from 'examples/row-selection/default-select'; import SelectionManagement from 'examples/row-selection/selection-management'; import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-select-with-cell-edit'; +import SelectionNoDataTable from 'examples/row-selection/selection-no-data'; import SelectionStyleTable from 'examples/row-selection/selection-style'; import SelectionClassTable from 'examples/row-selection/selection-class'; import NonSelectableRowsTable from 'examples/row-selection/non-selectable-rows'; @@ -196,6 +197,7 @@ storiesOf('Row Selection', module) .add('Default Select', () => ) .add('Selection Management', () => ) .add('Click to Select and Edit Cell', () => ) + .add('Selection without Data', () => ) .add('Selection Style', () => ) .add('Selection Class', () => ) .add('Selection Background Color', () => ) diff --git a/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js b/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js index 584649896..c330c7d5e 100644 --- a/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js +++ b/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js @@ -1,6 +1,11 @@ export default ExtendBase => class ColumnResolver extends ExtendBase { - visibleColumnSize() { - return this.props.columns.filter(c => !c.hidden).length; + visibleColumnSize(includeSelectColumn = true) { + const columnLen = this.props.columns.filter(c => !c.hidden).length; + if (!includeSelectColumn) return columnLen; + if (this.props.selectRow && !this.props.selectRow.hideSelectColumn) { + return columnLen + 1; + } + return columnLen; } }; diff --git a/packages/react-bootstrap-table2/src/props-resolver/index.js b/packages/react-bootstrap-table2/src/props-resolver/index.js index 4871e2d5e..4f40d97fc 100644 --- a/packages/react-bootstrap-table2/src/props-resolver/index.js +++ b/packages/react-bootstrap-table2/src/props-resolver/index.js @@ -5,12 +5,12 @@ import _ from '../utils'; export default ExtendBase => class TableResolver extends ColumnResolver(ExtendBase) { validateProps() { - const { columns, keyField } = this.props; + const { keyField } = this.props; if (!keyField) { throw new Error('Please specify a field as key via keyField'); } - if (this.visibleColumnSize(columns) <= 0) { - throw new Error('No any visible columns detect'); + if (this.visibleColumnSize(false) <= 0) { + throw new Error('No visible columns detected'); } } diff --git a/packages/react-bootstrap-table2/test/props-resolver/index.test.js b/packages/react-bootstrap-table2/test/props-resolver/index.test.js index 1b6bf8c9d..cb3a54b52 100644 --- a/packages/react-bootstrap-table2/test/props-resolver/index.test.js +++ b/packages/react-bootstrap-table2/test/props-resolver/index.test.js @@ -56,7 +56,7 @@ describe('TableResolver', () => { }); }); - describe('if columns is all unvisible', () => { + describe('if no columns are visible', () => { beforeEach(() => { const mockElement = React.createElement(BootstrapTableMock, { data, keyField, columns: [] @@ -67,7 +67,7 @@ describe('TableResolver', () => { it('should throw error', () => { expect(() => wrapper.instance().validateProps() - ).toThrow(new Error('No any visible columns detect')); + ).toThrow(new Error('No visible columns detected')); }); }); }); From 9ee9c7de434ba19d2558583d4ed4542a25d4d95c Mon Sep 17 00:00:00 2001 From: Allen Date: Sun, 25 Mar 2018 16:37:27 +0800 Subject: [PATCH 053/576] Revert "fix#264: wrong col span when enable selection in a empty table (#265)" This reverts commit 42dbd00fd9edbf44b66b2cb577304d36741c2276. --- .../row-selection/selection-no-data.js | 62 ------------------- .../stories/index.js | 2 - .../src/props-resolver/column-resolver.js | 9 +-- .../src/props-resolver/index.js | 6 +- .../test/props-resolver/index.test.js | 4 +- 5 files changed, 7 insertions(+), 76 deletions(-) delete mode 100644 packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js diff --git a/packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js b/packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js deleted file mode 100644 index 4867ffd9c..000000000 --- a/packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js +++ /dev/null @@ -1,62 +0,0 @@ -/* eslint no-unused-vars: 0 */ -import React from 'react'; - -import BootstrapTable from 'react-bootstrap-table-next'; -import Code from 'components/common/code-block'; - -const columns = [{ - dataField: 'id', - text: 'Product ID' -}, { - dataField: 'name', - text: 'Product Name' -}, { - dataField: 'price', - text: 'Product Price' -}]; - -const selectRow1 = { - mode: 'checkbox', - clickToSelect: true -}; - -const sourceCode1 = `\ -import BootstrapTable from 'react-bootstrap-table-next'; - -const columns = [{ - dataField: 'id', - text: 'Product ID' -}, { - dataField: 'name', - text: 'Product Name' -}, { - dataField: 'price', - text: 'Product Price' -}]; - -const selectRow = { - mode: 'checkbox', - clickToSelect: true -}; - - -`; - -export default () => ( -
- - { sourceCode1 } -
-); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index f95959bb8..3f116f508 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -81,7 +81,6 @@ import ClickToSelectTable from 'examples/row-selection/click-to-select'; import DefaultSelectTable from 'examples/row-selection/default-select'; import SelectionManagement from 'examples/row-selection/selection-management'; import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-select-with-cell-edit'; -import SelectionNoDataTable from 'examples/row-selection/selection-no-data'; import SelectionStyleTable from 'examples/row-selection/selection-style'; import SelectionClassTable from 'examples/row-selection/selection-class'; import NonSelectableRowsTable from 'examples/row-selection/non-selectable-rows'; @@ -197,7 +196,6 @@ storiesOf('Row Selection', module) .add('Default Select', () => ) .add('Selection Management', () => ) .add('Click to Select and Edit Cell', () => ) - .add('Selection without Data', () => ) .add('Selection Style', () => ) .add('Selection Class', () => ) .add('Selection Background Color', () => ) diff --git a/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js b/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js index c330c7d5e..584649896 100644 --- a/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js +++ b/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js @@ -1,11 +1,6 @@ export default ExtendBase => class ColumnResolver extends ExtendBase { - visibleColumnSize(includeSelectColumn = true) { - const columnLen = this.props.columns.filter(c => !c.hidden).length; - if (!includeSelectColumn) return columnLen; - if (this.props.selectRow && !this.props.selectRow.hideSelectColumn) { - return columnLen + 1; - } - return columnLen; + visibleColumnSize() { + return this.props.columns.filter(c => !c.hidden).length; } }; diff --git a/packages/react-bootstrap-table2/src/props-resolver/index.js b/packages/react-bootstrap-table2/src/props-resolver/index.js index 4f40d97fc..4871e2d5e 100644 --- a/packages/react-bootstrap-table2/src/props-resolver/index.js +++ b/packages/react-bootstrap-table2/src/props-resolver/index.js @@ -5,12 +5,12 @@ import _ from '../utils'; export default ExtendBase => class TableResolver extends ColumnResolver(ExtendBase) { validateProps() { - const { keyField } = this.props; + const { columns, keyField } = this.props; if (!keyField) { throw new Error('Please specify a field as key via keyField'); } - if (this.visibleColumnSize(false) <= 0) { - throw new Error('No visible columns detected'); + if (this.visibleColumnSize(columns) <= 0) { + throw new Error('No any visible columns detect'); } } diff --git a/packages/react-bootstrap-table2/test/props-resolver/index.test.js b/packages/react-bootstrap-table2/test/props-resolver/index.test.js index cb3a54b52..1b6bf8c9d 100644 --- a/packages/react-bootstrap-table2/test/props-resolver/index.test.js +++ b/packages/react-bootstrap-table2/test/props-resolver/index.test.js @@ -56,7 +56,7 @@ describe('TableResolver', () => { }); }); - describe('if no columns are visible', () => { + describe('if columns is all unvisible', () => { beforeEach(() => { const mockElement = React.createElement(BootstrapTableMock, { data, keyField, columns: [] @@ -67,7 +67,7 @@ describe('TableResolver', () => { it('should throw error', () => { expect(() => wrapper.instance().validateProps() - ).toThrow(new Error('No visible columns detected')); + ).toThrow(new Error('No any visible columns detect')); }); }); }); From c91f5219138619656e3d26b4171b92187f56c914 Mon Sep 17 00:00:00 2001 From: Allen Date: Sun, 25 Mar 2018 16:44:27 +0800 Subject: [PATCH 054/576] fix #258 (#268) --- docs/columns.md | 8 + .../react-bootstrap-table2-editor/README.md | 6 +- .../src/editing-cell.js | 21 ++- .../test/editing-cell.test.js | 141 +++++++++++++++++- .../examples/cell-edit/editor-class-table.js | 61 ++++++++ .../examples/cell-edit/editor-style-table.js | 69 +++++++++ .../stories/index.js | 8 +- .../react-bootstrap-table2/src/header-cell.js | 2 + packages/react-bootstrap-table2/src/row.js | 2 + 9 files changed, 311 insertions(+), 7 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/cell-edit/editor-class-table.js create mode 100644 packages/react-bootstrap-table2-example/examples/cell-edit/editor-style-table.js diff --git a/docs/columns.md b/docs/columns.md index eeab42ba2..d7a7beaf7 100644 --- a/docs/columns.md +++ b/docs/columns.md @@ -32,6 +32,8 @@ Available properties in a column object: * [validator](#validator) * [editCellStyle](#editCellStyle) * [editCellClasses](#editCellClasses) +* [editorStyle](#editorStyle) +* [editorClasses](#editorClasses) * [filter](#filter) * [filterValue](#filterValue) @@ -552,6 +554,12 @@ Or take a callback function } ``` +## column.editorStyle - [Object | Function] +This is almost same as [`column.editCellStyle`](#editCellStyle), but `column.editorStyle` is custom the style on editor instead of cell(`td`). + +## column.editorClasses - [Object | Function] +This is almost same as [`column.editCellClasses`](#editCellClasses), but `column.editorClasses` is custom the class on editor instead of cell(`td`). + ## column.filter - [Object] Configure `column.filter` will able to setup a column level filter on the header column. Currently, `react-bootstrap-table2` support following filters: diff --git a/packages/react-bootstrap-table2-editor/README.md b/packages/react-bootstrap-table2-editor/README.md index 02e0e46af..5c9719e1b 100644 --- a/packages/react-bootstrap-table2-editor/README.md +++ b/packages/react-bootstrap-table2-editor/README.md @@ -49,13 +49,15 @@ How user save their new editings? We offer two ways: * Cell Level (Configure [column.editable](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditable-bool-function) as a callback function) ## Customize Style/Class -Currently, we only support the editing cell style/class customization, in the future, we will offer more customizations. - ### Editing Cell * Customize the editing cell style via [column.editCellStyle](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditcellstyle-object-function) * Customize the editing cell classname via [column.editCellClasses](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditcellclasses-string-function) +### Editor +* Customize the editor style via [column.editorStyle](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditorstyle-object-function) +* Customize the editor classname via [column.editoClasses](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditorclasses-string-function) + ## Validation [`column.validator`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnvalidator-function) will help you to work on it! \ No newline at end of file diff --git a/packages/react-bootstrap-table2-editor/src/editing-cell.js b/packages/react-bootstrap-table2-editor/src/editing-cell.js index 5e54984c6..2c732de0d 100644 --- a/packages/react-bootstrap-table2-editor/src/editing-cell.js +++ b/packages/react-bootstrap-table2-editor/src/editing-cell.js @@ -14,7 +14,9 @@ export default _ => class EditingCell extends Component { static propTypes = { row: PropTypes.object.isRequired, + rowIndex: PropTypes.number.isRequired, column: PropTypes.object.isRequired, + columnIndex: PropTypes.number.isRequired, onUpdate: PropTypes.func.isRequired, onEscape: PropTypes.func.isRequired, timeToCloseMessage: PropTypes.number, @@ -123,7 +125,7 @@ export default _ => render() { const { invalidMessage } = this.state; - const { row, column, className, style } = this.props; + const { row, column, className, style, rowIndex, columnIndex } = this.props; const { dataField } = column; const value = _.get(row, dataField); @@ -133,7 +135,21 @@ export default _ => }; const hasError = _.isDefined(invalidMessage); - const editorClass = hasError ? cs('animated', 'shake') : null; + let customEditorClass = column.editorClasses || ''; + if (_.isFunction(column.editorClasses)) { + customEditorClass = column.editorClasses(value, row, rowIndex, columnIndex); + } + + let editorStyle = column.editorStyle || {}; + if (_.isFunction(column.editorStyle)) { + editorStyle = column.editorStyle(value, row, rowIndex, columnIndex); + } + + const editorClass = cs({ + animated: hasError, + shake: hasError + }, customEditorClass); + return (
); } diff --git a/packages/react-bootstrap-table2-editor/src/text-editor.js b/packages/react-bootstrap-table2-editor/src/text-editor.js index 7937282b6..b44c2da30 100644 --- a/packages/react-bootstrap-table2-editor/src/text-editor.js +++ b/packages/react-bootstrap-table2-editor/src/text-editor.js @@ -10,6 +10,10 @@ class TextEditor extends Component { this.text.focus(); } + getValue() { + return this.text.value; + } + render() { const { defaultValue, className, ...rest } = this.props; const editorClass = cs('form-control editor edit-text', className); diff --git a/packages/react-bootstrap-table2-editor/src/textarea-editor.js b/packages/react-bootstrap-table2-editor/src/textarea-editor.js new file mode 100644 index 000000000..e65b27ecd --- /dev/null +++ b/packages/react-bootstrap-table2-editor/src/textarea-editor.js @@ -0,0 +1,60 @@ +/* eslint no-return-assign: 0 */ +import React, { Component } from 'react'; +import cs from 'classnames'; +import PropTypes from 'prop-types'; + +class TextAreaEditor extends Component { + constructor(props) { + super(props); + this.handleKeyDown = this.handleKeyDown.bind(this); + } + + componentDidMount() { + const { defaultValue } = this.props; + this.text.value = defaultValue; + this.text.focus(); + } + + getValue() { + return this.text.value; + } + + handleKeyDown(e) { + if (e.keyCode === 13 && !e.shiftKey) return; + if (this.props.onKeyDown) { + this.props.onKeyDown(e); + } + } + + render() { + const { defaultValue, className, ...rest } = this.props; + const editorClass = cs('form-control editor edit-textarea', className); + return ( +
this.editor = node } defaultValue={ value } + style={ editorStyle } className={ editorClass } { ...editorAttrs } /> diff --git a/packages/react-bootstrap-table2-editor/test/editing-cell.test.js b/packages/react-bootstrap-table2-editor/test/editing-cell.test.js index 9b34d9388..2741ee103 100644 --- a/packages/react-bootstrap-table2-editor/test/editing-cell.test.js +++ b/packages/react-bootstrap-table2-editor/test/editing-cell.test.js @@ -28,6 +28,9 @@ describe('EditingCell', () => { name: 'A' }; + const rowIndex = 1; + const columnIndex = 1; + let column = { dataField: 'id', text: 'ID' @@ -39,6 +42,8 @@ describe('EditingCell', () => { wrapper = shallow( { expect(textEditor.props().defaultValue).toEqual(row[column.dataField]); expect(textEditor.props().onKeyDown).toBeDefined(); expect(textEditor.props().onBlur).toBeDefined(); - expect(textEditor.props().className).toBeNull(); + expect(textEditor.props().className).toEqual(''); }); it('should not render EditorIndicator due to state.invalidMessage is null', () => { @@ -92,6 +97,8 @@ describe('EditingCell', () => { wrapper = shallow( { wrapper = shallow( { }); }); + describe('if column.editorClasses is defined', () => { + let columnWithEditorClasses; + const classes = 'test test1'; + + describe('and it is a function', () => { + beforeEach(() => { + columnWithEditorClasses = { + ...column, + editorClasses: jest.fn(() => classes) + }; + wrapper = shallow( + + ); + }); + + it('should render TextEditor with correct props', () => { + const textEditor = wrapper.find(TextEditor); + expect(textEditor.props().className).toEqual(classes); + }); + + it('should call column.editorClasses correctly', () => { + expect(columnWithEditorClasses.editorClasses).toHaveBeenCalledTimes(1); + expect(columnWithEditorClasses.editorClasses).toHaveBeenCalledWith( + _.get(row, column.dataField), + row, + rowIndex, + columnIndex + ); + }); + }); + + describe('and it is a string', () => { + beforeEach(() => { + columnWithEditorClasses = { + ...column, + editorClasses: classes + }; + wrapper = shallow( + + ); + }); + + it('should render TextEditor with correct props', () => { + const textEditor = wrapper.find(TextEditor); + expect(textEditor.props().className).toEqual(classes); + }); + }); + }); + + describe('if column.editorStyle is defined', () => { + let columnWithEditorStyle; + const style = { color: 'red' }; + + describe('and it is a function', () => { + beforeEach(() => { + columnWithEditorStyle = { + ...column, + editorStyle: jest.fn(() => style) + }; + wrapper = shallow( + + ); + }); + + it('should render TextEditor with correct props', () => { + const textEditor = wrapper.find(TextEditor); + expect(textEditor.props().style).toEqual(style); + }); + + it('should call column.editorStyle correctly', () => { + expect(columnWithEditorStyle.editorStyle).toHaveBeenCalledTimes(1); + expect(columnWithEditorStyle.editorStyle).toHaveBeenCalledWith( + _.get(row, column.dataField), + row, + rowIndex, + columnIndex + ); + }); + }); + + describe('and it is an object', () => { + beforeEach(() => { + columnWithEditorStyle = { + ...column, + editorStyle: style + }; + wrapper = shallow( + + ); + }); + + it('should render TextEditor with correct props', () => { + const textEditor = wrapper.find(TextEditor); + expect(textEditor.props().style).toEqual(style); + }); + }); + }); + describe('if blurToSave prop is true', () => { beforeEach(() => { wrapper = mount( { wrapper = mount( + (cell > 2101 ? 'editing-price-bigger-than-2101' : 'editing-price-small-than-2101') +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import cellEditFactory from 'react-bootstrap-table2-editor'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name', + editorClasses: 'editing-name' +}, { + dataField: 'price', + text: 'Product Price', + editorClasses: (cell, row, rowIndex, colIndex) => + (cell > 2101 ? 'editing-price-bigger-than-2101' : 'editing-price-small-than-2101') +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/cell-edit/editor-style-table.js b/packages/react-bootstrap-table2-example/examples/cell-edit/editor-style-table.js new file mode 100644 index 000000000..37bf5bf96 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/cell-edit/editor-style-table.js @@ -0,0 +1,69 @@ +/* eslint no-unused-vars: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import cellEditFactory from 'react-bootstrap-table2-editor'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name', + editorStyle: { + backgroundColor: '#20B2AA' + } +}, { + dataField: 'price', + text: 'Product Price', + editorStyle: (cell, row, rowIndex, colIndex) => { + const backgroundColor = cell > 2101 ? '#00BFFF' : '#00FFFF'; + return { backgroundColor }; + } +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import cellEditFactory from 'react-bootstrap-table2-editor'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name', + editorStyle: { + backgroundColor: '#20B2AA' + } +}, { + dataField: 'price', + text: 'Product Price', + editorStyle: (cell, row, rowIndex, colIndex) => { + const backgroundColor = cell > 2101 ? '#00BFFF' : '#00FFFF'; + return { backgroundColor }; + } +}]; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 3f116f508..ae50d60ed 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -73,6 +73,8 @@ import CellEditHooks from 'examples/cell-edit/cell-edit-hooks-table'; import CellEditValidator from 'examples/cell-edit/cell-edit-validator-table'; import CellEditStyleTable from 'examples/cell-edit/cell-edit-style-table'; import CellEditClassTable from 'examples/cell-edit/cell-edit-class-table'; +import EditorStyleTable from 'examples/cell-edit/editor-style-table'; +import EditorClassTable from 'examples/cell-edit/editor-class-table'; // work on row selection import SingleSelectionTable from 'examples/row-selection/single-selection'; @@ -186,8 +188,10 @@ storiesOf('Cell Editing', module) .add('Cell Level Editable', () => ) .add('Rich Hook Functions', () => ) .add('Validation', () => ) - .add('Custom Cell Style When Editing', () => ) - .add('Custom Cell Classes When Editing', () => ); + .add('Custom Cell Style', () => ) + .add('Custom Cell Classes', () => ) + .add('Custom Editor Classes', () => ) + .add('Custom Editor Style', () => ); storiesOf('Row Selection', module) .add('Single Selection', () => ) diff --git a/packages/react-bootstrap-table2/src/header-cell.js b/packages/react-bootstrap-table2/src/header-cell.js index bb012d182..69fdfed11 100644 --- a/packages/react-bootstrap-table2/src/header-cell.js +++ b/packages/react-bootstrap-table2/src/header-cell.js @@ -130,6 +130,8 @@ HeaderCell.propTypes = { editable: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]), editCellStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), editCellClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), + editorStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), + editorClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), validator: PropTypes.func, filter: PropTypes.object, filterValue: PropTypes.func diff --git a/packages/react-bootstrap-table2/src/row.js b/packages/react-bootstrap-table2/src/row.js index 3efb0c529..b6222bb07 100644 --- a/packages/react-bootstrap-table2/src/row.js +++ b/packages/react-bootstrap-table2/src/row.js @@ -79,7 +79,9 @@ class Row extends eventDelegater(Component) { Date: Sat, 31 Mar 2018 22:30:59 -0700 Subject: [PATCH 055/576] Fix textFilter() for Internet Explorer (includes() and find() are not supported) (#274) * Fix textFilter() for Internet Explorer 11 - replace includes() with indexOf() !== -1 - replace find() with for loop * Requested changes; more readability with for loop - use .length of the columns instead of the Object.keys() --- packages/react-bootstrap-table2-filter/src/filter.js | 10 ++++++++-- packages/react-bootstrap-table2/src/sort/wrapper.js | 9 +++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/react-bootstrap-table2-filter/src/filter.js b/packages/react-bootstrap-table2-filter/src/filter.js index f16674228..e0d7a452b 100644 --- a/packages/react-bootstrap-table2-filter/src/filter.js +++ b/packages/react-bootstrap-table2-filter/src/filter.js @@ -21,7 +21,7 @@ export const filterByText = _ => ( if (caseSensitive) { return cellStr.includes(filterVal); } - return cellStr.toLocaleUpperCase().includes(filterVal.toLocaleUpperCase()); + return cellStr.toLocaleUpperCase().indexOf(filterVal.toLocaleUpperCase()) !== -1; }); export const filterByNumber = _ => ( @@ -106,7 +106,13 @@ export const filters = (store, columns, _) => (currFilters) => { Object.keys(currFilters).forEach((dataField) => { const filterObj = currFilters[dataField]; filterFn = factory(filterObj.filterType); - const { filterValue } = columns.find(col => col.dataField === dataField); + let filterValue; + for (let i = 0; i < columns.length; i += 1) { + if (columns[i].dataField === dataField) { + filterValue = columns[i].filterValue; + break; + } + } result = filterFn(result, dataField, filterObj, filterValue); }); return result; diff --git a/packages/react-bootstrap-table2/src/sort/wrapper.js b/packages/react-bootstrap-table2/src/sort/wrapper.js index 71c50511c..8528e0f0b 100644 --- a/packages/react-bootstrap-table2/src/sort/wrapper.js +++ b/packages/react-bootstrap-table2/src/sort/wrapper.js @@ -39,8 +39,13 @@ export default Base => } componentWillReceiveProps(nextProps) { - const sortedColumn = nextProps.columns.find( - column => column.dataField === nextProps.store.sortField); + let sortedColumn; + for (let i = 0; i < nextProps.columns.length; i += 1) { + if (nextProps.columns[i].dataField === nextProps.store.sortField) { + sortedColumn = nextProps.columns[i]; + break; + } + } if (sortedColumn && sortedColumn.sort) { nextProps.store.sortBy(sortedColumn); } From 41dc3ef6191e9f6d7528fffdb1a125a202c64dc0 Mon Sep 17 00:00:00 2001 From: Patrick O'Meara Date: Sun, 1 Apr 2018 15:32:24 +1000 Subject: [PATCH 056/576] empty noDataIndication when empty (#275) * don't display unneeded empty row when noDataIndication isn't set --- packages/react-bootstrap-table2/src/body.js | 3 +++ packages/react-bootstrap-table2/test/body.test.js | 8 +++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/react-bootstrap-table2/src/body.js b/packages/react-bootstrap-table2/src/body.js index 9ee9e898e..b4ca400c0 100644 --- a/packages/react-bootstrap-table2/src/body.js +++ b/packages/react-bootstrap-table2/src/body.js @@ -35,6 +35,9 @@ const Body = (props) => { if (isEmpty) { const indication = _.isFunction(noDataIndication) ? noDataIndication() : noDataIndication; + if (!indication) { + return null; + } content = ; } else { const nonEditableRows = cellEdit.nonEditableRows || []; diff --git a/packages/react-bootstrap-table2/test/body.test.js b/packages/react-bootstrap-table2/test/body.test.js index 5674b83fe..ea624e51f 100644 --- a/packages/react-bootstrap-table2/test/body.test.js +++ b/packages/react-bootstrap-table2/test/body.test.js @@ -53,12 +53,10 @@ describe('Body', () => { />); }); - it('should render successfully', () => { + it('should not render', () => { expect(wrapper.length).toBe(1); - expect(wrapper.find('tbody').length).toBe(1); - expect(wrapper.find(RowSection).length).toBe(1); - expect(wrapper.find(RowSection).prop('colSpan')).toBe(columns.length); - expect(wrapper.find(RowSection).prop('content')).toBe(null); + expect(wrapper.find('tbody').length).toBe(0); + expect(wrapper.find(RowSection).length).toBe(0); }); describe('when noDataIndication props is defined', () => { From 11d4f40089879e5e4f830c0e4f5c76c9a9c064a3 Mon Sep 17 00:00:00 2001 From: Patrick O'Meara Date: Sun, 1 Apr 2018 15:34:06 +1000 Subject: [PATCH 057/576] noDataIndication (#276) * use the correct amount of cells when the first row is select * storybook added for development, not necessary in docs fixes react-bootstrap-table/react-bootstrap-table2#264 --- .../row-selection/selection-no-data.js | 62 +++++++++++++++++++ .../stories/index.js | 2 + .../src/props-resolver/column-resolver.js | 9 ++- .../src/props-resolver/index.js | 6 +- .../test/props-resolver/index.test.js | 4 +- 5 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js diff --git a/packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js b/packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js new file mode 100644 index 000000000..4867ffd9c --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js @@ -0,0 +1,62 @@ +/* eslint no-unused-vars: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import Code from 'components/common/code-block'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const selectRow1 = { + mode: 'checkbox', + clickToSelect: true +}; + +const sourceCode1 = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const selectRow = { + mode: 'checkbox', + clickToSelect: true +}; + + +`; + +export default () => ( +
+ + { sourceCode1 } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index ae50d60ed..206f1eee0 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -83,6 +83,7 @@ import ClickToSelectTable from 'examples/row-selection/click-to-select'; import DefaultSelectTable from 'examples/row-selection/default-select'; import SelectionManagement from 'examples/row-selection/selection-management'; import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-select-with-cell-edit'; +import SelectionNoDataTable from 'examples/row-selection/selection-no-data'; import SelectionStyleTable from 'examples/row-selection/selection-style'; import SelectionClassTable from 'examples/row-selection/selection-class'; import NonSelectableRowsTable from 'examples/row-selection/non-selectable-rows'; @@ -200,6 +201,7 @@ storiesOf('Row Selection', module) .add('Default Select', () => ) .add('Selection Management', () => ) .add('Click to Select and Edit Cell', () => ) + .add('Selection without Data', () => ) .add('Selection Style', () => ) .add('Selection Class', () => ) .add('Selection Background Color', () => ) diff --git a/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js b/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js index 584649896..c330c7d5e 100644 --- a/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js +++ b/packages/react-bootstrap-table2/src/props-resolver/column-resolver.js @@ -1,6 +1,11 @@ export default ExtendBase => class ColumnResolver extends ExtendBase { - visibleColumnSize() { - return this.props.columns.filter(c => !c.hidden).length; + visibleColumnSize(includeSelectColumn = true) { + const columnLen = this.props.columns.filter(c => !c.hidden).length; + if (!includeSelectColumn) return columnLen; + if (this.props.selectRow && !this.props.selectRow.hideSelectColumn) { + return columnLen + 1; + } + return columnLen; } }; diff --git a/packages/react-bootstrap-table2/src/props-resolver/index.js b/packages/react-bootstrap-table2/src/props-resolver/index.js index 4871e2d5e..4f40d97fc 100644 --- a/packages/react-bootstrap-table2/src/props-resolver/index.js +++ b/packages/react-bootstrap-table2/src/props-resolver/index.js @@ -5,12 +5,12 @@ import _ from '../utils'; export default ExtendBase => class TableResolver extends ColumnResolver(ExtendBase) { validateProps() { - const { columns, keyField } = this.props; + const { keyField } = this.props; if (!keyField) { throw new Error('Please specify a field as key via keyField'); } - if (this.visibleColumnSize(columns) <= 0) { - throw new Error('No any visible columns detect'); + if (this.visibleColumnSize(false) <= 0) { + throw new Error('No visible columns detected'); } } diff --git a/packages/react-bootstrap-table2/test/props-resolver/index.test.js b/packages/react-bootstrap-table2/test/props-resolver/index.test.js index 1b6bf8c9d..cb3a54b52 100644 --- a/packages/react-bootstrap-table2/test/props-resolver/index.test.js +++ b/packages/react-bootstrap-table2/test/props-resolver/index.test.js @@ -56,7 +56,7 @@ describe('TableResolver', () => { }); }); - describe('if columns is all unvisible', () => { + describe('if no columns are visible', () => { beforeEach(() => { const mockElement = React.createElement(BootstrapTableMock, { data, keyField, columns: [] @@ -67,7 +67,7 @@ describe('TableResolver', () => { it('should throw error', () => { expect(() => wrapper.instance().validateProps() - ).toThrow(new Error('No any visible columns detect')); + ).toThrow(new Error('No visible columns detected')); }); }); }); From 88e1a0774b91308bbb265209fe178ca082a8d5e3 Mon Sep 17 00:00:00 2001 From: Allen Date: Sun, 1 Apr 2018 14:14:32 +0800 Subject: [PATCH 058/576] fix #281 --- docs/README.md | 4 ++ .../examples/sort/default-sort-direction.js | 67 +++++++++++++++++++ .../stories/index.js | 2 + .../src/bootstrap-table.js | 1 + .../src/sort/wrapper.js | 6 +- .../react-bootstrap-table2/src/store/index.js | 4 +- .../react-bootstrap-table2/src/store/sort.js | 4 +- .../test/store/index.test.js | 7 +- .../test/store/sort.test.js | 4 ++ 9 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/sort/default-sort-direction.js diff --git a/docs/README.md b/docs/README.md index 34b38df98..181b4a809 100644 --- a/docs/README.md +++ b/docs/README.md @@ -23,6 +23,7 @@ * [rowClasses](#rowClasses) * [rowEvents](#rowEvents) * [defaultSorted](#defaultSorted) +* [defaultSortDirection](#defaultSortDirection) * [pagination](#pagination) * [filter](#filter) * [onTableChange](#onTableChange) @@ -168,6 +169,9 @@ const defaultSorted = [{ }]; ``` +### defaultSortDirection - [String] +Default sort direction when user click on header column at first time, available value is `asc` and `desc`. Default is `desc`. + ### pagination - [Object] `pagination` allow user to render a pagination panel on the bottom of table. But pagination functionality is separated from core of `react-bootstrap-table2` so that you are suppose to install `react-bootstrap-table2-paginator` additionally. diff --git a/packages/react-bootstrap-table2-example/examples/sort/default-sort-direction.js b/packages/react-bootstrap-table2-example/examples/sort/default-sort-direction.js new file mode 100644 index 000000000..f5c0aeafc --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/sort/default-sort-direction.js @@ -0,0 +1,67 @@ +/* eslint react/prefer-stateless-function: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(); + +const columns = [{ + dataField: 'id', + text: 'Product ID', + sort: true +}, { + dataField: 'name', + text: 'Product Name', + sort: true +}, { + dataField: 'price', + text: 'Product Price', + sort: true +}]; + + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const columns = [{ + dataField: 'id', + text: 'Product ID', + sort: true +}, { + dataField: 'name', + text: 'Product Name', + sort: true +}, { + dataField: 'price', + text: 'Product Price', + sort: true +}]; + +const defaultSorted = [{ + dataField: 'name', + order: 'desc' +}]; + + +`; + + +class DefaultSortDirectionTable extends React.PureComponent { + render() { + return ( +
+ + { sourceCode } +
+ ); + } +} + +export default DefaultSortDirectionTable; diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 206f1eee0..25d8538a3 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -57,6 +57,7 @@ import RowEventTable from 'examples/rows/row-event'; // table sort import EnableSortTable from 'examples/sort/enable-sort-table'; import DefaultSortTable from 'examples/sort/default-sort-table'; +import DefaultSortDirectionTable from 'examples/sort/default-sort-direction'; import SortEvents from 'examples/sort/sort-events'; import CustomSortTable from 'examples/sort/custom-sort-table'; import HeaderSortingClassesTable from 'examples/sort/header-sorting-classes'; @@ -175,6 +176,7 @@ storiesOf('Work on Rows', module) storiesOf('Sort Table', module) .add('Enable Sort', () => ) .add('Default Sort Table', () => ) + .add('Default Sort Direction Table', () => ) .add('Sort Events', () => ) .add('Custom Sort Fuction', () => ) .add('Custom Classes on Sorting Header Column', () => ) diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index 743eb3b00..0e801cb0e 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -149,6 +149,7 @@ BootstrapTable.propTypes = { dataField: PropTypes.string.isRequired, order: PropTypes.oneOf([Const.SORT_DESC, Const.SORT_ASC]).isRequired })), + defaultSortDirection: PropTypes.oneOf([Const.SORT_DESC, Const.SORT_ASC]), overlay: PropTypes.func, onTableChange: PropTypes.func, onSort: PropTypes.func, diff --git a/packages/react-bootstrap-table2/src/sort/wrapper.js b/packages/react-bootstrap-table2/src/sort/wrapper.js index 8528e0f0b..d20d207d6 100644 --- a/packages/react-bootstrap-table2/src/sort/wrapper.js +++ b/packages/react-bootstrap-table2/src/sort/wrapper.js @@ -15,7 +15,7 @@ export default Base => } componentWillMount() { - const { columns, defaultSorted, store } = this.props; + const { columns, defaultSorted, defaultSortDirection, store } = this.props; // defaultSorted is an array, it's ready to use as multi / single sort // when we start to support multi sort, please update following code to use array.forEach if (defaultSorted && defaultSorted.length > 0) { @@ -23,7 +23,7 @@ export default Base => const order = defaultSorted[0].order; const column = columns.filter(col => col.dataField === dataField); if (column.length > 0) { - store.setSort(column[0], order); + store.setSort(column[0], order, defaultSortDirection); if (column[0].onSort) { column[0].onSort(store.sortField, store.sortOrder); @@ -53,7 +53,7 @@ export default Base => handleSort(column) { const { store } = this.props; - store.setSort(column); + store.setSort(column, undefined, this.props.defaultSortDirection); if (column.onSort) { column.onSort(store.sortField, store.sortOrder); diff --git a/packages/react-bootstrap-table2/src/store/index.js b/packages/react-bootstrap-table2/src/store/index.js index 6711c99e7..f0d7933a4 100644 --- a/packages/react-bootstrap-table2/src/store/index.js +++ b/packages/react-bootstrap-table2/src/store/index.js @@ -21,8 +21,8 @@ export default class Store { if (row) _.set(row, dataField, newValue); } - setSort({ dataField }, order) { - this.sortOrder = nextOrder(this)(dataField, order); + setSort({ dataField }, order, defaultOrder) { + this.sortOrder = nextOrder(this)(dataField, order, defaultOrder); this.sortField = dataField; } diff --git a/packages/react-bootstrap-table2/src/store/sort.js b/packages/react-bootstrap-table2/src/store/sort.js index a2228bb1e..1987e0ef5 100644 --- a/packages/react-bootstrap-table2/src/store/sort.js +++ b/packages/react-bootstrap-table2/src/store/sort.js @@ -37,11 +37,11 @@ export const sort = ({ data, sortOrder, sortField }) => (sortFunc) => { return _data; }; -export const nextOrder = store => (field, order) => { +export const nextOrder = store => (field, order, defaultOrder = Const.SORT_DESC) => { if (order) return order; if (field !== store.sortField) { - return Const.SORT_DESC; + return defaultOrder; } return store.sortOrder === Const.SORT_DESC ? Const.SORT_ASC : Const.SORT_DESC; }; diff --git a/packages/react-bootstrap-table2/test/store/index.test.js b/packages/react-bootstrap-table2/test/store/index.test.js index dc8b28e42..a257272cf 100644 --- a/packages/react-bootstrap-table2/test/store/index.test.js +++ b/packages/react-bootstrap-table2/test/store/index.test.js @@ -56,10 +56,15 @@ describe('Store Base', () => { expect(store.sortOrder).toEqual(Const.SORT_DESC); }); - it('should force assign sortOrder correctly if second argument is passed', () => { + it('should force assign sortOrder correctly if second argument is given', () => { store.setSort({ dataField }, Const.SORT_DESC); expect(store.sortOrder).toEqual(Const.SORT_DESC); }); + + it('should force assign sortOrder correctly if third argument is given', () => { + store.setSort({ dataField }, undefined, Const.SORT_ASC); + expect(store.sortOrder).toEqual(Const.SORT_ASC); + }); }); describe('sortBy', () => { diff --git a/packages/react-bootstrap-table2/test/store/sort.test.js b/packages/react-bootstrap-table2/test/store/sort.test.js index 3279cd53d..33422b94c 100644 --- a/packages/react-bootstrap-table2/test/store/sort.test.js +++ b/packages/react-bootstrap-table2/test/store/sort.test.js @@ -63,6 +63,10 @@ describe('Sort Function', () => { expect(nextOrder(store)('name')).toBe(Const.SORT_DESC); }); + it('should return correcly order when store.sortField is not eq next sort field and default sort direction is given', () => { + expect(nextOrder(store)('name', undefined, Const.SORT_ASC)).toBe(Const.SORT_ASC); + }); + it('should return correcly order when store.sortField is eq next sort field', () => { store.sortField = 'name'; store.sortOrder = Const.SORT_DESC; From e8458b4b6331512719774d45ec8bf4e37614fb2f Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sun, 1 Apr 2018 15:56:53 +0800 Subject: [PATCH 059/576] Publish - react-bootstrap-table2-editor@0.1.4 - react-bootstrap-table2-example@0.1.5 - react-bootstrap-table2-filter@0.1.4 - react-bootstrap-table-next@0.1.6 --- packages/react-bootstrap-table2-editor/package.json | 2 +- packages/react-bootstrap-table2-example/package.json | 2 +- packages/react-bootstrap-table2-filter/package.json | 2 +- packages/react-bootstrap-table2/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-bootstrap-table2-editor/package.json b/packages/react-bootstrap-table2-editor/package.json index 86bb4d9a4..595b63d6a 100644 --- a/packages/react-bootstrap-table2-editor/package.json +++ b/packages/react-bootstrap-table2-editor/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-editor", - "version": "0.1.3", + "version": "0.1.4", "description": "it's the editor addon for react-bootstrap-table2", "main": "./lib/index.js", "scripts": { diff --git a/packages/react-bootstrap-table2-example/package.json b/packages/react-bootstrap-table2-example/package.json index 5a0ead8a7..3626c28c7 100644 --- a/packages/react-bootstrap-table2-example/package.json +++ b/packages/react-bootstrap-table2-example/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-example", - "version": "0.1.4", + "version": "0.1.5", "description": "", "main": "index.js", "private": true, diff --git a/packages/react-bootstrap-table2-filter/package.json b/packages/react-bootstrap-table2-filter/package.json index 77dd46812..bd9c0120c 100644 --- a/packages/react-bootstrap-table2-filter/package.json +++ b/packages/react-bootstrap-table2-filter/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-filter", - "version": "0.1.3", + "version": "0.1.4", "description": "it's a column filter addon for react-bootstrap-table2", "main": "./lib/index.js", "repository": { diff --git a/packages/react-bootstrap-table2/package.json b/packages/react-bootstrap-table2/package.json index c9fc9b89a..8dd50de7e 100644 --- a/packages/react-bootstrap-table2/package.json +++ b/packages/react-bootstrap-table2/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table-next", - "version": "0.1.5", + "version": "0.1.6", "description": "Next generation of react-bootstrap-table", "main": "./lib/index.js", "repository": { From 3dc9cd39414be5468ac714bf8fa469be9d098b76 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Mon, 2 Apr 2018 23:46:59 +0800 Subject: [PATCH 060/576] Publish - react-bootstrap-table2-editor@0.1.5 - react-bootstrap-table2-filter@0.1.5 - react-bootstrap-table-next@0.1.7 --- packages/react-bootstrap-table2-editor/package.json | 2 +- packages/react-bootstrap-table2-filter/package.json | 2 +- packages/react-bootstrap-table2/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-bootstrap-table2-editor/package.json b/packages/react-bootstrap-table2-editor/package.json index 595b63d6a..d6a5b1a81 100644 --- a/packages/react-bootstrap-table2-editor/package.json +++ b/packages/react-bootstrap-table2-editor/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-editor", - "version": "0.1.4", + "version": "0.1.5", "description": "it's the editor addon for react-bootstrap-table2", "main": "./lib/index.js", "scripts": { diff --git a/packages/react-bootstrap-table2-filter/package.json b/packages/react-bootstrap-table2-filter/package.json index bd9c0120c..19c06b876 100644 --- a/packages/react-bootstrap-table2-filter/package.json +++ b/packages/react-bootstrap-table2-filter/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table2-filter", - "version": "0.1.4", + "version": "0.1.5", "description": "it's a column filter addon for react-bootstrap-table2", "main": "./lib/index.js", "repository": { diff --git a/packages/react-bootstrap-table2/package.json b/packages/react-bootstrap-table2/package.json index 8dd50de7e..f880ab7ad 100644 --- a/packages/react-bootstrap-table2/package.json +++ b/packages/react-bootstrap-table2/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-table-next", - "version": "0.1.6", + "version": "0.1.7", "description": "Next generation of react-bootstrap-table", "main": "./lib/index.js", "repository": { From f34cb4bf6353b48240afa9f97d64fbf0a23fd2b0 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Mon, 26 Mar 2018 23:49:27 +0800 Subject: [PATCH 061/576] allow user to filter column without inputField * wrap onFilter to HOF to allow filter dynamically --- .../src/wrapper.js | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/packages/react-bootstrap-table2-filter/src/wrapper.js b/packages/react-bootstrap-table2-filter/src/wrapper.js index f48e0316d..9a64eb1ed 100644 --- a/packages/react-bootstrap-table2-filter/src/wrapper.js +++ b/packages/react-bootstrap-table2-filter/src/wrapper.js @@ -40,33 +40,42 @@ export default (Base, { } } - onFilter(column, filterVal, filterType) { - const { store, columns } = this.props; - const currFilters = Object.assign({}, this.state.currFilters); - const { dataField, filter } = column; + /** + * filter the table like below: + * onFilter(column, filterType)(filterVal) + * @param {Object} column + * @param {String} filterType + * @param {String} filterVal - user input for filtering. + */ + onFilter(column, filterType) { + return (filterVal) => { + const { store, columns } = this.props; + const currFilters = Object.assign({}, this.state.currFilters); + const { dataField, filter } = column; - if (!_.isDefined(filterVal) || filterVal === '') { - delete currFilters[dataField]; - } else { - // select default comparator is EQ, others are LIKE - const { - comparator = (filterType === FILTER_TYPE.SELECT ? EQ : LIKE), - caseSensitive = false - } = filter.props; - currFilters[dataField] = { filterVal, filterType, comparator, caseSensitive }; - } - store.filters = currFilters; + if (!_.isDefined(filterVal) || filterVal === '') { + delete currFilters[dataField]; + } else { + // select default comparator is EQ, others are LIKE + const { + comparator = (filterType === FILTER_TYPE.SELECT ? EQ : LIKE), + caseSensitive = false + } = filter.props; + currFilters[dataField] = { filterVal, filterType, comparator, caseSensitive }; + } + store.filters = currFilters; - if (this.isRemoteFiltering() || this.isRemotePagination()) { - this.handleRemoteFilterChange(); - // when remote filtering is enable, dont set currFilters state - // in the componentWillReceiveProps, - // it's the key point that we can know the filter is changed - return; - } + if (this.isRemoteFiltering() || this.isRemotePagination()) { + this.handleRemoteFilterChange(); + // when remote filtering is enable, dont set currFilters state + // in the componentWillReceiveProps, + // it's the key point that we can know the filter is changed + return; + } - store.filteredData = filters(store, columns, _)(currFilters); - this.setState(() => ({ currFilters, isDataChanged: true })); + store.filteredData = filters(store, columns, _)(currFilters); + this.setState(() => ({ currFilters, isDataChanged: true })); + }; } render() { From a1477e2ad38b29f66e9652634caa2d59ee5a6c18 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Tue, 27 Mar 2018 00:16:33 +0800 Subject: [PATCH 062/576] filter column by new onFilter --- .../src/components/number.js | 12 ++++++------ .../src/components/select.js | 10 +++++----- .../src/components/text.js | 13 +++++++++---- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/react-bootstrap-table2-filter/src/components/number.js b/packages/react-bootstrap-table2-filter/src/components/number.js index 3c2b61286..5a996923d 100644 --- a/packages/react-bootstrap-table2-filter/src/components/number.js +++ b/packages/react-bootstrap-table2-filter/src/components/number.js @@ -34,7 +34,7 @@ class NumberFilter extends Component { const comparator = this.numberFilterComparator.value; const number = this.numberFilter.value; if (comparator && number) { - onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number, comparator }); } } @@ -53,7 +53,7 @@ class NumberFilter extends Component { } const filterValue = e.target.value; this.timeout = setTimeout(() => { - onFilter(column, { number: filterValue, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number: filterValue, comparator }); }, delay); } @@ -65,7 +65,7 @@ class NumberFilter extends Component { // if (comparator === '') { // return; // } - onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number: value, comparator }); } onChangeComparator(e) { @@ -75,7 +75,7 @@ class NumberFilter extends Component { // if (value === '') { // return; // } - onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number: value, comparator }); } getComparatorOptions() { @@ -116,7 +116,7 @@ class NumberFilter extends Component { this.setState(() => ({ isSelected: (number !== '') })); this.numberFilterComparator.value = comparator; this.numberFilter.value = number; - onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number, comparator }); } cleanFiltered() { @@ -126,7 +126,7 @@ class NumberFilter extends Component { this.setState(() => ({ isSelected: (value !== '') })); this.numberFilterComparator.value = comparator; this.numberFilter.value = value; - onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER); + onFilter(column, FILTER_TYPE.NUMBER)({ number: value, comparator }); } render() { diff --git a/packages/react-bootstrap-table2-filter/src/components/select.js b/packages/react-bootstrap-table2-filter/src/components/select.js index 7e17afd7a..852938c89 100644 --- a/packages/react-bootstrap-table2-filter/src/components/select.js +++ b/packages/react-bootstrap-table2-filter/src/components/select.js @@ -27,7 +27,7 @@ class SelectFilter extends Component { componentDidMount() { const value = this.selectInput.value; if (value && value !== '') { - this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); } } @@ -41,7 +41,7 @@ class SelectFilter extends Component { if (needFilter) { const value = this.selectInput.value; if (value) { - this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); } } } @@ -64,19 +64,19 @@ class SelectFilter extends Component { const value = (this.props.defaultValue !== undefined) ? this.props.defaultValue : ''; this.setState(() => ({ isSelected: value !== '' })); this.selectInput.value = value; - this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); } applyFilter(value) { this.selectInput.value = value; this.setState(() => ({ isSelected: value !== '' })); - this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); } filter(e) { const { value } = e.target; this.setState(() => ({ isSelected: value !== '' })); - this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT); + this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); } render() { diff --git a/packages/react-bootstrap-table2-filter/src/components/text.js b/packages/react-bootstrap-table2-filter/src/components/text.js index ffbe70272..154f30811 100644 --- a/packages/react-bootstrap-table2-filter/src/components/text.js +++ b/packages/react-bootstrap-table2-filter/src/components/text.js @@ -17,10 +17,14 @@ class TextFilter extends Component { value: props.defaultValue }; } + componentDidMount() { + const { onFilter } = this.props; + const defaultValue = this.input.value; + if (defaultValue) { - this.props.onFilter(this.props.column, defaultValue, FILTER_TYPE.TEXT); + onFilter(this.props.column, FILTER_TYPE.TEXT)(defaultValue); } } @@ -40,7 +44,7 @@ class TextFilter extends Component { const filterValue = e.target.value; this.setState(() => ({ value: filterValue })); this.timeout = setTimeout(() => { - this.props.onFilter(this.props.column, filterValue, FILTER_TYPE.TEXT); + this.props.onFilter(this.props.column, FILTER_TYPE.TEXT)(filterValue); }, this.props.delay); } @@ -53,12 +57,12 @@ class TextFilter extends Component { cleanFiltered() { const value = this.props.defaultValue; this.setState(() => ({ value })); - this.props.onFilter(this.props.column, value, FILTER_TYPE.TEXT); + this.props.onFilter(this.props.column, value, FILTER_TYPE.TEXT)(); } applyFilter(filterText) { this.setState(() => ({ value: filterText })); - this.props.onFilter(this.props.column, filterText, FILTER_TYPE.TEXT); + this.props.onFilter(this.props.column, FILTER_TYPE.TEXT)(filterText); } handleClick(e) { @@ -79,6 +83,7 @@ class TextFilter extends Component { defaultValue, ...rest } = this.props; + // stopPropagation for onClick event is try to prevent sort was triggered. return ( Date: Sun, 1 Apr 2018 13:51:11 +0800 Subject: [PATCH 063/576] export onFilter function to allow user to access --- .../src/components/number.js | 17 +++++++++++++++-- .../src/components/select.js | 16 ++++++++++++++-- .../src/components/text.js | 15 ++++++++++++--- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/packages/react-bootstrap-table2-filter/src/components/number.js b/packages/react-bootstrap-table2-filter/src/components/number.js index 5a996923d..3b946cf26 100644 --- a/packages/react-bootstrap-table2-filter/src/components/number.js +++ b/packages/react-bootstrap-table2-filter/src/components/number.js @@ -1,3 +1,4 @@ +/* eslint react/require-default-props: 0 */ /* eslint no-return-assign: 0 */ import React, { Component } from 'react'; @@ -30,12 +31,23 @@ class NumberFilter extends Component { } componentDidMount() { - const { column, onFilter } = this.props; + const { column, onFilter, getFilterBy } = this.props; const comparator = this.numberFilterComparator.value; const number = this.numberFilter.value; if (comparator && number) { onFilter(column, FILTER_TYPE.NUMBER)({ number, comparator }); } + + // export onFilter function to allow users to access + if (getFilterBy) { + getFilterBy((filterVal) => { + this.setState(() => ({ isSelected: (filterVal !== '') })); + onFilter(column, FILTER_TYPE.NUMBER)({ + number: filterVal.number, + comparator: filterVal.comparator + }); + }); + } } componentWillUnmount() { @@ -224,7 +236,8 @@ NumberFilter.propTypes = { comparatorStyle: PropTypes.object, comparatorClassName: PropTypes.string, numberStyle: PropTypes.object, - numberClassName: PropTypes.string + numberClassName: PropTypes.string, + getFilterBy: PropTypes.func }; NumberFilter.defaultProps = { diff --git a/packages/react-bootstrap-table2-filter/src/components/select.js b/packages/react-bootstrap-table2-filter/src/components/select.js index 852938c89..8ba74b217 100644 --- a/packages/react-bootstrap-table2-filter/src/components/select.js +++ b/packages/react-bootstrap-table2-filter/src/components/select.js @@ -25,9 +25,19 @@ class SelectFilter extends Component { } componentDidMount() { + const { column, onFilter, getFilterBy } = this.props; + const value = this.selectInput.value; if (value && value !== '') { - this.props.onFilter(this.props.column, FILTER_TYPE.SELECT)(value); + onFilter(column, FILTER_TYPE.SELECT)(value); + } + + // export onFilter function to allow users to access + if (getFilterBy) { + getFilterBy((filterVal) => { + this.setState(() => ({ isSelected: filterVal !== '' })); + onFilter(column, FILTER_TYPE.SELECT)(filterVal); + }); } } @@ -90,6 +100,7 @@ class SelectFilter extends Component { comparator, withoutEmptyOption, caseSensitive, + getFilterBy, ...rest } = this.props; @@ -121,7 +132,8 @@ SelectFilter.propTypes = { className: PropTypes.string, withoutEmptyOption: PropTypes.bool, defaultValue: PropTypes.any, - caseSensitive: PropTypes.bool + caseSensitive: PropTypes.bool, + getFilterBy: PropTypes.func }; SelectFilter.defaultProps = { diff --git a/packages/react-bootstrap-table2-filter/src/components/text.js b/packages/react-bootstrap-table2-filter/src/components/text.js index 154f30811..65b6c7d90 100644 --- a/packages/react-bootstrap-table2-filter/src/components/text.js +++ b/packages/react-bootstrap-table2-filter/src/components/text.js @@ -19,13 +19,20 @@ class TextFilter extends Component { } componentDidMount() { - const { onFilter } = this.props; - + const { onFilter, getFilterBy, column } = this.props; const defaultValue = this.input.value; if (defaultValue) { onFilter(this.props.column, FILTER_TYPE.TEXT)(defaultValue); } + + // export onFilter function to allow users to access + if (getFilterBy) { + getFilterBy((filterVal) => { + this.setState(() => ({ value: filterVal })); + onFilter(column, FILTER_TYPE.TEXT)(filterVal); + }); + } } componentWillReceiveProps(nextProps) { @@ -81,6 +88,7 @@ class TextFilter extends Component { onFilter, caseSensitive, defaultValue, + getFilterBy, ...rest } = this.props; @@ -110,7 +118,8 @@ TextFilter.propTypes = { placeholder: PropTypes.string, style: PropTypes.object, className: PropTypes.string, - caseSensitive: PropTypes.bool + caseSensitive: PropTypes.bool, + getFilterBy: PropTypes.func }; TextFilter.defaultProps = { From 09032349d0290365e307880b505350dc5467c616 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sun, 1 Apr 2018 14:49:22 +0800 Subject: [PATCH 064/576] [example] example for programmatically filter by text, number and select --- .../programmatically-number-filter.js | 85 ++++++++++++++++ .../programmatically-select-filter.js | 96 +++++++++++++++++++ .../programmatically-text-filter.js | 80 ++++++++++++++++ .../stories/index.js | 8 +- 4 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js create mode 100644 packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js new file mode 100644 index 000000000..76a26b877 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js @@ -0,0 +1,85 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(8); + +let filterBy; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: numberFilter({ + getFilterBy: (filterByFunc) => { + filterBy = filterByFunc; + } + }) +}]; + +const handleClick = () => { + filterBy({ + number: 2103, + comparator: Comparator.GT + }); +}; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter'; + +let filterBy; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price', + filter: numberFilter({ + getFilterBy: (filterByFunc) => { + filterBy = filterByFunc; + } + }) +}]; + +const handleClick = () => { + filterBy({ + number: 2103, + comparator: Comparator.GT + }); +}; + + + +export default () => ( +
+ + + +
+); +`; + +export default () => ( +
+ + + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js new file mode 100644 index 000000000..b084db29e --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js @@ -0,0 +1,96 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsQualityGenerator } from 'utils/common'; + +const products = productsQualityGenerator(6); + +let filterBy; + +const selectOptions = { + 0: 'good', + 1: 'Bad', + 2: 'unknown' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'quality', + text: 'Product Quailty', + formatter: cell => selectOptions[cell], + filter: selectFilter({ + options: selectOptions, + getFilterBy: (filterByFunc) => { + // filterBy was assigned to onFilter once the component has mount + filterBy = filterByFunc; + } + }) +}]; + +const handleClick = () => { + filterBy('0'); +}; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; + +let filterBy; + +const selectOptions = { + 0: 'good', + 1: 'Bad', + 2: 'unknown' +}; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'quality', + text: 'Product Quailty', + formatter: cell => selectOptions[cell], + filter: selectFilter({ + options: selectOptions, + getFilterBy: (filterByFunc) => { + // filterBy was assigned to onFilter once the component has mount + filterBy = filterByFunc; + } + }) +}]; + +const handleClick = () => { + filterBy('0'); +}; + +export default () => ( +
+ + + +
+); +`; + +export default () => ( +
+ + + + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js new file mode 100644 index 000000000..2e7f01bfa --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js @@ -0,0 +1,80 @@ +import React from 'react'; +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const products = productsGenerator(8); + +let filterBy; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name', + filter: textFilter({ + getFilterBy: (filterByFunc) => { + filterBy = filterByFunc; + } + }) +}, { + dataField: 'price', + text: 'Product Price', + filter: textFilter() +}]; + +const handleClick = () => { + filterBy('0'); +}; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; +import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; + +let filterBy; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name', + filter: textFilter({ + getFilterBy: (filterByFunc) => { + // filterBy was assigned to onFilter once the component has mount + filterBy = filterByFunc; + } + }) +}, { + dataField: 'price', + text: 'Product Price', + filter: textFilter() +}]; + +const handleClick = () => { + filterBy('0'); +}; + +export default () => ( +
+ + + +
+); +`; + +export default () => ( +
+ + + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 25d8538a3..7e3ba5e8d 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -48,6 +48,9 @@ import CustomSelectFilter from 'examples/column-filter/custom-select-filter'; import NumberFilter from 'examples/column-filter/number-filter'; import NumberFilterWithDefaultValue from 'examples/column-filter/number-filter-default-value'; import CustomNumberFilter from 'examples/column-filter/custom-number-filter'; +import ProgrammaticallyTextFilter from 'examples/column-filter/programmatically-text-filter'; +import ProgrammaticallySelectFilter from 'examples/column-filter/programmatically-select-filter'; +import ProgrammaticallyNumberFilter from 'examples/column-filter/programmatically-number-filter'; // work on rows import RowStyleTable from 'examples/rows/row-style'; @@ -166,7 +169,10 @@ storiesOf('Column Filter', module) .add('Custom Text Filter', () => ) .add('Custom Select Filter', () => ) .add('Custom Number Filter', () => ) - .add('Custom Filter Value', () => ); + .add('Custom Filter Value', () => ) + .add('Programmatically Text Filter ', () => ) + .add('Programmatically Select Filter ', () => ) + .add('Programmatically Number Filter ', () => ); storiesOf('Work on Rows', module) .add('Customize Row Style', () => ) From 377534512a35e0f850f9b91052c66db9cd04e3e9 Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Sun, 1 Apr 2018 15:59:26 +0800 Subject: [PATCH 065/576] rename props and variable in samples for better readability --- .../programmatically-number-filter.js | 22 +++++++++---------- .../programmatically-select-filter.js | 20 ++++++++--------- .../programmatically-text-filter.js | 19 ++++++++-------- .../src/components/number.js | 8 +++---- .../src/components/select.js | 10 ++++----- .../src/components/text.js | 10 ++++----- 6 files changed, 45 insertions(+), 44 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js index 76a26b877..12a5ebcb4 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js @@ -6,7 +6,7 @@ import { productsGenerator } from 'utils/common'; const products = productsGenerator(8); -let filterBy; +let priceFilter; const columns = [{ dataField: 'id', @@ -18,14 +18,15 @@ const columns = [{ dataField: 'price', text: 'Product Price', filter: numberFilter({ - getFilterBy: (filterByFunc) => { - filterBy = filterByFunc; + getFilter: (filter) => { + // pricerFilter was assigned once the component has been mounted. + priceFilter = filter; } }) }]; const handleClick = () => { - filterBy({ + priceFilter({ number: 2103, comparator: Comparator.GT }); @@ -35,7 +36,7 @@ const sourceCode = `\ import BootstrapTable from 'react-bootstrap-table-next'; import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter'; -let filterBy; +let priceFilter; const columns = [{ dataField: 'id', @@ -47,24 +48,23 @@ const columns = [{ dataField: 'price', text: 'Product Price', filter: numberFilter({ - getFilterBy: (filterByFunc) => { - filterBy = filterByFunc; + getFilter: (filter) => { + // pricerFilter was assigned once the component has been mounted. + priceFilter = filter; } }) }]; const handleClick = () => { - filterBy({ + priceFilter({ number: 2103, comparator: Comparator.GT }); }; - - export default () => (
- +
diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js index b084db29e..96f00de1d 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js @@ -6,7 +6,7 @@ import { productsQualityGenerator } from 'utils/common'; const products = productsQualityGenerator(6); -let filterBy; +let qualityFilter; const selectOptions = { 0: 'good', @@ -26,22 +26,22 @@ const columns = [{ formatter: cell => selectOptions[cell], filter: selectFilter({ options: selectOptions, - getFilterBy: (filterByFunc) => { - // filterBy was assigned to onFilter once the component has mount - filterBy = filterByFunc; + getFilter: (filter) => { + // qualityFilter was assigned once the component has been mounted. + qualityFilter = filter; } }) }]; const handleClick = () => { - filterBy('0'); + qualityFilter('0'); }; const sourceCode = `\ import BootstrapTable from 'react-bootstrap-table-next'; import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter'; -let filterBy; +let qualityFilter; const selectOptions = { 0: 'good', @@ -61,15 +61,15 @@ const columns = [{ formatter: cell => selectOptions[cell], filter: selectFilter({ options: selectOptions, - getFilterBy: (filterByFunc) => { - // filterBy was assigned to onFilter once the component has mount - filterBy = filterByFunc; + getFilter: (filter) => { + // qualityFilter was assigned once the component has been mounted. + qualityFilter = filter; } }) }]; const handleClick = () => { - filterBy('0'); + qualityFilter('0'); }; export default () => ( diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js index 2e7f01bfa..2db8698d9 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js @@ -6,7 +6,7 @@ import { productsGenerator } from 'utils/common'; const products = productsGenerator(8); -let filterBy; +let nameFilter; const columns = [{ dataField: 'id', @@ -15,8 +15,9 @@ const columns = [{ dataField: 'name', text: 'Product Name', filter: textFilter({ - getFilterBy: (filterByFunc) => { - filterBy = filterByFunc; + getFilter: (filter) => { + // nameFilter was assigned once the component has been mounted. + nameFilter = filter; } }) }, { @@ -26,14 +27,14 @@ const columns = [{ }]; const handleClick = () => { - filterBy('0'); + nameFilter('0'); }; const sourceCode = `\ import BootstrapTable from 'react-bootstrap-table-next'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; -let filterBy; +let nameFilter; const columns = [{ dataField: 'id', @@ -42,9 +43,9 @@ const columns = [{ dataField: 'name', text: 'Product Name', filter: textFilter({ - getFilterBy: (filterByFunc) => { - // filterBy was assigned to onFilter once the component has mount - filterBy = filterByFunc; + getFilter: (filter) => { + // nameFilter was assigned once the component has been mounted. + nameFilter = filter; } }) }, { @@ -54,7 +55,7 @@ const columns = [{ }]; const handleClick = () => { - filterBy('0'); + nameFilter('0'); }; export default () => ( diff --git a/packages/react-bootstrap-table2-filter/src/components/number.js b/packages/react-bootstrap-table2-filter/src/components/number.js index 3b946cf26..c2d07ce4b 100644 --- a/packages/react-bootstrap-table2-filter/src/components/number.js +++ b/packages/react-bootstrap-table2-filter/src/components/number.js @@ -31,7 +31,7 @@ class NumberFilter extends Component { } componentDidMount() { - const { column, onFilter, getFilterBy } = this.props; + const { column, onFilter, getFilter } = this.props; const comparator = this.numberFilterComparator.value; const number = this.numberFilter.value; if (comparator && number) { @@ -39,8 +39,8 @@ class NumberFilter extends Component { } // export onFilter function to allow users to access - if (getFilterBy) { - getFilterBy((filterVal) => { + if (getFilter) { + getFilter((filterVal) => { this.setState(() => ({ isSelected: (filterVal !== '') })); onFilter(column, FILTER_TYPE.NUMBER)({ number: filterVal.number, @@ -237,7 +237,7 @@ NumberFilter.propTypes = { comparatorClassName: PropTypes.string, numberStyle: PropTypes.object, numberClassName: PropTypes.string, - getFilterBy: PropTypes.func + getFilter: PropTypes.func }; NumberFilter.defaultProps = { diff --git a/packages/react-bootstrap-table2-filter/src/components/select.js b/packages/react-bootstrap-table2-filter/src/components/select.js index 8ba74b217..91ab9346c 100644 --- a/packages/react-bootstrap-table2-filter/src/components/select.js +++ b/packages/react-bootstrap-table2-filter/src/components/select.js @@ -25,7 +25,7 @@ class SelectFilter extends Component { } componentDidMount() { - const { column, onFilter, getFilterBy } = this.props; + const { column, onFilter, getFilter } = this.props; const value = this.selectInput.value; if (value && value !== '') { @@ -33,8 +33,8 @@ class SelectFilter extends Component { } // export onFilter function to allow users to access - if (getFilterBy) { - getFilterBy((filterVal) => { + if (getFilter) { + getFilter((filterVal) => { this.setState(() => ({ isSelected: filterVal !== '' })); onFilter(column, FILTER_TYPE.SELECT)(filterVal); }); @@ -100,7 +100,7 @@ class SelectFilter extends Component { comparator, withoutEmptyOption, caseSensitive, - getFilterBy, + getFilter, ...rest } = this.props; @@ -133,7 +133,7 @@ SelectFilter.propTypes = { withoutEmptyOption: PropTypes.bool, defaultValue: PropTypes.any, caseSensitive: PropTypes.bool, - getFilterBy: PropTypes.func + getFilter: PropTypes.func }; SelectFilter.defaultProps = { diff --git a/packages/react-bootstrap-table2-filter/src/components/text.js b/packages/react-bootstrap-table2-filter/src/components/text.js index 65b6c7d90..746804440 100644 --- a/packages/react-bootstrap-table2-filter/src/components/text.js +++ b/packages/react-bootstrap-table2-filter/src/components/text.js @@ -19,7 +19,7 @@ class TextFilter extends Component { } componentDidMount() { - const { onFilter, getFilterBy, column } = this.props; + const { onFilter, getFilter, column } = this.props; const defaultValue = this.input.value; if (defaultValue) { @@ -27,8 +27,8 @@ class TextFilter extends Component { } // export onFilter function to allow users to access - if (getFilterBy) { - getFilterBy((filterVal) => { + if (getFilter) { + getFilter((filterVal) => { this.setState(() => ({ value: filterVal })); onFilter(column, FILTER_TYPE.TEXT)(filterVal); }); @@ -88,7 +88,7 @@ class TextFilter extends Component { onFilter, caseSensitive, defaultValue, - getFilterBy, + getFilter, ...rest } = this.props; @@ -119,7 +119,7 @@ TextFilter.propTypes = { style: PropTypes.object, className: PropTypes.string, caseSensitive: PropTypes.bool, - getFilterBy: PropTypes.func + getFilter: PropTypes.func }; TextFilter.defaultProps = { From f54c1f77b41720953afbb0476ea1a52700f8f95e Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Wed, 4 Apr 2018 15:39:23 +0800 Subject: [PATCH 066/576] display filter condition correctly and make sure text filter to be String --- .../programmatically-select-filter.js | 8 ++-- .../programmatically-text-filter.js | 4 +- .../src/components/number.js | 3 ++ .../src/components/select.js | 2 + .../src/filter.js | 44 +++++++++++-------- .../src/wrapper.js | 1 + 6 files changed, 38 insertions(+), 24 deletions(-) diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js index 96f00de1d..d368af5a6 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js @@ -22,7 +22,7 @@ const columns = [{ text: 'Product Name' }, { dataField: 'quality', - text: 'Product Quailty', + text: 'Product Quality', formatter: cell => selectOptions[cell], filter: selectFilter({ options: selectOptions, @@ -34,7 +34,7 @@ const columns = [{ }]; const handleClick = () => { - qualityFilter('0'); + qualityFilter(0); }; const sourceCode = `\ @@ -57,7 +57,7 @@ const columns = [{ text: 'Product Name' }, { dataField: 'quality', - text: 'Product Quailty', + text: 'Product Quality', formatter: cell => selectOptions[cell], filter: selectFilter({ options: selectOptions, @@ -69,7 +69,7 @@ const columns = [{ }]; const handleClick = () => { - qualityFilter('0'); + qualityFilter(0); }; export default () => ( diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js index 2db8698d9..f1080c000 100644 --- a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js +++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js @@ -27,7 +27,7 @@ const columns = [{ }]; const handleClick = () => { - nameFilter('0'); + nameFilter(0); }; const sourceCode = `\ @@ -55,7 +55,7 @@ const columns = [{ }]; const handleClick = () => { - nameFilter('0'); + nameFilter(0); }; export default () => ( diff --git a/packages/react-bootstrap-table2-filter/src/components/number.js b/packages/react-bootstrap-table2-filter/src/components/number.js index c2d07ce4b..ebf55e81b 100644 --- a/packages/react-bootstrap-table2-filter/src/components/number.js +++ b/packages/react-bootstrap-table2-filter/src/components/number.js @@ -42,6 +42,9 @@ class NumberFilter extends Component { if (getFilter) { getFilter((filterVal) => { this.setState(() => ({ isSelected: (filterVal !== '') })); + this.numberFilterComparator.value = filterVal.comparator; + this.numberFilter.value = filterVal.number; + onFilter(column, FILTER_TYPE.NUMBER)({ number: filterVal.number, comparator: filterVal.comparator diff --git a/packages/react-bootstrap-table2-filter/src/components/select.js b/packages/react-bootstrap-table2-filter/src/components/select.js index 91ab9346c..ba2d3060b 100644 --- a/packages/react-bootstrap-table2-filter/src/components/select.js +++ b/packages/react-bootstrap-table2-filter/src/components/select.js @@ -36,6 +36,8 @@ class SelectFilter extends Component { if (getFilter) { getFilter((filterVal) => { this.setState(() => ({ isSelected: filterVal !== '' })); + this.selectInput.value = filterVal; + onFilter(column, FILTER_TYPE.SELECT)(filterVal); }); } diff --git a/packages/react-bootstrap-table2-filter/src/filter.js b/packages/react-bootstrap-table2-filter/src/filter.js index e0d7a452b..9f7812ceb 100644 --- a/packages/react-bootstrap-table2-filter/src/filter.js +++ b/packages/react-bootstrap-table2-filter/src/filter.js @@ -6,30 +6,37 @@ import { LIKE, EQ, NE, GT, GE, LT, LE } from './comparison'; export const filterByText = _ => ( data, dataField, - { filterVal = '', comparator = LIKE, caseSensitive }, + { filterVal: userInput = '', comparator = LIKE, caseSensitive }, customFilterValue -) => - data.filter((row) => { - let cell = _.get(row, dataField); - if (customFilterValue) { - cell = customFilterValue(cell, row); - } - const cellStr = _.isDefined(cell) ? cell.toString() : ''; - if (comparator === EQ) { - return cellStr === filterVal; - } - if (caseSensitive) { - return cellStr.includes(filterVal); - } - return cellStr.toLocaleUpperCase().indexOf(filterVal.toLocaleUpperCase()) !== -1; - }); +) => { + // make sure filter value to be a string + const filterVal = userInput.toString(); + + return ( + data.filter((row) => { + let cell = _.get(row, dataField); + if (customFilterValue) { + cell = customFilterValue(cell, row); + } + const cellStr = _.isDefined(cell) ? cell.toString() : ''; + if (comparator === EQ) { + return cellStr === filterVal; + } + if (caseSensitive) { + return cellStr.includes(filterVal); + } + + return cellStr.toLocaleUpperCase().indexOf(filterVal.toLocaleUpperCase()) !== -1; + }) + ); +}; export const filterByNumber = _ => ( data, dataField, { filterVal: { comparator, number } }, customFilterValue -) => +) => ( data.filter((row) => { if (number === '' || !comparator) return true; let valid = true; @@ -81,7 +88,8 @@ export const filterByNumber = _ => ( } } return valid; - }); + }) +); export const filterFactory = _ => (filterType) => { let filterFn; diff --git a/packages/react-bootstrap-table2-filter/src/wrapper.js b/packages/react-bootstrap-table2-filter/src/wrapper.js index 9a64eb1ed..f13e6151f 100644 --- a/packages/react-bootstrap-table2-filter/src/wrapper.js +++ b/packages/react-bootstrap-table2-filter/src/wrapper.js @@ -63,6 +63,7 @@ export default (Base, { } = filter.props; currFilters[dataField] = { filterVal, filterType, comparator, caseSensitive }; } + store.filters = currFilters; if (this.isRemoteFiltering() || this.isRemotePagination()) { From a35701fabfc84675656a1f81fed1ba7c1c59116d Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Wed, 4 Apr 2018 16:23:59 +0800 Subject: [PATCH 067/576] [test] correct test for filter wrapper --- .../test/filter.test.js | 13 ++++++++++++ .../test/wrapper.test.js | 20 +++++++++---------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/packages/react-bootstrap-table2-filter/test/filter.test.js b/packages/react-bootstrap-table2-filter/test/filter.test.js index ae66a38c9..2ffd36de4 100644 --- a/packages/react-bootstrap-table2-filter/test/filter.test.js +++ b/packages/react-bootstrap-table2-filter/test/filter.test.js @@ -42,6 +42,19 @@ describe('filter', () => { filterFn = filters(store, columns, _); }); + describe('when filter value is not a String', () => { + it('should transform to string and do the filter', () => { + currFilters.name = { + filterVal: 3, + filterType: FILTER_TYPE.TEXT + }; + + const result = filterFn(currFilters); + expect(result).toBeDefined(); + expect(result).toHaveLength(2); + }); + }); + describe(`when default comparator is ${LIKE}`, () => { it('should returning correct result', () => { currFilters.name = { diff --git a/packages/react-bootstrap-table2-filter/test/wrapper.test.js b/packages/react-bootstrap-table2-filter/test/wrapper.test.js index 3d862858d..144265845 100644 --- a/packages/react-bootstrap-table2-filter/test/wrapper.test.js +++ b/packages/react-bootstrap-table2-filter/test/wrapper.test.js @@ -167,14 +167,14 @@ describe('Wrapper', () => { it('should setting store object correctly', () => { filterVals.forEach((filterVal) => { - instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal); expect(props.store.filtering).toBeFalsy(); }); }); it('should setting state correctly', () => { filterVals.forEach((filterVal) => { - instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(0); }); @@ -185,12 +185,12 @@ describe('Wrapper', () => { const filterVal = '3'; it('should setting store object correctly', () => { - instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal); expect(props.store.filters).toEqual(instance.state.currFilters); }); it('should setting state correctly', () => { - instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(1); }); @@ -203,7 +203,7 @@ describe('Wrapper', () => { props = createTableProps(); props.remote = { filter: true }; createFilterWrapper(props); - instance.onFilter(props.columns[1], filterVal, FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(filterVal); }); it('should not setting store object correctly', () => { @@ -222,27 +222,27 @@ describe('Wrapper', () => { describe('combination', () => { it('should setting store object correctly', () => { - instance.onFilter(props.columns[1], '3', FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)('3'); expect(props.store.filters).toEqual(instance.state.currFilters); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(1); - instance.onFilter(props.columns[1], '2', FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)('2'); expect(props.store.filters).toEqual(instance.state.currFilters); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(1); - instance.onFilter(props.columns[2], '2', FILTER_TYPE.TEXT); + instance.onFilter(props.columns[2], FILTER_TYPE.TEXT)('2'); expect(props.store.filters).toEqual(instance.state.currFilters); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(2); - instance.onFilter(props.columns[2], '', FILTER_TYPE.TEXT); + instance.onFilter(props.columns[2], FILTER_TYPE.TEXT)(''); expect(props.store.filters).toEqual(instance.state.currFilters); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(1); - instance.onFilter(props.columns[1], '', FILTER_TYPE.TEXT); + instance.onFilter(props.columns[1], FILTER_TYPE.TEXT)(''); expect(props.store.filters).toEqual(instance.state.currFilters); expect(instance.state.isDataChanged).toBeTruthy(); expect(Object.keys(instance.state.currFilters)).toHaveLength(0); From c64951fd6fb8d710c6018431420a4620943bc2ea Mon Sep 17 00:00:00 2001 From: Chun-MingChen Date: Wed, 4 Apr 2018 16:51:54 +0800 Subject: [PATCH 068/576] [test] correct tests for filter components * , this.checkbox = node } + type="checkbox" + className={ editorClass } + { ...rest } + checked={ this.state.checked } + onChange={ this.handleChange } + /> + ); + } +} + +CheckBoxEditor.propTypes = { + className: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.object + ]), + value: PropTypes.string, + defaultValue: PropTypes.any, + onChange: PropTypes.func +}; +CheckBoxEditor.defaultProps = { + className: '', + value: 'on:off', + defaultValue: false, + onChange: undefined +}; +export default CheckBoxEditor; diff --git a/packages/react-bootstrap-table2-editor/src/const.js b/packages/react-bootstrap-table2-editor/src/const.js index acbef9d80..4455ad797 100644 --- a/packages/react-bootstrap-table2-editor/src/const.js +++ b/packages/react-bootstrap-table2-editor/src/const.js @@ -2,3 +2,11 @@ export const TIME_TO_CLOSE_MESSAGE = 3000; export const DELAY_FOR_DBCLICK = 200; export const CLICK_TO_CELL_EDIT = 'click'; export const DBCLICK_TO_CELL_EDIT = 'dbclick'; + +export const EDITTYPE = { + TEXT: 'text', + SELECT: 'select', + TEXTAREA: 'textarea', + CHECKBOX: 'checkbox', + DATE: 'date' +}; diff --git a/packages/react-bootstrap-table2-editor/src/date-editor.js b/packages/react-bootstrap-table2-editor/src/date-editor.js new file mode 100644 index 000000000..b712fe213 --- /dev/null +++ b/packages/react-bootstrap-table2-editor/src/date-editor.js @@ -0,0 +1,42 @@ +/* eslint no-return-assign: 0 */ +import React, { Component } from 'react'; +import cs from 'classnames'; +import PropTypes from 'prop-types'; + +class DateEditor extends Component { + componentDidMount() { + const { defaultValue } = this.props; + this.date.valueAsDate = new Date(defaultValue); + this.date.focus(); + } + + getValue() { + return this.date.value; + } + + render() { + const { defaultValue, className, ...rest } = this.props; + const editorClass = cs('form-control editor edit-date', className); + return ( + this.date = node } + type="date" + className={ editorClass } + { ...rest } + /> + ); + } +} + +DateEditor.propTypes = { + className: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.object + ]), + defaultValue: PropTypes.string +}; +DateEditor.defaultProps = { + className: '', + defaultValue: '' +}; +export default DateEditor; diff --git a/packages/react-bootstrap-table2-editor/src/dropdown-editor.js b/packages/react-bootstrap-table2-editor/src/dropdown-editor.js new file mode 100644 index 000000000..cf6a2a682 --- /dev/null +++ b/packages/react-bootstrap-table2-editor/src/dropdown-editor.js @@ -0,0 +1,61 @@ +/* eslint no-return-assign: 0 */ +import React, { Component } from 'react'; +import cs from 'classnames'; +import PropTypes from 'prop-types'; + +class DropDownEditor extends Component { + componentDidMount() { + const { defaultValue } = this.props; + this.select.value = defaultValue; + this.select.focus(); + } + + getValue() { + return this.select.value; + } + + render() { + const { defaultValue, className, options, ...rest } = this.props; + const editorClass = cs('form-control editor edit-select', className); + + const attr = { + ...rest, + className: editorClass + }; + + return ( + + ); + } +} + +DropDownEditor.propTypes = { + defaultValue: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number + ]), + className: PropTypes.string, + style: PropTypes.object, + options: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.shape({ + label: PropTypes.string, + value: PropTypes.any + })) + ]).isRequired +}; +DropDownEditor.defaultProps = { + className: '', + defaultValue: '', + style: {} +}; +export default DropDownEditor; diff --git a/packages/react-bootstrap-table2-editor/src/editing-cell.js b/packages/react-bootstrap-table2-editor/src/editing-cell.js index 2c732de0d..2acda72c4 100644 --- a/packages/react-bootstrap-table2-editor/src/editing-cell.js +++ b/packages/react-bootstrap-table2-editor/src/editing-cell.js @@ -6,9 +6,13 @@ import React, { Component } from 'react'; import cs from 'classnames'; import PropTypes from 'prop-types'; +import DropdownEditor from './dropdown-editor'; +import TextAreaEditor from './textarea-editor'; +import CheckBoxEditor from './checkbox-editor'; +import DateEditor from './date-editor'; import TextEditor from './text-editor'; import EditorIndicator from './editor-indicator'; -import { TIME_TO_CLOSE_MESSAGE } from './const'; +import { TIME_TO_CLOSE_MESSAGE, EDITTYPE } from './const'; export default _ => class EditingCell extends Component { @@ -73,8 +77,8 @@ export default _ => }, timeToCloseMessage); } - beforeComplete(row, column, newValue) { - const { onUpdate } = this.props; + beforeComplete(newValue) { + const { onUpdate, row, column } = this.props; if (_.isFunction(column.validator)) { const validateForm = column.validator(newValue, row, column); if (_.isObject(validateForm) && !validateForm.valid) { @@ -89,28 +93,20 @@ export default _ => } handleBlur() { - const { onEscape, blurToSave, row, column } = this.props; + const { onEscape, blurToSave } = this.props; if (blurToSave) { - const value = this.editor.text.value; - if (!_.isDefined(value)) { - // TODO: for other custom or embed editor - } - this.beforeComplete(row, column, value); + this.beforeComplete(this.editor.getValue()); } else { onEscape(); } } handleKeyDown(e) { - const { onEscape, row, column } = this.props; + const { onEscape } = this.props; if (e.keyCode === 27) { // ESC onEscape(); } else if (e.keyCode === 13) { // ENTER - const value = e.currentTarget.value; - if (!_.isDefined(value)) { - // TODO: for other custom or embed editor - } - this.beforeComplete(row, column, value); + this.beforeComplete(this.editor.getValue()); } } @@ -124,17 +120,13 @@ export default _ => } render() { - const { invalidMessage } = this.state; + let editor; const { row, column, className, style, rowIndex, columnIndex } = this.props; const { dataField } = column; const value = _.get(row, dataField); - const editorAttrs = { - onKeyDown: this.handleKeyDown, - onBlur: this.handleBlur - }; + const hasError = _.isDefined(this.state.invalidMessage); - const hasError = _.isDefined(invalidMessage); let customEditorClass = column.editorClasses || ''; if (_.isFunction(column.editorClasses)) { customEditorClass = column.editorClasses(value, row, rowIndex, columnIndex); @@ -150,20 +142,51 @@ export default _ => shake: hasError }, customEditorClass); + let editorProps = { + ref: node => this.editor = node, + defaultValue: value, + style: editorStyle, + className: editorClass, + onKeyDown: this.handleKeyDown, + onBlur: this.handleBlur + }; + + const isDefaultEditorDefined = _.isObject(column.editor); + + if (isDefaultEditorDefined) { + editorProps = { + ...editorProps, + ...column.editor + }; + } else if (_.isFunction(column.editorRenderer)) { + editorProps = { + ...editorProps, + onUpdate: this.beforeComplete + }; + } + + if (_.isFunction(column.editorRenderer)) { + editor = column.editorRenderer(editorProps, value, row, column, rowIndex, columnIndex); + } else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.SELECT) { + editor = ; + } else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.TEXTAREA) { + editor = ; + } else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.CHECKBOX) { + editor = ; + } else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.DATE) { + editor = ; + } else { + editor = ; + } + return (
- this.editor = node } - defaultValue={ value } - style={ editorStyle } - className={ editorClass } - { ...editorAttrs } - /> - { hasError ? : null } + { editor } + { hasError ? : null }