mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2026-06-29 13:40:07 +00:00
Compare commits
75 Commits
react-boot
...
react-boot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4db4f4fb2d | ||
|
|
1d7df6819e | ||
|
|
e4b6993692 | ||
|
|
b15d7a3412 | ||
|
|
b172c6801c | ||
|
|
dc1f4dcc38 | ||
|
|
a82e611358 | ||
|
|
c64951fd6f | ||
|
|
a35701fabf | ||
|
|
f54c1f77b4 | ||
|
|
377534512a | ||
|
|
09032349d0 | ||
|
|
4dd39aeed8 | ||
|
|
a1477e2ad3 | ||
|
|
f34cb4bf63 | ||
|
|
3dc9cd3941 | ||
|
|
e8458b4b63 | ||
|
|
1d87ce9ffc | ||
|
|
88e1a0774b | ||
|
|
11d4f40089 | ||
|
|
41dc3ef619 | ||
|
|
4501ddb632 | ||
|
|
05657ee217 | ||
|
|
c91f521913 | ||
|
|
9ee9c7de43 | ||
|
|
42dbd00fd9 | ||
|
|
bd9150f88f | ||
|
|
3956fbca11 | ||
|
|
240bcd75c0 | ||
|
|
6de57737ea | ||
|
|
33a8da701b | ||
|
|
d5ddd8c3af | ||
|
|
6f9361934a | ||
|
|
6bc81dddd0 | ||
|
|
c11539b9fb | ||
|
|
94f1a5ee57 | ||
|
|
de27072ceb | ||
|
|
55336108a0 | ||
|
|
923439dc81 | ||
|
|
d80ae13513 | ||
|
|
ceebdf5a13 | ||
|
|
0eda54b772 | ||
|
|
3ed4d87b29 | ||
|
|
8a8c2d4964 | ||
|
|
3cea9658c7 | ||
|
|
9f9203bffa | ||
|
|
4011cae18e | ||
|
|
60f32f0336 | ||
|
|
a5cb806d98 | ||
|
|
9382ed587b | ||
|
|
a11913c49a | ||
|
|
4635b60da0 | ||
|
|
4d9e20e9c8 | ||
|
|
931cf80450 | ||
|
|
5dd1f1e9ea | ||
|
|
a8083ac17d | ||
|
|
096799c403 | ||
|
|
6dee718081 | ||
|
|
936a82954c | ||
|
|
ba24990994 | ||
|
|
e7ccd47817 | ||
|
|
a0af964d76 | ||
|
|
865be93ef7 | ||
|
|
65a596a0e9 | ||
|
|
024bba15fa | ||
|
|
f9217930e7 | ||
|
|
fc34ea12e6 | ||
|
|
b0f411e934 | ||
|
|
28a1077bad | ||
|
|
ca32eee28e | ||
|
|
7030b54cbd | ||
|
|
4d7378e3f1 | ||
|
|
577973a147 | ||
|
|
c4f14e2b69 | ||
|
|
feedcb9f4b |
@@ -9,9 +9,10 @@ cache:
|
||||
|
||||
branches:
|
||||
only:
|
||||
# skip master branch when it's under development phase
|
||||
# - master
|
||||
- master
|
||||
- develop
|
||||
except:
|
||||
- gh-pages-src
|
||||
|
||||
before_install:
|
||||
- curl -o- -L https://yarnpkg.com/install.sh | bash -s
|
||||
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -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.
|
||||
@@ -1,4 +1,5 @@
|
||||
# react-bootstrap-table2
|
||||
[](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
|
||||
|
||||
@@ -15,12 +15,15 @@
|
||||
* [bordered](#bordered)
|
||||
* [hover](#hover)
|
||||
* [condensed](#condensed)
|
||||
* [id](#id)
|
||||
* [classes](#classes)
|
||||
* [cellEdit](#cellEdit)
|
||||
* [selectRow](#selectRow)
|
||||
* [rowStyle](#rowStyle)
|
||||
* [rowClasses](#rowClasses)
|
||||
* [rowEvents](#rowEvents)
|
||||
* [defaultSorted](#defaultSorted)
|
||||
* [defaultSortDirection](#defaultSortDirection)
|
||||
* [pagination](#pagination)
|
||||
* [filter](#filter)
|
||||
* [onTableChange](#onTableChange)
|
||||
@@ -59,14 +62,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.
|
||||
|
||||
### <a name='loading'>loading - [Bool]</a>
|
||||
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.
|
||||
|
||||
### <a name='overlay'>overlay - [Function]</a>
|
||||
`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
|
||||
@@ -100,6 +103,10 @@ Same as bootstrap `.table-hover` class for adding mouse hover effect (grey backg
|
||||
### <a name='condensed'>condensed - [Bool]</a>
|
||||
Same as bootstrap `.table-condensed` class for making a table more compact by cutting cell padding in half.
|
||||
|
||||
### <a name='id'>id - [String]</a>
|
||||
Customize id on `table` element.
|
||||
### <a name='classes'>classes - [String]</a>
|
||||
Customize class on `table` element.
|
||||
### <a name='cellEdit'>cellEdit - [Object]</a>
|
||||
Makes table cells editable, please see [cellEdit definition](./cell-edit.md) for more detail.
|
||||
|
||||
@@ -145,7 +152,7 @@ Custom the events on row:
|
||||
|
||||
```js
|
||||
const rowEvents = {
|
||||
onClick: (e) => {
|
||||
onClick: (e, row, rowIndex) => {
|
||||
....
|
||||
}
|
||||
};
|
||||
@@ -162,8 +169,11 @@ const defaultSorted = [{
|
||||
}];
|
||||
```
|
||||
|
||||
### <a name='defaultSortDirection'>defaultSortDirection - [String]</a>
|
||||
Default sort direction when user click on header column at first time, available value is `asc` and `desc`. Default is `desc`.
|
||||
|
||||
### <a name='pagination'>pagination - [Object]</a>
|
||||
`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 +215,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 +223,7 @@ paginator({
|
||||
```
|
||||
|
||||
### <a name='filter'>filter - [Object]</a>
|
||||
`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
|
||||
|
||||
@@ -12,6 +12,7 @@ Available properties in a column object:
|
||||
* [formatExtraData](#formatExtraData)
|
||||
* [sort](#sort)
|
||||
* [sortFunc](#sortFunc)
|
||||
* [onSort](#onSort)
|
||||
* [classes](#classes)
|
||||
* [style](#style)
|
||||
* [title](#title)
|
||||
@@ -31,6 +32,8 @@ Available properties in a column object:
|
||||
* [validator](#validator)
|
||||
* [editCellStyle](#editCellStyle)
|
||||
* [editCellClasses](#editCellClasses)
|
||||
* [editorStyle](#editorStyle)
|
||||
* [editorClasses](#editorClasses)
|
||||
* [filter](#filter)
|
||||
* [filterValue](#filterValue)
|
||||
|
||||
@@ -122,8 +125,21 @@ Enable the column sort via a `true` value given.
|
||||
```
|
||||
> The possible value of `order` argument is **`asc`** and **`desc`**.
|
||||
|
||||
## <a name='sortFunc'>column.onSort - [Function]</a>
|
||||
`column.onSort` is an event listener for sort change event:
|
||||
|
||||
```js
|
||||
{
|
||||
// omit...
|
||||
sort: true,
|
||||
onSort: (field, order) => {
|
||||
// ....
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## <a name='classes'>column.classes - [String | Function]</a>
|
||||
It's availabe to have custom class on table column:
|
||||
It's available to have custom class on table column:
|
||||
|
||||
```js
|
||||
{
|
||||
@@ -151,7 +167,7 @@ In addition, `classes` also accept a callback function which have more power to
|
||||
A new `String` will be the result as element class.
|
||||
|
||||
## <a name='headerClasses'>column.headerClasses - [String | Function]</a>
|
||||
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
|
||||
{
|
||||
@@ -176,7 +192,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.
|
||||
|
||||
## <a name='style'>column.style - [Object | Function]</a>
|
||||
It's availabe to have custom style on table column:
|
||||
It's available to have custom style on table column:
|
||||
|
||||
```js
|
||||
{
|
||||
@@ -206,7 +222,7 @@ A new `Object` will be the result of element style.
|
||||
|
||||
|
||||
## <a name='headerStyle'>column.headerStyle - [Object | Function]</a>
|
||||
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
|
||||
{
|
||||
@@ -264,7 +280,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) { ... }
|
||||
@@ -387,7 +403,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
|
||||
{
|
||||
@@ -398,7 +414,7 @@ A new `Object` will be the result of element HTML attributes.
|
||||
```
|
||||
|
||||
## <a name='headerAttrs'>column.headerAttrs - [Object | Function]</a>
|
||||
`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...
|
||||
@@ -430,7 +446,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.
|
||||
|
||||
### <a name='headerSortingClasses'>headerSortingClasses - [String | Function]</a>
|
||||
|
||||
@@ -453,7 +469,7 @@ const headerSortingClasses = (column, sortOrder, isLastSorting, colIndex) => { .
|
||||
|
||||
### <a name='headerSortingStyle'>headerSortingStyle - [Object | Function]</a>
|
||||
|
||||
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 = {
|
||||
@@ -488,7 +504,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,
|
||||
@@ -538,6 +554,12 @@ Or take a callback function
|
||||
}
|
||||
```
|
||||
|
||||
## <a name='editorStyle'>column.editorStyle - [Object | Function]</a>
|
||||
This is almost same as [`column.editCellStyle`](#editCellStyle), but `column.editorStyle` is custom the style on editor instead of cell(`td`).
|
||||
|
||||
## <a name='editorClasses'>column.editorClasses - [Object | Function]</a>
|
||||
This is almost same as [`column.editCellClasses`](#editCellClasses), but `column.editorClasses` is custom the class on editor instead of cell(`td`).
|
||||
|
||||
## <a name='filter'>column.filter - [Object]</a>
|
||||
Configure `column.filter` will able to setup a column level filter on the header column. Currently, `react-bootstrap-table2` support following filters:
|
||||
|
||||
@@ -560,7 +582,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.
|
||||
|
||||
## <a name='filterValue'>column.filterValue - [Function]</a>
|
||||
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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -60,11 +60,12 @@ 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
|
||||
|
||||
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
|
||||
|
||||
@@ -85,14 +86,14 @@ 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
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* [mode (**required**)](#mode)
|
||||
|
||||
## Optional
|
||||
* [selected](#selected)
|
||||
* [style](#style)
|
||||
* [classes)](#classes)
|
||||
* [bgColor](#bgColor)
|
||||
@@ -52,6 +53,16 @@ const selectRow = {
|
||||
/>
|
||||
```
|
||||
|
||||
### <a name='selected'>selectRow.selected - [Array]</a>
|
||||
`selectRow.selected` allow you have default selections on table.
|
||||
|
||||
```js
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
selected: [1, 3] // should be a row keys array
|
||||
};
|
||||
```
|
||||
|
||||
### <a name='style'>selectRow.style - [Object | Function]</a>
|
||||
`selectRow.style` allow you to have custom style on selected rows:
|
||||
|
||||
@@ -91,7 +102,7 @@ const selectRow = {
|
||||
```
|
||||
|
||||
### <a name='bgColor'>selectRow.bgColor - [String | Function]</a>
|
||||
The backgroud color when row is selected
|
||||
The background color when row is selected
|
||||
|
||||
```js
|
||||
const selectRow = {
|
||||
@@ -147,12 +158,12 @@ const selectRow = {
|
||||
|
||||
### <a name='onSelect'>selectRow.onSelect - [Function]</a>
|
||||
This callback function will be called when a row is select/unselect and pass following three arguments:
|
||||
`row`, `isSelect` and `rowIndex`.
|
||||
`row`, `isSelect`, `rowIndex` and `e`.
|
||||
|
||||
```js
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
onSelect: (row, isSelect, rowIndex) => {
|
||||
onSelect: (row, isSelect, rowIndex, e) => {
|
||||
// ...
|
||||
}
|
||||
};
|
||||
@@ -164,7 +175,7 @@ This callback function will be called when select/unselect all and it only work
|
||||
```js
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
onSelectAll: (isSelect, results) => {
|
||||
onSelectAll: (isSelect, results, e) => {
|
||||
// ...
|
||||
}
|
||||
};
|
||||
|
||||
@@ -72,9 +72,15 @@ function styles() {
|
||||
.pipe(gulp.dest(PKG_PATH));
|
||||
}
|
||||
|
||||
function umd() {
|
||||
return gulp.src('./webpack.prod.config.babel.js')
|
||||
.pipe(shell(['webpack --config <%= file.path %>']));
|
||||
function umd(done) {
|
||||
gulp.parallel(
|
||||
() => gulp.src('./webpack/next.umd.babel.js').pipe(shell(['webpack --config <%= file.path %>'])),
|
||||
() => gulp.src('./webpack/editor.umd.babel.js').pipe(shell(['webpack --config <%= file.path %>'])),
|
||||
() => gulp.src('./webpack/filter.umd.babel.js').pipe(shell(['webpack --config <%= file.path %>'])),
|
||||
() => gulp.src('./webpack/overlay.umd.babel.js').pipe(shell(['webpack --config <%= file.path %>'])),
|
||||
() => gulp.src('./webpack/paginator.umd.babel.js').pipe(shell(['webpack --config <%= file.path %>']))
|
||||
)();
|
||||
done();
|
||||
}
|
||||
|
||||
const buildJS = gulp.parallel(umd, scripts);
|
||||
|
||||
@@ -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!
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-bootstrap-table2-editor",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.5",
|
||||
"description": "it's the editor addon for react-bootstrap-table2",
|
||||
"main": "./lib/index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -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 (
|
||||
<td
|
||||
className={ cs('react-bootstrap-table-editing-cell', className) }
|
||||
@@ -143,6 +159,7 @@ export default _ =>
|
||||
<TextEditor
|
||||
ref={ node => this.editor = node }
|
||||
defaultValue={ value }
|
||||
style={ editorStyle }
|
||||
className={ editorClass }
|
||||
{ ...editorAttrs }
|
||||
/>
|
||||
|
||||
@@ -32,9 +32,10 @@ TextEditor.propTypes = {
|
||||
defaultValue: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number
|
||||
]).isRequired
|
||||
])
|
||||
};
|
||||
TextEditor.defaultProps = {
|
||||
className: null
|
||||
className: null,
|
||||
defaultValue: ''
|
||||
};
|
||||
export default TextEditor;
|
||||
|
||||
@@ -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(
|
||||
<EditingCell
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columnIndex={ columnIndex }
|
||||
column={ column }
|
||||
onUpdate={ onUpdate }
|
||||
onEscape={ onEscape }
|
||||
@@ -58,7 +63,7 @@ describe('EditingCell', () => {
|
||||
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(
|
||||
<EditingCell
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columnIndex={ columnIndex }
|
||||
column={ column }
|
||||
onUpdate={ onUpdate }
|
||||
onEscape={ onEscape }
|
||||
@@ -112,6 +119,8 @@ describe('EditingCell', () => {
|
||||
wrapper = shallow(
|
||||
<EditingCell
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columnIndex={ columnIndex }
|
||||
column={ column }
|
||||
onUpdate={ onUpdate }
|
||||
onEscape={ onEscape }
|
||||
@@ -126,12 +135,140 @@ describe('EditingCell', () => {
|
||||
});
|
||||
});
|
||||
|
||||
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(
|
||||
<EditingCell
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columnIndex={ columnIndex }
|
||||
column={ columnWithEditorClasses }
|
||||
onUpdate={ onUpdate }
|
||||
onEscape={ onEscape }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<EditingCell
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columnIndex={ columnIndex }
|
||||
column={ columnWithEditorClasses }
|
||||
onUpdate={ onUpdate }
|
||||
onEscape={ onEscape }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<EditingCell
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columnIndex={ columnIndex }
|
||||
column={ columnWithEditorStyle }
|
||||
onUpdate={ onUpdate }
|
||||
onEscape={ onEscape }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<EditingCell
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columnIndex={ columnIndex }
|
||||
column={ columnWithEditorStyle }
|
||||
onUpdate={ onUpdate }
|
||||
onEscape={ onEscape }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<TableRowWrapper>
|
||||
<EditingCell
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columnIndex={ columnIndex }
|
||||
column={ column }
|
||||
onUpdate={ onUpdate }
|
||||
onEscape={ onEscape }
|
||||
@@ -167,6 +304,8 @@ describe('EditingCell', () => {
|
||||
wrapper = mount(
|
||||
<EditingCell
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columnIndex={ columnIndex }
|
||||
column={ column }
|
||||
onUpdate={ onUpdate }
|
||||
onEscape={ onEscape }
|
||||
|
||||
48
packages/react-bootstrap-table2-example/examples/basic/customized-id-classes.js
vendored
Normal file
48
packages/react-bootstrap-table2-example/examples/basic/customized-id-classes.js
vendored
Normal file
@@ -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'
|
||||
}];
|
||||
|
||||
<BootstrapTable id="bar" keyField='id' data={ products } columns={ columns } />
|
||||
<BootstrapTable classes="foo" keyField='id' data={ products } columns={ columns } />
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<h4> Customized table ID </h4>
|
||||
<BootstrapTable id="bar" keyField="id" data={ products } columns={ columns } />
|
||||
|
||||
<h4> Customized table className </h4>
|
||||
<BootstrapTable classes="foo" keyField="id" data={ products } columns={ columns } />
|
||||
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
61
packages/react-bootstrap-table2-example/examples/cell-edit/editor-class-table.js
vendored
Normal file
61
packages/react-bootstrap-table2-example/examples/cell-edit/editor-class-table.js
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/* 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',
|
||||
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')
|
||||
}];
|
||||
|
||||
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')
|
||||
}];
|
||||
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEditFactory({ mode: 'click' }) }
|
||||
/>
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEditFactory({ mode: 'click' }) }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
69
packages/react-bootstrap-table2-example/examples/cell-edit/editor-style-table.js
vendored
Normal file
69
packages/react-bootstrap-table2-example/examples/cell-edit/editor-style-table.js
vendored
Normal file
@@ -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 };
|
||||
}
|
||||
}];
|
||||
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEditFactory({ mode: 'click' }) }
|
||||
/>
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
cellEdit={ cellEditFactory({ mode: 'click' }) }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
74
packages/react-bootstrap-table2-example/examples/column-filter/custom-number-filter.js
vendored
Normal file
74
packages/react-bootstrap-table2-example/examples/column-filter/custom-number-filter.js
vendored
Normal file
@@ -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'
|
||||
})
|
||||
}];
|
||||
|
||||
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
filter={ filterFactory() }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
54
packages/react-bootstrap-table2-example/examples/column-filter/number-filter-default-value.js
vendored
Normal file
54
packages/react-bootstrap-table2-example/examples/column-filter/number-filter-default-value.js
vendored
Normal file
@@ -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 }
|
||||
})
|
||||
}];
|
||||
|
||||
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
filter={ filterFactory() }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
50
packages/react-bootstrap-table2-example/examples/column-filter/number-filter.js
vendored
Normal file
50
packages/react-bootstrap-table2-example/examples/column-filter/number-filter.js
vendored
Normal file
@@ -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()
|
||||
}];
|
||||
|
||||
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
filter={ filterFactory() }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
85
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js
vendored
Normal file
85
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-number-filter.js
vendored
Normal file
@@ -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 priceFilter;
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
filter: numberFilter({
|
||||
getFilter: (filter) => {
|
||||
// pricerFilter was assigned once the component has been mounted.
|
||||
priceFilter = filter;
|
||||
}
|
||||
})
|
||||
}];
|
||||
|
||||
const handleClick = () => {
|
||||
priceFilter({
|
||||
number: 2103,
|
||||
comparator: Comparator.GT
|
||||
});
|
||||
};
|
||||
|
||||
const sourceCode = `\
|
||||
import BootstrapTable from 'react-bootstrap-table-next';
|
||||
import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter';
|
||||
|
||||
let priceFilter;
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
filter: numberFilter({
|
||||
getFilter: (filter) => {
|
||||
// pricerFilter was assigned once the component has been mounted.
|
||||
priceFilter = filter;
|
||||
}
|
||||
})
|
||||
}];
|
||||
|
||||
const handleClick = () => {
|
||||
priceFilter({
|
||||
number: 2103,
|
||||
comparator: Comparator.GT
|
||||
});
|
||||
};
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<button className="btn btn-lg btn-primary" onClick={ handleClick }> filter all columns which is greater than 2103 </button>
|
||||
|
||||
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||
</div>
|
||||
);
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<button className="btn btn-lg btn-primary" onClick={ handleClick }> filter all columns which is greater than 2103 </button>
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
filter={ filterFactory() }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
96
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js
vendored
Normal file
96
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-select-filter.js
vendored
Normal file
@@ -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 qualityFilter;
|
||||
|
||||
const selectOptions = {
|
||||
0: 'good',
|
||||
1: 'Bad',
|
||||
2: 'unknown'
|
||||
};
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'quality',
|
||||
text: 'Product Quality',
|
||||
formatter: cell => selectOptions[cell],
|
||||
filter: selectFilter({
|
||||
options: selectOptions,
|
||||
getFilter: (filter) => {
|
||||
// qualityFilter was assigned once the component has been mounted.
|
||||
qualityFilter = filter;
|
||||
}
|
||||
})
|
||||
}];
|
||||
|
||||
const handleClick = () => {
|
||||
qualityFilter(0);
|
||||
};
|
||||
|
||||
const sourceCode = `\
|
||||
import BootstrapTable from 'react-bootstrap-table-next';
|
||||
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
|
||||
|
||||
let qualityFilter;
|
||||
|
||||
const selectOptions = {
|
||||
0: 'good',
|
||||
1: 'Bad',
|
||||
2: 'unknown'
|
||||
};
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'quality',
|
||||
text: 'Product Quality',
|
||||
formatter: cell => selectOptions[cell],
|
||||
filter: selectFilter({
|
||||
options: selectOptions,
|
||||
getFilter: (filter) => {
|
||||
// qualityFilter was assigned once the component has been mounted.
|
||||
qualityFilter = filter;
|
||||
}
|
||||
})
|
||||
}];
|
||||
|
||||
const handleClick = () => {
|
||||
qualityFilter(0);
|
||||
};
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<button className="btn btn-lg btn-primary" onClick={ handleClick }>{' filter columns by option "good" '}</button>
|
||||
|
||||
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||
</div>
|
||||
);
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<button className="btn btn-lg btn-primary" onClick={ handleClick }>{' filter columns by option "good" '}</button>
|
||||
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
filter={ filterFactory() }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
81
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js
vendored
Normal file
81
packages/react-bootstrap-table2-example/examples/column-filter/programmatically-text-filter.js
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
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 nameFilter;
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name',
|
||||
filter: textFilter({
|
||||
getFilter: (filter) => {
|
||||
// nameFilter was assigned once the component has been mounted.
|
||||
nameFilter = filter;
|
||||
}
|
||||
})
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
filter: textFilter()
|
||||
}];
|
||||
|
||||
const handleClick = () => {
|
||||
nameFilter(0);
|
||||
};
|
||||
|
||||
const sourceCode = `\
|
||||
import BootstrapTable from 'react-bootstrap-table-next';
|
||||
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
|
||||
|
||||
let nameFilter;
|
||||
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name',
|
||||
filter: textFilter({
|
||||
getFilter: (filter) => {
|
||||
// nameFilter was assigned once the component has been mounted.
|
||||
nameFilter = filter;
|
||||
}
|
||||
})
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price',
|
||||
filter: textFilter()
|
||||
}];
|
||||
|
||||
const handleClick = () => {
|
||||
nameFilter(0);
|
||||
};
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<button className="btn btn-lg btn-primary" onClick={ handleClick }> filter columns by 0 </button>
|
||||
|
||||
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||
</div>
|
||||
);
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<button className="btn btn-lg btn-primary" onClick={ handleClick }> filter columns by 0 </button>
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
filter={ filterFactory() }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
51
packages/react-bootstrap-table2-example/examples/column-filter/text-filter-caseSensitive.js
vendored
Normal file
51
packages/react-bootstrap-table2-example/examples/column-filter/text-filter-caseSensitive.js
vendored
Normal file
@@ -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'
|
||||
}];
|
||||
|
||||
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<h3>Product Name is case sensitive</h3>
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
filter={ filterFactory() }
|
||||
/>
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
@@ -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')
|
||||
}
|
||||
}, {
|
||||
|
||||
59
packages/react-bootstrap-table2-example/examples/row-selection/default-select.js
vendored
Normal file
59
packages/react-bootstrap-table2-example/examples/row-selection/default-select.js
vendored
Normal file
@@ -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]
|
||||
};
|
||||
|
||||
<BootstrapTable
|
||||
keyField='id'
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
selectRow={ selectRow }
|
||||
/>
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
@@ -22,14 +22,16 @@ const columns = [{
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
clickToSelect: true,
|
||||
onSelect: (row, isSelect, rowIndex) => {
|
||||
onSelect: (row, isSelect, rowIndex, e) => {
|
||||
console.log(row.id);
|
||||
console.log(isSelect);
|
||||
console.log(rowIndex);
|
||||
console.log(e);
|
||||
},
|
||||
onSelectAll: (isSelect, rows) => {
|
||||
onSelectAll: (isSelect, rows, e) => {
|
||||
console.log(isSelect);
|
||||
console.log(rows);
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -49,7 +51,18 @@ const columns = [{
|
||||
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
clickToSelect: true
|
||||
clickToSelect: true,
|
||||
onSelect: (row, isSelect, rowIndex, e) => {
|
||||
console.log(row.id);
|
||||
console.log(isSelect);
|
||||
console.log(rowIndex);
|
||||
console.log(e);
|
||||
},
|
||||
onSelectAll: (isSelect, rows, e) => {
|
||||
console.log(isSelect);
|
||||
console.log(rows);
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
<BootstrapTable
|
||||
|
||||
144
packages/react-bootstrap-table2-example/examples/row-selection/selection-management.js
vendored
Normal file
144
packages/react-bootstrap-table2-example/examples/row-selection/selection-management.js
vendored
Normal file
@@ -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 (
|
||||
<div>
|
||||
<button className="btn btn-success" onClick={ this.handleBtnClick }>Select/UnSelect 3rd row</button>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
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 (
|
||||
<div>
|
||||
<button className="btn btn-success" onClick={ this.handleBtnClick }>Select/UnSelect 3rd row</button>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
62
packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js
vendored
Normal file
62
packages/react-bootstrap-table2-example/examples/row-selection/selection-no-data.js
vendored
Normal file
@@ -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
|
||||
};
|
||||
|
||||
<BootstrapTable
|
||||
keyField='id'
|
||||
data={ [] }
|
||||
columns={ columns }
|
||||
selectRow={ selectRow }
|
||||
noDataIndication={ 'no results found' }
|
||||
/>
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ [] }
|
||||
columns={ columns }
|
||||
selectRow={ selectRow1 }
|
||||
noDataIndication={ 'no results found' }
|
||||
/>
|
||||
<Code>{ sourceCode1 }</Code>
|
||||
</div>
|
||||
);
|
||||
@@ -20,8 +20,8 @@ const columns = [{
|
||||
}];
|
||||
|
||||
const rowEvents = {
|
||||
onClick: (e) => {
|
||||
alert('click on row');
|
||||
onClick: (e, row, rowIndex) => {
|
||||
alert(`clicked on row with index: ${rowIndex}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -40,8 +40,8 @@ const columns = [{
|
||||
}];
|
||||
|
||||
const rowEvents = {
|
||||
onClick: (e) => {
|
||||
alert('click on row');
|
||||
onClick: (e, row, rowIndex) => {
|
||||
alert(\`clicked on row with index: \${rowIndex}\`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
67
packages/react-bootstrap-table2-example/examples/sort/default-sort-direction.js
vendored
Normal file
67
packages/react-bootstrap-table2-example/examples/sort/default-sort-direction.js
vendored
Normal file
@@ -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'
|
||||
}];
|
||||
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
defaultSortDirection="asc"
|
||||
/>
|
||||
`;
|
||||
|
||||
|
||||
class DefaultSortDirectionTable extends React.PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } defaultSortDirection="asc" />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DefaultSortDirectionTable;
|
||||
@@ -38,9 +38,28 @@ const columns = [{
|
||||
<BootstrapTable keyField='id' data={ products } columns={ columns } />
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
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 (
|
||||
<div>
|
||||
<button className="btn btn-default" onClick={ this.handleClick }>Change Data</button>
|
||||
<BootstrapTable keyField="id" data={ this.state.data } columns={ columns } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
58
packages/react-bootstrap-table2-example/examples/sort/sort-events.js
vendored
Normal file
58
packages/react-bootstrap-table2-example/examples/sort/sort-events.js
vendored
Normal file
@@ -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'
|
||||
}];
|
||||
|
||||
<BootstrapTable keyField='id' data={ products } columns={ columns } />
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } defaultSorted={ defaultSorted } />
|
||||
<Code>{ sourceCode }</Code>
|
||||
</div>
|
||||
);
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-bootstrap-table2-example",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.6",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
|
||||
@@ -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
|
||||
@@ -37,12 +38,19 @@ 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';
|
||||
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';
|
||||
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';
|
||||
@@ -52,6 +60,8 @@ 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';
|
||||
import HeaderSortingStyleTable from 'examples/sort/header-sorting-style';
|
||||
@@ -67,12 +77,17 @@ 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';
|
||||
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 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';
|
||||
@@ -115,6 +130,7 @@ storiesOf('Basic Table', module)
|
||||
.add('striped, hover, condensed table', () => <StripHoverCondensedTable />)
|
||||
.add('borderless table', () => <BorderlessTable />)
|
||||
.add('Indication For Empty Table', () => <NoDataTable />)
|
||||
.add('Customized id and class table', () => <CustomizedIdClassesTable />)
|
||||
.add('Table with caption', () => <CaptionTable />);
|
||||
|
||||
storiesOf('Work on Columns', module)
|
||||
@@ -143,13 +159,20 @@ storiesOf('Column Filter', module)
|
||||
.add('Text Filter', () => <TextFilter />)
|
||||
.add('Text Filter with Default Value', () => <TextFilterWithDefaultValue />)
|
||||
.add('Text Filter with Comparator', () => <TextFilterComparator />)
|
||||
.add('Custom Text Filter', () => <CustomTextFilter />)
|
||||
.add('Text Filter with Case Sensitive', () => <TextFilterCaseSensitive />)
|
||||
// add another filter type example right here.
|
||||
.add('Select Filter', () => <SelectFilter />)
|
||||
.add('Select Filter with Default Value', () => <SelectFilterWithDefaultValue />)
|
||||
.add('Select Filter with Comparator', () => <SelectFilterComparator />)
|
||||
.add('Number Filter', () => <NumberFilter />)
|
||||
.add('Number Filter with Default Value', () => <NumberFilterWithDefaultValue />)
|
||||
.add('Custom Text Filter', () => <CustomTextFilter />)
|
||||
.add('Custom Select Filter', () => <CustomSelectFilter />)
|
||||
.add('Custom Filter Value', () => <CustomFilterValue />);
|
||||
.add('Custom Number Filter', () => <CustomNumberFilter />)
|
||||
.add('Custom Filter Value', () => <CustomFilterValue />)
|
||||
.add('Programmatically Text Filter ', () => <ProgrammaticallyTextFilter />)
|
||||
.add('Programmatically Select Filter ', () => <ProgrammaticallySelectFilter />)
|
||||
.add('Programmatically Number Filter ', () => <ProgrammaticallyNumberFilter />);
|
||||
|
||||
storiesOf('Work on Rows', module)
|
||||
.add('Customize Row Style', () => <RowStyleTable />)
|
||||
@@ -159,6 +182,8 @@ storiesOf('Work on Rows', module)
|
||||
storiesOf('Sort Table', module)
|
||||
.add('Enable Sort', () => <EnableSortTable />)
|
||||
.add('Default Sort Table', () => <DefaultSortTable />)
|
||||
.add('Default Sort Direction Table', () => <DefaultSortDirectionTable />)
|
||||
.add('Sort Events', () => <SortEvents />)
|
||||
.add('Custom Sort Fuction', () => <CustomSortTable />)
|
||||
.add('Custom Classes on Sorting Header Column', () => <HeaderSortingClassesTable />)
|
||||
.add('Custom Style on Sorting Header Column', () => <HeaderSortingStyleTable />);
|
||||
@@ -172,14 +197,19 @@ storiesOf('Cell Editing', module)
|
||||
.add('Cell Level Editable', () => <CellLevelEditable />)
|
||||
.add('Rich Hook Functions', () => <CellEditHooks />)
|
||||
.add('Validation', () => <CellEditValidator />)
|
||||
.add('Custom Cell Style When Editing', () => <CellEditStyleTable />)
|
||||
.add('Custom Cell Classes When Editing', () => <CellEditClassTable />);
|
||||
.add('Custom Cell Style', () => <CellEditStyleTable />)
|
||||
.add('Custom Cell Classes', () => <CellEditClassTable />)
|
||||
.add('Custom Editor Classes', () => <EditorClassTable />)
|
||||
.add('Custom Editor Style', () => <EditorStyleTable />);
|
||||
|
||||
storiesOf('Row Selection', module)
|
||||
.add('Single Selection', () => <SingleSelectionTable />)
|
||||
.add('Multiple Selection', () => <MultipleSelectionTable />)
|
||||
.add('Click to Select', () => <ClickToSelectTable />)
|
||||
.add('Default Select', () => <DefaultSelectTable />)
|
||||
.add('Selection Management', () => <SelectionManagement />)
|
||||
.add('Click to Select and Edit Cell', () => <ClickToSelectWithCellEditTable />)
|
||||
.add('Selection without Data', () => <SelectionNoDataTable />)
|
||||
.add('Selection Style', () => <SelectionStyleTable />)
|
||||
.add('Selection Class', () => <SelectionClassTable />)
|
||||
.add('Selection Background Color', () => <SelectionBgColorTable />)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
table.foo {
|
||||
background-color: $grey-500;
|
||||
}
|
||||
|
||||
table#bar {
|
||||
background-color: $light-blue;
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
@@ -58,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
|
||||
});
|
||||
@@ -107,5 +109,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()
|
||||
}];
|
||||
|
||||
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
|
||||
```
|
||||
|
||||
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...
|
||||
```
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-bootstrap-table2-filter",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.6",
|
||||
"description": "it's a column filter addon for react-bootstrap-table2",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
|
||||
@@ -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 = '<=';
|
||||
|
||||
265
packages/react-bootstrap-table2-filter/src/components/number.js
vendored
Normal file
265
packages/react-bootstrap-table2-filter/src/components/number.js
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
/* eslint react/require-default-props: 0 */
|
||||
/* 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, getFilter } = 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 (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
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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, FILTER_TYPE.NUMBER)({ number: filterValue, comparator });
|
||||
}, 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, FILTER_TYPE.NUMBER)({ number: value, comparator });
|
||||
}
|
||||
|
||||
onChangeComparator(e) {
|
||||
const { column, onFilter } = this.props;
|
||||
const value = this.numberFilter.value;
|
||||
const comparator = e.target.value;
|
||||
// if (value === '') {
|
||||
// return;
|
||||
// }
|
||||
onFilter(column, FILTER_TYPE.NUMBER)({ number: value, comparator });
|
||||
}
|
||||
|
||||
getComparatorOptions() {
|
||||
const optionTags = [];
|
||||
const { withoutEmptyComparatorOption } = this.props;
|
||||
if (!withoutEmptyComparatorOption) {
|
||||
optionTags.push(<option key="-1" />);
|
||||
}
|
||||
for (let i = 0; i < this.comparators.length; i += 1) {
|
||||
optionTags.push(
|
||||
<option key={ i } value={ this.comparators[i] }>
|
||||
{ this.comparators[i] }
|
||||
</option>
|
||||
);
|
||||
}
|
||||
return optionTags;
|
||||
}
|
||||
|
||||
getNumberOptions() {
|
||||
const optionTags = [];
|
||||
const { options, column, withoutEmptyNumberOption } = this.props;
|
||||
if (!withoutEmptyNumberOption) {
|
||||
optionTags.push(
|
||||
<option key="-1" value="">
|
||||
{ this.props.placeholder || `Select ${column.text}...` }
|
||||
</option>
|
||||
);
|
||||
}
|
||||
for (let i = 0; i < options.length; i += 1) {
|
||||
optionTags.push(<option key={ i } value={ options[i] }>{ options[i] }</option>);
|
||||
}
|
||||
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, FILTER_TYPE.NUMBER)({ number, comparator });
|
||||
}
|
||||
|
||||
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, FILTER_TYPE.NUMBER)({ number: value, comparator });
|
||||
}
|
||||
|
||||
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 (
|
||||
<div className={ `filter number-filter ${className}` } style={ style }>
|
||||
<select
|
||||
ref={ n => this.numberFilterComparator = n }
|
||||
style={ comparatorStyle }
|
||||
className={ `number-filter-comparator form-control ${comparatorClassName}` }
|
||||
onChange={ this.onChangeComparator }
|
||||
defaultValue={ defaultValue ? defaultValue.comparator : '' }
|
||||
>
|
||||
{ this.getComparatorOptions() }
|
||||
</select>
|
||||
{
|
||||
options ?
|
||||
<select
|
||||
ref={ n => this.numberFilter = n }
|
||||
style={ numberStyle }
|
||||
className={ selectClass }
|
||||
onChange={ this.onChangeNumberSet }
|
||||
defaultValue={ defaultValue ? defaultValue.number : '' }
|
||||
>
|
||||
{ this.getNumberOptions() }
|
||||
</select> :
|
||||
<input
|
||||
ref={ n => 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 : '' }
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
getFilter: PropTypes.func
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -25,9 +25,21 @@ class SelectFilter extends Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { column, onFilter, getFilter } = this.props;
|
||||
|
||||
const value = this.selectInput.value;
|
||||
if (value && value !== '') {
|
||||
this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT);
|
||||
onFilter(column, FILTER_TYPE.SELECT)(value);
|
||||
}
|
||||
|
||||
// export onFilter function to allow users to access
|
||||
if (getFilter) {
|
||||
getFilter((filterVal) => {
|
||||
this.setState(() => ({ isSelected: filterVal !== '' }));
|
||||
this.selectInput.value = filterVal;
|
||||
|
||||
onFilter(column, FILTER_TYPE.SELECT)(filterVal);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +53,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 +76,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() {
|
||||
@@ -89,6 +101,8 @@ class SelectFilter extends Component {
|
||||
options,
|
||||
comparator,
|
||||
withoutEmptyOption,
|
||||
caseSensitive,
|
||||
getFilter,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
@@ -119,14 +133,17 @@ SelectFilter.propTypes = {
|
||||
style: PropTypes.object,
|
||||
className: PropTypes.string,
|
||||
withoutEmptyOption: PropTypes.bool,
|
||||
defaultValue: PropTypes.any
|
||||
defaultValue: PropTypes.any,
|
||||
caseSensitive: PropTypes.bool,
|
||||
getFilter: PropTypes.func
|
||||
};
|
||||
|
||||
SelectFilter.defaultProps = {
|
||||
defaultValue: '',
|
||||
className: '',
|
||||
withoutEmptyOption: false,
|
||||
comparator: EQ
|
||||
comparator: EQ,
|
||||
caseSensitive: true
|
||||
};
|
||||
|
||||
export default SelectFilter;
|
||||
|
||||
@@ -17,10 +17,21 @@ class TextFilter extends Component {
|
||||
value: props.defaultValue
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { onFilter, getFilter, column } = 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);
|
||||
}
|
||||
|
||||
// export onFilter function to allow users to access
|
||||
if (getFilter) {
|
||||
getFilter((filterVal) => {
|
||||
this.setState(() => ({ value: filterVal }));
|
||||
onFilter(column, FILTER_TYPE.TEXT)(filterVal);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +51,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 +64,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, FILTER_TYPE.TEXT)(value);
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -69,7 +80,18 @@ class TextFilter extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { placeholder, column: { text }, style, className, onFilter, ...rest } = this.props;
|
||||
const {
|
||||
placeholder,
|
||||
column: { text },
|
||||
style,
|
||||
className,
|
||||
onFilter,
|
||||
caseSensitive,
|
||||
defaultValue,
|
||||
getFilter,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
// stopPropagation for onClick event is try to prevent sort was triggered.
|
||||
return (
|
||||
<input
|
||||
@@ -95,12 +117,15 @@ TextFilter.propTypes = {
|
||||
delay: PropTypes.number,
|
||||
placeholder: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
className: PropTypes.string
|
||||
className: PropTypes.string,
|
||||
caseSensitive: PropTypes.bool,
|
||||
getFilter: PropTypes.func
|
||||
};
|
||||
|
||||
TextFilter.defaultProps = {
|
||||
delay: FILTER_DELAY,
|
||||
defaultValue: ''
|
||||
defaultValue: '',
|
||||
caseSensitive: false
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export const FILTER_TYPE = {
|
||||
TEXT: 'TEXT',
|
||||
SELECT: 'SELECT'
|
||||
SELECT: 'SELECT',
|
||||
NUMBER: 'NUMBER'
|
||||
};
|
||||
|
||||
export const FILTER_DELAY = 500;
|
||||
|
||||
100
packages/react-bootstrap-table2-filter/src/filter.js
vendored
100
packages/react-bootstrap-table2-filter/src/filter.js
vendored
@@ -1,30 +1,106 @@
|
||||
/* 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,
|
||||
dataField,
|
||||
{ filterVal, comparator = LIKE },
|
||||
{ filterVal: userInput = '', comparator = LIKE, caseSensitive },
|
||||
customFilterValue
|
||||
) =>
|
||||
) => {
|
||||
// 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;
|
||||
let cell = _.get(row, dataField);
|
||||
if (customFilterValue) {
|
||||
cell = customFilterValue(cell, row);
|
||||
}
|
||||
const cellStr = _.isDefined(cell) ? cell.toString() : '';
|
||||
if (comparator === EQ) {
|
||||
return cellStr === filterVal;
|
||||
|
||||
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 cellStr.indexOf(filterVal) > -1;
|
||||
});
|
||||
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(_);
|
||||
}
|
||||
@@ -38,7 +114,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;
|
||||
|
||||
@@ -40,30 +40,43 @@ 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) } = filter.props;
|
||||
currFilters[dataField] = { filterVal, filterType, comparator };
|
||||
}
|
||||
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 };
|
||||
}
|
||||
|
||||
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.filters = currFilters;
|
||||
|
||||
store.filteredData = filters(store, columns, _)(currFilters);
|
||||
this.setState(() => ({ currFilters, isDataChanged: true }));
|
||||
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 }));
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
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;
|
||||
|
||||
// onFilter(x)(y) = filter result
|
||||
const onFilter = sinon.stub();
|
||||
const onFilterFirstReturn = sinon.stub();
|
||||
|
||||
const column = {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
onFilter.reset();
|
||||
onFilterFirstReturn.reset();
|
||||
|
||||
onFilter.returns(onFilterFirstReturn);
|
||||
});
|
||||
|
||||
describe('initialization', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
<NumberFilter onFilter={ onFilter } column={ column } />
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter onFilter={ onFilter } column={ column } withoutEmptyComparatorOption />
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter onFilter={ onFilter } column={ column } defaultValue={ { number } } />
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter onFilter={ onFilter } column={ column } defaultValue={ { comparator } } />
|
||||
);
|
||||
});
|
||||
|
||||
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 props.getFilter is defined', () => {
|
||||
let programmaticallyFilter;
|
||||
|
||||
const comparator = Comparator.EQ;
|
||||
const number = 123;
|
||||
|
||||
const getFilter = (filter) => {
|
||||
programmaticallyFilter = filter;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
<NumberFilter onFilter={ onFilter } column={ column } getFilter={ getFilter } />
|
||||
);
|
||||
|
||||
programmaticallyFilter({ comparator, number });
|
||||
});
|
||||
|
||||
it('should do onFilter correctly when exported function was executed', () => {
|
||||
expect(onFilter.calledOnce).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.NUMBER)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledWith({ comparator, number })).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should setState correctly when exported function was executed', () => {
|
||||
expect(wrapper.state().isSelected).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when defaultValue.number and defaultValue.comparator props is defined', () => {
|
||||
const number = 203;
|
||||
const comparator = Comparator.EQ;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
<NumberFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
defaultValue={ { number, comparator } }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should have correct state', () => {
|
||||
expect(wrapper.state().isSelected).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should calling onFilter on componentDidMount', () => {
|
||||
expect(onFilter.calledOnce).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.NUMBER)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledWith({ number: `${number}`, comparator })).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when options props is defined', () => {
|
||||
const options = [2100, 2103, 2105];
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
<NumberFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
options={ options }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
options={ options }
|
||||
withoutEmptyNumberOption
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
defaultValue={ { number } }
|
||||
options={ options }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
defaultValue={ { number, comparator } }
|
||||
options={ options }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
style={ style }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
numberStyle={ numberStyle }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
comparatorStyle={ comparatorStyle }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
className={ className }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
numberClassName={ className }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
<NumberFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
comparatorClassName={ className }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should rendering component successfully', () => {
|
||||
expect(wrapper).toHaveLength(1);
|
||||
expect(wrapper.find('select').prop('className').indexOf(className) > -1).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -9,19 +9,27 @@ import { FILTER_TYPE } from '../../src/const';
|
||||
describe('Select Filter', () => {
|
||||
let wrapper;
|
||||
let instance;
|
||||
|
||||
// onFilter(x)(y) = filter result
|
||||
const onFilter = sinon.stub();
|
||||
const onFilterFirstReturn = sinon.stub();
|
||||
|
||||
const column = {
|
||||
dataField: 'quality',
|
||||
text: 'Product Quality'
|
||||
};
|
||||
|
||||
const options = {
|
||||
0: 'Bad',
|
||||
1: 'Good',
|
||||
2: 'Unknow'
|
||||
2: 'Unknown'
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
onFilter.reset();
|
||||
onFilterFirstReturn.reset();
|
||||
|
||||
onFilter.returns(onFilterFirstReturn);
|
||||
});
|
||||
|
||||
describe('initialization', () => {
|
||||
@@ -83,11 +91,48 @@ describe('Select Filter', () => {
|
||||
|
||||
it('should calling onFilter on componentDidMount', () => {
|
||||
expect(onFilter.calledOnce).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledWith(defaultValue)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when props.getFilter is defined', () => {
|
||||
let programmaticallyFilter;
|
||||
|
||||
const filterValue = 'foo';
|
||||
|
||||
const getFilter = (filter) => {
|
||||
programmaticallyFilter = filter;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
<SelectFilter
|
||||
onFilter={ onFilter }
|
||||
column={ column }
|
||||
options={ options }
|
||||
getFilter={ getFilter }
|
||||
/>
|
||||
);
|
||||
instance = wrapper.instance();
|
||||
|
||||
programmaticallyFilter(filterValue);
|
||||
});
|
||||
|
||||
it('should do onFilter correctly when exported function was executed', () => {
|
||||
expect(onFilter.calledOnce).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledWith(filterValue)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should setState correctly when exported function was executed', () => {
|
||||
expect(instance.state.isSelected).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when placeholder is defined', () => {
|
||||
const placeholder = 'test';
|
||||
beforeEach(() => {
|
||||
@@ -170,8 +215,9 @@ describe('Select Filter', () => {
|
||||
|
||||
it('should update', () => {
|
||||
expect(onFilter.callCount).toBe(2);
|
||||
expect(onFilter.calledWith(
|
||||
column, instance.props.defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.callCount).toBe(2);
|
||||
expect(onFilterFirstReturn.calledWith(instance.props.defaultValue)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -198,8 +244,9 @@ describe('Select Filter', () => {
|
||||
|
||||
it('should update', () => {
|
||||
expect(onFilter.callCount).toBe(2);
|
||||
expect(onFilter.calledWith(
|
||||
column, instance.props.defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.callCount).toBe(2);
|
||||
expect(onFilterFirstReturn.calledWith(instance.props.defaultValue)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -226,7 +273,9 @@ describe('Select Filter', () => {
|
||||
|
||||
it('should calling onFilter correctly', () => {
|
||||
expect(onFilter.callCount).toBe(2);
|
||||
expect(onFilter.calledWith(column, defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.callCount).toBe(2);
|
||||
expect(onFilterFirstReturn.calledWith(defaultValue)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -249,6 +298,7 @@ describe('Select Filter', () => {
|
||||
|
||||
it('should calling onFilter correctly', () => {
|
||||
expect(onFilter.callCount).toBe(1);
|
||||
expect(onFilterFirstReturn.callCount).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -268,8 +318,10 @@ describe('Select Filter', () => {
|
||||
});
|
||||
|
||||
it('should calling onFilter correctly', () => {
|
||||
expect(onFilter.callCount).toBe(1);
|
||||
expect(onFilter.calledWith(column, value, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilter.calledOnce).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledWith(value)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -289,8 +341,10 @@ describe('Select Filter', () => {
|
||||
});
|
||||
|
||||
it('should calling onFilter correctly', () => {
|
||||
expect(onFilter.callCount).toBe(1);
|
||||
expect(onFilter.calledWith(column, event.target.value, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilter.calledOnce).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.SELECT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledWith(event.target.value)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,7 +9,11 @@ jest.useFakeTimers();
|
||||
describe('Text Filter', () => {
|
||||
let wrapper;
|
||||
let instance;
|
||||
|
||||
// onFilter(x)(y) = filter result
|
||||
const onFilter = sinon.stub();
|
||||
const onFilterFirstReturn = sinon.stub();
|
||||
|
||||
const column = {
|
||||
dataField: 'price',
|
||||
text: 'Price'
|
||||
@@ -17,6 +21,9 @@ describe('Text Filter', () => {
|
||||
|
||||
afterEach(() => {
|
||||
onFilter.reset();
|
||||
onFilterFirstReturn.reset();
|
||||
|
||||
onFilter.returns(onFilterFirstReturn);
|
||||
});
|
||||
|
||||
describe('initialization', () => {
|
||||
@@ -58,7 +65,39 @@ describe('Text Filter', () => {
|
||||
|
||||
it('should calling onFilter on componentDidMount', () => {
|
||||
expect(onFilter.calledOnce).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, defaultValue, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledWith(defaultValue)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when props.getFilter is defined', () => {
|
||||
let programmaticallyFilter;
|
||||
|
||||
const filterValue = 'foo';
|
||||
|
||||
const getFilter = (filter) => {
|
||||
programmaticallyFilter = filter;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
<TextFilter onFilter={ onFilter } column={ column } getFilter={ getFilter } />
|
||||
);
|
||||
instance = wrapper.instance();
|
||||
|
||||
programmaticallyFilter(filterValue);
|
||||
});
|
||||
|
||||
it('should do onFilter correctly when exported function was executed', () => {
|
||||
expect(onFilter.calledOnce).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledWith(filterValue)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should setState correctly when exported function was executed', () => {
|
||||
expect(instance.state.value).toEqual(filterValue);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -114,7 +153,9 @@ describe('Text Filter', () => {
|
||||
|
||||
it('should calling onFilter correctly when props.defaultValue is changed', () => {
|
||||
expect(onFilter.calledOnce).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, nextDefaultValue, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledWith(nextDefaultValue)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -133,8 +174,9 @@ describe('Text Filter', () => {
|
||||
|
||||
it('should calling onFilter correctly', () => {
|
||||
expect(onFilter.calledOnce).toBeTruthy();
|
||||
expect(onFilter.calledWith(
|
||||
column, instance.props.defaultValue, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledWith(instance.props.defaultValue)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -154,7 +196,9 @@ describe('Text Filter', () => {
|
||||
|
||||
it('should calling onFilter correctly', () => {
|
||||
expect(onFilter.calledOnce).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, filterText, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||
expect(onFilter.calledWith(column, FILTER_TYPE.TEXT)).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledOnce).toBeTruthy();
|
||||
expect(onFilterFirstReturn.calledWith(filterText)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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,11 +37,24 @@ describe('filter', () => {
|
||||
}];
|
||||
});
|
||||
|
||||
describe('text filter', () => {
|
||||
describe('filterByText', () => {
|
||||
beforeEach(() => {
|
||||
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 = {
|
||||
@@ -55,6 +68,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 = {
|
||||
@@ -91,4 +118,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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-bootstrap-table-next",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.8",
|
||||
"description": "Next generation of react-bootstrap-table",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
|
||||
3
packages/react-bootstrap-table2/src/body.js
vendored
3
packages/react-bootstrap-table2/src/body.js
vendored
@@ -35,6 +35,9 @@ const Body = (props) => {
|
||||
|
||||
if (isEmpty) {
|
||||
const indication = _.isFunction(noDataIndication) ? noDataIndication() : noDataIndication;
|
||||
if (!indication) {
|
||||
return null;
|
||||
}
|
||||
content = <RowSection content={ indication } colSpan={ visibleColumnSize } />;
|
||||
} else {
|
||||
const nonEditableRows = cellEdit.nonEditableRows || [];
|
||||
|
||||
@@ -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
|
||||
@@ -70,10 +72,12 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
||||
allRowsSelected: isSelectedAll(store)
|
||||
});
|
||||
|
||||
const tableCaption = (caption && <Caption>{ caption }</Caption>);
|
||||
|
||||
return (
|
||||
<div className="react-bootstrap-table">
|
||||
<table className={ tableClass }>
|
||||
<Caption>{ caption }</Caption>
|
||||
<table id={ id } className={ tableClass }>
|
||||
{ tableCaption }
|
||||
<Header
|
||||
columns={ columns }
|
||||
sortField={ store.sortField }
|
||||
@@ -114,6 +118,8 @@ BootstrapTable.propTypes = {
|
||||
striped: PropTypes.bool,
|
||||
bordered: PropTypes.bool,
|
||||
hover: PropTypes.bool,
|
||||
id: PropTypes.string,
|
||||
classes: PropTypes.string,
|
||||
condensed: PropTypes.bool,
|
||||
caption: PropTypes.oneOfType([
|
||||
PropTypes.node,
|
||||
@@ -143,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,
|
||||
|
||||
5
packages/react-bootstrap-table2/src/cell.js
vendored
5
packages/react-bootstrap-table2/src/cell.js
vendored
@@ -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;
|
||||
|
||||
@@ -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) => {
|
||||
@@ -131,9 +126,12 @@ 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]),
|
||||
editorStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||
editorClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
validator: PropTypes.func,
|
||||
filter: PropTypes.object,
|
||||
filterValue: PropTypes.func
|
||||
|
||||
29
packages/react-bootstrap-table2/src/header.js
vendored
29
packages/react-bootstrap-table2/src/header.js
vendored
@@ -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 (
|
||||
<HeaderCell
|
||||
index={ i }
|
||||
key={ column.dataField }
|
||||
column={ column }
|
||||
onSort={ onSort }
|
||||
sorting={ currSort }
|
||||
onFilter={ onFilter }
|
||||
sortOrder={ sortOrder }
|
||||
isLastSorting={ isLastSorting }
|
||||
/>);
|
||||
return (
|
||||
<HeaderCell
|
||||
index={ i }
|
||||
key={ column.dataField }
|
||||
column={ column }
|
||||
onSort={ onSort }
|
||||
sorting={ currSort }
|
||||
onFilter={ onFilter }
|
||||
sortOrder={ sortOrder }
|
||||
isLastSorting={ isLastSorting }
|
||||
/>);
|
||||
}
|
||||
return false;
|
||||
})
|
||||
}
|
||||
</tr>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
84
packages/react-bootstrap-table2/src/row-event-delegater.js
vendored
Normal file
84
packages/react-bootstrap-table2/src/row-event-delegater.js
vendored
Normal file
@@ -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, e);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
@@ -28,7 +28,7 @@ export default class SelectionCell extends Component {
|
||||
return nextProps.selected !== selected;
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
handleClick(e) {
|
||||
const {
|
||||
mode: inputType,
|
||||
rowKey,
|
||||
@@ -46,7 +46,7 @@ export default class SelectionCell extends Component {
|
||||
? true
|
||||
: !selected;
|
||||
|
||||
onRowSelect(rowKey, checked, rowIndex);
|
||||
onRowSelect(rowKey, checked, rowIndex, e);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -44,10 +44,10 @@ export default class SelectionHeaderCell extends Component {
|
||||
return nextProps.checkedStatus !== checkedStatus;
|
||||
}
|
||||
|
||||
handleCheckBoxClick() {
|
||||
handleCheckBoxClick(e) {
|
||||
const { onAllRowsSelect } = this.props;
|
||||
|
||||
onAllRowsSelect();
|
||||
onAllRowsSelect(e);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint no-param-reassign: 0 */
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
@@ -21,17 +22,26 @@ export default Base =>
|
||||
super(props);
|
||||
this.handleRowSelect = this.handleRowSelect.bind(this);
|
||||
this.handleAllRowsSelect = this.handleAllRowsSelect.bind(this);
|
||||
|
||||
props.store.selected = props.selectRow.selected || [];
|
||||
this.state = {
|
||||
selectedRowKeys: props.store.selected
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
nextProps.store.selected = nextProps.selectRow.selected || [];
|
||||
this.setState(() => ({
|
||||
selectedRowKeys: nextProps.store.selected
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* row selection handler
|
||||
* @param {String} rowKey - row key of what was selected.
|
||||
* @param {Boolean} checked - next checked status of input button.
|
||||
*/
|
||||
handleRowSelect(rowKey, checked, rowIndex) {
|
||||
handleRowSelect(rowKey, checked, rowIndex, e) {
|
||||
const { selectRow: { mode, onSelect }, store } = this.props;
|
||||
const { ROW_SELECT_SINGLE } = Const;
|
||||
|
||||
@@ -49,7 +59,7 @@ export default Base =>
|
||||
|
||||
if (onSelect) {
|
||||
const row = getRowByRowId(store)(rowKey);
|
||||
onSelect(row, checked, rowIndex);
|
||||
onSelect(row, checked, rowIndex, e);
|
||||
}
|
||||
|
||||
this.setState(() => ({
|
||||
@@ -58,18 +68,16 @@ export default Base =>
|
||||
}
|
||||
|
||||
/**
|
||||
* handle all rows selection on header cell by store.selected or given specific result.
|
||||
* @param {Boolean} option - customized result for all rows selection
|
||||
* handle all rows selection on header cell by store.selected
|
||||
*/
|
||||
handleAllRowsSelect(option) {
|
||||
handleAllRowsSelect(e) {
|
||||
const { store, selectRow: {
|
||||
onSelectAll,
|
||||
nonSelectable
|
||||
} } = this.props;
|
||||
const selected = isAnySelectedRow(store)(nonSelectable);
|
||||
|
||||
// set next status of all row selected by store.selected or customizing by user.
|
||||
const result = option || !selected;
|
||||
const result = !selected;
|
||||
|
||||
const currSelected = result ?
|
||||
selectableKeys(store)(nonSelectable) :
|
||||
@@ -79,7 +87,7 @@ export default Base =>
|
||||
store.selected = currSelected;
|
||||
|
||||
if (onSelectAll) {
|
||||
onSelectAll(result, getSelectedRows(store));
|
||||
onSelectAll(result, getSelectedRows(store), e);
|
||||
}
|
||||
|
||||
this.setState(() => ({
|
||||
|
||||
126
packages/react-bootstrap-table2/src/row.js
vendored
126
packages/react-bootstrap-table2/src/row.js
vendored
@@ -6,57 +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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
class Row extends eventDelegater(Component) {
|
||||
render() {
|
||||
const {
|
||||
row,
|
||||
@@ -85,12 +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;
|
||||
}
|
||||
const { hideSelectColumn } = selectRow;
|
||||
const trAttrs = this.delegate(attrs);
|
||||
|
||||
return (
|
||||
<tr style={ style } className={ className } { ...trAttrs }>
|
||||
@@ -109,46 +58,51 @@ class Row extends 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 (
|
||||
<EditingCell
|
||||
key={ `${content}-${index}` }
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
column={ column }
|
||||
columnIndex={ index }
|
||||
className={ editCellclasses }
|
||||
style={ editCellstyle }
|
||||
{ ...rest }
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<EditingCell
|
||||
<Cell
|
||||
key={ `${content}-${index}` }
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columnIndex={ index }
|
||||
column={ column }
|
||||
className={ editCellclasses }
|
||||
style={ editCellstyle }
|
||||
{ ...rest }
|
||||
onStart={ onStart }
|
||||
editable={ editable }
|
||||
clickToEdit={ mode === CLICK_TO_CELL_EDIT }
|
||||
dbclickToEdit={ mode === DBCLICK_TO_CELL_EDIT }
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Cell
|
||||
key={ `${content}-${index}` }
|
||||
row={ row }
|
||||
rowIndex={ rowIndex }
|
||||
columnIndex={ index }
|
||||
column={ column }
|
||||
onStart={ onStart }
|
||||
editable={ editable }
|
||||
clickToEdit={ mode === CLICK_TO_CELL_EDIT }
|
||||
dbclickToEdit={ mode === DBCLICK_TO_CELL_EDIT }
|
||||
/>
|
||||
);
|
||||
return false;
|
||||
})
|
||||
}
|
||||
</tr>
|
||||
|
||||
@@ -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,11 @@ 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);
|
||||
}
|
||||
|
||||
if (this.isRemoteSort() || this.isRemotePagination()) {
|
||||
this.handleSortChange();
|
||||
@@ -35,18 +39,25 @@ 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (this.isRemoteSort() || this.isRemotePagination()) {
|
||||
this.handleSortChange();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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(
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
columns={ columns }
|
||||
data={ data }
|
||||
store={ store }
|
||||
classes={ classes }
|
||||
/>);
|
||||
});
|
||||
|
||||
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(
|
||||
<BootstrapTable
|
||||
keyField="id"
|
||||
columns={ columns }
|
||||
data={ data }
|
||||
store={ store }
|
||||
id={ id }
|
||||
/>);
|
||||
});
|
||||
|
||||
it('should display customized id correctly', () => {
|
||||
expect(wrapper.find(`table#${id}`).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -27,24 +27,6 @@ describe('Cell', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when column.hidden prop is true', () => {
|
||||
const column = {
|
||||
dataField: 'id',
|
||||
text: 'ID',
|
||||
hidden: true
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(<Cell row={ row } columnIndex={ 1 } rowIndex={ 1 } column={ column } />);
|
||||
});
|
||||
|
||||
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(
|
||||
<Cell row={ row } columnIndex={ columnIndex } rowIndex={ 1 } column={ column } />);
|
||||
|
||||
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';
|
||||
|
||||
@@ -33,24 +33,6 @@ describe('HeaderCell', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when column.hidden props is true', () => {
|
||||
const column = {
|
||||
dataField: 'id',
|
||||
text: 'ID',
|
||||
hidden: true
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(<HeaderCell column={ column } index={ index } />);
|
||||
});
|
||||
|
||||
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(() => {
|
||||
|
||||
@@ -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(
|
||||
<Header
|
||||
{ ...mockHeaderResolvedProps }
|
||||
columns={ newColumns }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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' };
|
||||
|
||||
@@ -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'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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(
|
||||
<RowSelectionWrapper
|
||||
keyField={ keyField }
|
||||
@@ -54,6 +54,10 @@ describe('RowSelectionWrapper', () => {
|
||||
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,11 +68,54 @@ describe('RowSelectionWrapper', () => {
|
||||
expect(wrapper.props().onAllRowsSelect).toBeDefined();
|
||||
});
|
||||
|
||||
describe('componentWillReceiveProps', () => {
|
||||
const nextSelected = [0];
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when selectRow.selected is defined', () => {
|
||||
beforeEach(() => {
|
||||
selectRow.mode = 'checkbox';
|
||||
selectRow.selected = [1, 3];
|
||||
wrapper = shallow(
|
||||
<RowSelectionWrapper
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
selectRow={ selectRow }
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
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];
|
||||
|
||||
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]);
|
||||
|
||||
@@ -94,7 +141,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]));
|
||||
|
||||
@@ -108,21 +155,13 @@ 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]));
|
||||
|
||||
wrapper.instance().handleAllRowsSelect();
|
||||
expect(wrapper.state('selectedRowKeys')).toEqual([]);
|
||||
});
|
||||
|
||||
it('call handleAllRowsSelect function with a bool args should seting correct state.selectedRowKeys', () => {
|
||||
wrapper.instance().handleAllRowsSelect(true);
|
||||
expect(wrapper.state('selectedRowKeys')).toEqual(expect.arrayContaining([firstSelectedRow, secondSelectedRow]));
|
||||
|
||||
wrapper.instance().handleAllRowsSelect(false);
|
||||
expect(wrapper.state('selectedRowKeys')).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when selectRow.onSelect is defined', () => {
|
||||
@@ -172,13 +211,14 @@ describe('RowSelectionWrapper', () => {
|
||||
});
|
||||
|
||||
it('selectRow.onSelect callback should be called correctly when calling handleRowSelect function', () => {
|
||||
wrapper.instance().handleAllRowsSelect();
|
||||
const e = {};
|
||||
wrapper.instance().handleAllRowsSelect(e);
|
||||
expect(onSelectAllCallBack.callCount).toEqual(1);
|
||||
expect(onSelectAllCallBack.calledWith(true, data)).toBeTruthy();
|
||||
expect(onSelectAllCallBack.calledWith(true, data, e)).toBeTruthy();
|
||||
|
||||
wrapper.instance().handleAllRowsSelect();
|
||||
wrapper.instance().handleAllRowsSelect(e);
|
||||
expect(onSelectAllCallBack.callCount).toEqual(2);
|
||||
expect(onSelectAllCallBack.calledWith(false, [])).toBeTruthy();
|
||||
expect(onSelectAllCallBack.calledWith(false, [], e)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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(
|
||||
<Row
|
||||
{ ...mockBodyResolvedProps }
|
||||
rowIndex={ rowIndex }
|
||||
columns={ newColumns }
|
||||
row={ row }
|
||||
/>);
|
||||
});
|
||||
|
||||
it('should not render column with hidden value true', () => {
|
||||
expect(wrapper.find(Cell).length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('selectRow', () => {
|
||||
let selectRow;
|
||||
@@ -799,8 +825,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', () => {
|
||||
|
||||
@@ -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(
|
||||
<SortWrapper
|
||||
keyField={ keyField }
|
||||
@@ -58,9 +58,10 @@ describe('SortWrapper', () => {
|
||||
|
||||
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(
|
||||
<SortWrapper
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
store={ store }
|
||||
/>
|
||||
);
|
||||
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(
|
||||
<SortWrapper
|
||||
keyField={ keyField }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
store={ store }
|
||||
defaultSorted={ defaultSorted }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should calling column.onSort function correctly', () => {
|
||||
expect(onSortCB).toHaveBeenCalledTimes(1);
|
||||
expect(onSortCB).toHaveBeenCalledWith(defaultSorted[0].dataField, defaultSorted[0].order);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('componentWillReceiveProps', () => {
|
||||
@@ -170,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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import * as path from 'path';
|
||||
import webpack from 'webpack';
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
'react-bootstrap-table2/dist/react-bootstrap-table2': './packages/react-bootstrap-table2/index.js',
|
||||
'react-bootstrap-table2/dist/react-bootstrap-table2.min': './packages/react-bootstrap-table2/index.js',
|
||||
'react-bootstrap-table2-editor/dist/react-bootstrap-table2-editor': './packages/react-bootstrap-table2-editor/index.js',
|
||||
'react-bootstrap-table2-editor/dist/react-bootstrap-table2-editor.min': './packages/react-bootstrap-table2-editor/index.js',
|
||||
'react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter': './packages/react-bootstrap-table2-filter/index.js',
|
||||
'react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min': './packages/react-bootstrap-table2-filter/index.js',
|
||||
'react-bootstrap-table2-overlay/dist/react-bootstrap-table2-overlay': './packages/react-bootstrap-table2-overlay/index.js',
|
||||
'react-bootstrap-table2-overlay/dist/react-bootstrap-table2-overlay.min': './packages/react-bootstrap-table2-overlay/index.js',
|
||||
'react-bootstrap-table2-paginator/dist/react-bootstrap-table2-paginator': './packages/react-bootstrap-table2-paginator/index.js',
|
||||
'react-bootstrap-table2-paginator/dist/react-bootstrap-table2-paginator.min': './packages/react-bootstrap-table2-paginator/index.js'
|
||||
},
|
||||
devtool: 'source-map',
|
||||
output: {
|
||||
path: path.join(__dirname, 'packages'),
|
||||
filename: '[name].js',
|
||||
library: 'ReactBootstrapTable',
|
||||
libraryTarget: 'umd'
|
||||
},
|
||||
externals: [{
|
||||
'react': {
|
||||
root: 'React',
|
||||
commonjs2: 'react',
|
||||
commonjs: 'react',
|
||||
amd: 'react'
|
||||
}
|
||||
}, {
|
||||
'react-dom': {
|
||||
root: 'ReactDOM',
|
||||
commonjs2: 'react-dom',
|
||||
commonjs: 'react-dom',
|
||||
amd: 'react-dom'
|
||||
}
|
||||
}],
|
||||
module: {
|
||||
rules: [{
|
||||
enforce: 'pre',
|
||||
test: /\.js?$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'eslint-loader'
|
||||
}, {
|
||||
test: /\.js?$/,
|
||||
use: ['babel-loader'],
|
||||
exclude: /node_modules/
|
||||
}]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('production')
|
||||
}),
|
||||
new webpack.SourceMapDevToolPlugin(),
|
||||
new webpack.optimize.DedupePlugin(),
|
||||
new webpack.optimize.OccurrenceOrderPlugin(),
|
||||
new webpack.optimize.AggressiveMergingPlugin(),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
include: /\.min\.js$/,
|
||||
compress: { warnings: false }
|
||||
})
|
||||
]
|
||||
};
|
||||
16
webpack/editor.umd.babel.js
Normal file
16
webpack/editor.umd.babel.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import * as path from 'path';
|
||||
import umdConfig from './webpack.umd.babel';
|
||||
|
||||
module.exports = {
|
||||
...umdConfig,
|
||||
entry: {
|
||||
'react-bootstrap-table2-editor/dist/react-bootstrap-table2-editor': './packages/react-bootstrap-table2-editor/index.js',
|
||||
'react-bootstrap-table2-editor/dist/react-bootstrap-table2-editor.min': './packages/react-bootstrap-table2-editor/index.js'
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, '../packages'),
|
||||
filename: '[name].js',
|
||||
library: 'ReactBootstrapTable2Editor',
|
||||
libraryTarget: 'umd'
|
||||
}
|
||||
};
|
||||
16
webpack/filter.umd.babel.js
Normal file
16
webpack/filter.umd.babel.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import * as path from 'path';
|
||||
import umdConfig from './webpack.umd.babel';
|
||||
|
||||
module.exports = {
|
||||
...umdConfig,
|
||||
entry: {
|
||||
'react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter': './packages/react-bootstrap-table2-filter/index.js',
|
||||
'react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min': './packages/react-bootstrap-table2-filter/index.js'
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, '../packages'),
|
||||
filename: '[name].js',
|
||||
library: 'ReactBootstrapTable2Filter',
|
||||
libraryTarget: 'umd'
|
||||
}
|
||||
};
|
||||
16
webpack/next.umd.babel.js
Normal file
16
webpack/next.umd.babel.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import * as path from 'path';
|
||||
import umdConfig from './webpack.umd.babel';
|
||||
|
||||
module.exports = {
|
||||
...umdConfig,
|
||||
entry: {
|
||||
'react-bootstrap-table2/dist/react-bootstrap-table-next': './packages/react-bootstrap-table2/index.js',
|
||||
'react-bootstrap-table2/dist/react-bootstrap-table-next.min': './packages/react-bootstrap-table2/index.js'
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, '../packages'),
|
||||
filename: '[name].js',
|
||||
library: 'ReactBootstrapTable2',
|
||||
libraryTarget: 'umd'
|
||||
}
|
||||
};
|
||||
16
webpack/overlay.umd.babel.js
Normal file
16
webpack/overlay.umd.babel.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import * as path from 'path';
|
||||
import umdConfig from './webpack.umd.babel';
|
||||
|
||||
module.exports = {
|
||||
...umdConfig,
|
||||
entry: {
|
||||
'react-bootstrap-table2-overlay/dist/react-bootstrap-table2-overlay': './packages/react-bootstrap-table2-overlay/index.js',
|
||||
'react-bootstrap-table2-overlay/dist/react-bootstrap-table2-overlay.min': './packages/react-bootstrap-table2-overlay/index.js'
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, '../packages'),
|
||||
filename: '[name].js',
|
||||
library: 'ReactBootstrapTable2Overlay',
|
||||
libraryTarget: 'umd'
|
||||
}
|
||||
};
|
||||
16
webpack/paginator.umd.babel.js
Normal file
16
webpack/paginator.umd.babel.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import * as path from 'path';
|
||||
import umdConfig from './webpack.umd.babel';
|
||||
|
||||
module.exports = {
|
||||
...umdConfig,
|
||||
entry: {
|
||||
'react-bootstrap-table2-paginator/dist/react-bootstrap-table2-paginator': './packages/react-bootstrap-table2-paginator/index.js',
|
||||
'react-bootstrap-table2-paginator/dist/react-bootstrap-table2-paginator.min': './packages/react-bootstrap-table2-paginator/index.js'
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, '../packages'),
|
||||
filename: '[name].js',
|
||||
library: 'ReactBootstrapTable2Paginator',
|
||||
libraryTarget: 'umd'
|
||||
}
|
||||
};
|
||||
45
webpack/webpack.umd.babel.js
Normal file
45
webpack/webpack.umd.babel.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import webpack from 'webpack';
|
||||
|
||||
module.exports = {
|
||||
devtool: 'source-map',
|
||||
externals: [{
|
||||
'react': {
|
||||
root: 'React',
|
||||
commonjs2: 'react',
|
||||
commonjs: 'react',
|
||||
amd: 'react'
|
||||
}
|
||||
}, {
|
||||
'react-dom': {
|
||||
root: 'ReactDOM',
|
||||
commonjs2: 'react-dom',
|
||||
commonjs: 'react-dom',
|
||||
amd: 'react-dom'
|
||||
}
|
||||
}],
|
||||
module: {
|
||||
rules: [{
|
||||
enforce: 'pre',
|
||||
test: /\.js?$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'eslint-loader'
|
||||
}, {
|
||||
test: /\.js?$/,
|
||||
use: ['babel-loader'],
|
||||
exclude: /node_modules/
|
||||
}]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('production')
|
||||
}),
|
||||
new webpack.SourceMapDevToolPlugin(),
|
||||
new webpack.optimize.DedupePlugin(),
|
||||
new webpack.optimize.OccurrenceOrderPlugin(),
|
||||
new webpack.optimize.AggressiveMergingPlugin(),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
include: /\.min\.js$/,
|
||||
compress: { warnings: false }
|
||||
})
|
||||
]
|
||||
};
|
||||
Reference in New Issue
Block a user