mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2026-06-29 13:40:07 +00:00
Compare commits
23 Commits
react-boot
...
react-boot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
765a49fb07 | ||
|
|
fe2fd93c20 | ||
|
|
a50148fe85 | ||
|
|
c96156503f | ||
|
|
ed2ba2a5c5 | ||
|
|
f87fe3e544 | ||
|
|
43e73313e6 | ||
|
|
888aa1d08b | ||
|
|
028834da8b | ||
|
|
8f3b989b00 | ||
|
|
fe8761427d | ||
|
|
27a09de008 | ||
|
|
20ba8cc24e | ||
|
|
b8b52e7fc0 | ||
|
|
05a8c3be5f | ||
|
|
2f9bedbeeb | ||
|
|
01be6fc275 | ||
|
|
c20a4bb220 | ||
|
|
ed21b3cb65 | ||
|
|
f2a44c976d | ||
|
|
ca5189d8ad | ||
|
|
03f51c36ac | ||
|
|
607202b4e9 |
@@ -17,6 +17,7 @@
|
|||||||
* [condensed](#condensed)
|
* [condensed](#condensed)
|
||||||
* [id](#id)
|
* [id](#id)
|
||||||
* [classes](#classes)
|
* [classes](#classes)
|
||||||
|
* [wrapperClasses](#wrapperClasses)
|
||||||
* [cellEdit](#cellEdit)
|
* [cellEdit](#cellEdit)
|
||||||
* [selectRow](#selectRow)
|
* [selectRow](#selectRow)
|
||||||
* [rowStyle](#rowStyle)
|
* [rowStyle](#rowStyle)
|
||||||
@@ -107,6 +108,9 @@ Same as bootstrap `.table-condensed` class for making a table more compact by cu
|
|||||||
Customize id on `table` element.
|
Customize id on `table` element.
|
||||||
### <a name='classes'>classes - [String]</a>
|
### <a name='classes'>classes - [String]</a>
|
||||||
Customize class on `table` element.
|
Customize class on `table` element.
|
||||||
|
|
||||||
|
### <a name='wrapperClasses'>wrapperClasses - [String]</a>
|
||||||
|
Customize class on the outer element which wrap up the `table` element.
|
||||||
### <a name='cellEdit'>cellEdit - [Object]</a>
|
### <a name='cellEdit'>cellEdit - [Object]</a>
|
||||||
Makes table cells editable, please see [cellEdit definition](./cell-edit.md) for more detail.
|
Makes table cells editable, please see [cellEdit definition](./cell-edit.md) for more detail.
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ Available properties in a column object:
|
|||||||
* [editCellClasses](#editCellClasses)
|
* [editCellClasses](#editCellClasses)
|
||||||
* [editorStyle](#editorStyle)
|
* [editorStyle](#editorStyle)
|
||||||
* [editorClasses](#editorClasses)
|
* [editorClasses](#editorClasses)
|
||||||
|
* [editor](#editor)
|
||||||
|
* [editorRenderer](#editorRenderer)
|
||||||
* [filter](#filter)
|
* [filter](#filter)
|
||||||
* [filterValue](#filterValue)
|
* [filterValue](#filterValue)
|
||||||
|
|
||||||
@@ -560,6 +562,87 @@ This is almost same as [`column.editCellStyle`](#editCellStyle), but `column.edi
|
|||||||
## <a name='editorClasses'>column.editorClasses - [Object | Function]</a>
|
## <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`).
|
This is almost same as [`column.editCellClasses`](#editCellClasses), but `column.editorClasses` is custom the class on editor instead of cell(`td`).
|
||||||
|
|
||||||
|
## <a name='editor'>column.editor - [Object]</a>
|
||||||
|
`column.editor` allow you to custom the type of cell editor by following predefined type:
|
||||||
|
|
||||||
|
* Text(Default)
|
||||||
|
* Dropdown
|
||||||
|
* Date
|
||||||
|
* Textarea
|
||||||
|
* Checkbox
|
||||||
|
|
||||||
|
Following is a quite example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
//...
|
||||||
|
, {
|
||||||
|
dataField: 'done',
|
||||||
|
text: 'Done',
|
||||||
|
editor: {
|
||||||
|
type: Type.CHECKBOX,
|
||||||
|
value: 'Y:N'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want more information, please check [here](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/master/packages/react-bootstrap-table2-editor).
|
||||||
|
|
||||||
|
## <a name='editorRenderer'>column.editorRenderer - [Function]</a>
|
||||||
|
If you feel above predefined editors are not satisfied to your requirement, you can totally custom the editor via `column.editorRenderer`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
// Custom Editor
|
||||||
|
class QualityRanger extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.number,
|
||||||
|
onUpdate: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
static defaultProps = {
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return parseInt(this.range.value, 10);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { value, onUpdate, ...rest } = this.props;
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
{ ...rest }
|
||||||
|
key="range"
|
||||||
|
ref={ node => this.range = node }
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
/>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-default"
|
||||||
|
onClick={ () => onUpdate(this.getValue()) }
|
||||||
|
>
|
||||||
|
done
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
//...
|
||||||
|
, {
|
||||||
|
dataField: 'done',
|
||||||
|
text: 'Done',
|
||||||
|
editorRenderer: (editorProps, value, row, column, rowIndex, columnIndex) =>
|
||||||
|
<QualityRanger { ...editorProps } value={ value } />;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
## <a name='filter'>column.filter - [Object]</a>
|
## <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:
|
Configure `column.filter` will able to setup a column level filter on the header column. Currently, `react-bootstrap-table2` support following filters:
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
"storybook": "cd ./packages/react-bootstrap-table2-example && yarn storybook",
|
"storybook": "cd ./packages/react-bootstrap-table2-example && yarn storybook",
|
||||||
"gh-pages:clean": "cd ./packages/react-bootstrap-table2-example && yarn gh-pages:clean",
|
"gh-pages:clean": "cd ./packages/react-bootstrap-table2-example && yarn gh-pages:clean",
|
||||||
"gh-pages:build": "cd ./packages/react-bootstrap-table2-example && yarn gh-pages:build"
|
"gh-pages:build": "cd ./packages/react-bootstrap-table2-example && yarn gh-pages:build",
|
||||||
|
"release": "yarn install && yarn build && lerna publish"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -85,7 +86,8 @@
|
|||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"collectCoverageFrom": [
|
"collectCoverageFrom": [
|
||||||
"packages/**/*.js"
|
"packages/*/src/*.js",
|
||||||
|
"packages/*/index.js"
|
||||||
],
|
],
|
||||||
"roots": [
|
"roots": [
|
||||||
"<rootDir>/packages"
|
"<rootDir>/packages"
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ How user save their new editings? We offer two ways:
|
|||||||
* Column Level (Configure [column.editable](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditable-bool-function) as bool value)
|
* Column Level (Configure [column.editable](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditable-bool-function) as bool value)
|
||||||
* 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)
|
* 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)
|
||||||
|
|
||||||
|
## 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!
|
||||||
## Customize Style/Class
|
## Customize Style/Class
|
||||||
### Editing Cell
|
### Editing Cell
|
||||||
|
|
||||||
@@ -58,6 +61,169 @@ How user save their new editings? We offer two ways:
|
|||||||
* 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 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)
|
* Customize the editor classname via [column.editoClasses](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditorclasses-string-function)
|
||||||
|
|
||||||
## Validation
|
## Rich Editors
|
||||||
|
`react-bootstrap-table2` have following predefined editor:
|
||||||
|
|
||||||
[`column.validator`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnvalidator-function) will help you to work on it!
|
* Text(Default)
|
||||||
|
* Dropdown
|
||||||
|
* Date
|
||||||
|
* Textarea
|
||||||
|
* Checkbox
|
||||||
|
|
||||||
|
In a nutshell, you just only give a [column.editor](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditor-object) and define the `type`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'done',
|
||||||
|
text: 'Done',
|
||||||
|
editor: {
|
||||||
|
type: Type.SELECT | Type.TEXTAREA | Type.CHECKBOX | Type.DATE,
|
||||||
|
... // The rest properties will be rendered into the editor's DOM element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
In the following, we go though all the predefined editors:
|
||||||
|
|
||||||
|
### Dropdown Editor
|
||||||
|
Dropdown editor give a select menu to choose a data from a list, the `editor.options` is required property for dropdown editor.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'type',
|
||||||
|
text: 'Job Type',
|
||||||
|
editor: {
|
||||||
|
type: Type.SELECT,
|
||||||
|
options: [{
|
||||||
|
value: 'A',
|
||||||
|
label: 'A'
|
||||||
|
}, {
|
||||||
|
value: 'B',
|
||||||
|
label: 'B'
|
||||||
|
}, {
|
||||||
|
value: 'C',
|
||||||
|
label: 'C'
|
||||||
|
}, {
|
||||||
|
value: 'D',
|
||||||
|
label: 'D'
|
||||||
|
}, {
|
||||||
|
value: 'E',
|
||||||
|
label: 'E'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Date Editor
|
||||||
|
Date editor is use `<input type="date">`, the configuration is very simple:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'Stock Date',
|
||||||
|
formatter: (cell) => {
|
||||||
|
let dateObj = cell;
|
||||||
|
if (typeof cell !== 'object') {
|
||||||
|
dateObj = new Date(cell);
|
||||||
|
}
|
||||||
|
return `${('0' + dateObj.getDate()).slice(-2)}/${('0' + (dateObj.getMonth() + 1)).slice(-2)}/${dateObj.getFullYear()}`;
|
||||||
|
},
|
||||||
|
editor: {
|
||||||
|
type: Type.DATE
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Textarea Editor
|
||||||
|
Textarea editor is use `<input type="textarea">`, user can press `ENTER` to change line and in the `react-bootstrap-table2`, user allow to save result via press `SHIFT` + `ENTER`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'comment',
|
||||||
|
text: 'Product Comments',
|
||||||
|
editor: {
|
||||||
|
type: Type.TEXTAREA
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
### Checkbox Editor
|
||||||
|
Checkbox editor allow you to have a pair value choice, the `editor.value` is required value to represent the actual value for check and uncheck.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'comment',
|
||||||
|
text: 'Product Comments',
|
||||||
|
editor: {
|
||||||
|
type: Type.CHECKBOX,
|
||||||
|
value: 'Y:N'
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customize Editor
|
||||||
|
If you feel above predefined editors are not satisfied to your requirement, you can certainly custom the editor via [column.editorRenderer](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditorrenderer-function). It accept a function and pass following arguments when function called:
|
||||||
|
|
||||||
|
* `editorProps`: Some useful attributes you can use on DOM editor, like class, style etc.
|
||||||
|
* `value`: Current cell value
|
||||||
|
* `row`: Current row data
|
||||||
|
* `column`: Current column definition
|
||||||
|
* `rowIndex`: Current row index
|
||||||
|
* `columnIndex`: Current column index
|
||||||
|
|
||||||
|
> Note when implement a custom React editor component, this component should have a **getValue** function which return current value on editor
|
||||||
|
|
||||||
|
> Note when you want to save value, you can call **editorProps.onUpdate** function
|
||||||
|
|
||||||
|
Following is a short example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
class QualityRanger extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.number,
|
||||||
|
onUpdate: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
static defaultProps = {
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return parseInt(this.range.value, 10);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { value, onUpdate, ...rest } = this.props;
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
{ ...rest }
|
||||||
|
key="range"
|
||||||
|
ref={ node => this.range = node }
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
/>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-default"
|
||||||
|
onClick={ () => onUpdate(this.getValue()) }
|
||||||
|
>
|
||||||
|
done
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
..., {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quality',
|
||||||
|
editorRenderer: (editorProps, value, row, column, rowIndex, columnIndex) => (
|
||||||
|
<QualityRanger { ...editorProps } value={ value } />
|
||||||
|
)
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import wrapperFactory from './src/wrapper';
|
import wrapperFactory from './src/wrapper';
|
||||||
import editingCellFactory from './src/editing-cell';
|
import editingCellFactory from './src/editing-cell';
|
||||||
import {
|
import {
|
||||||
|
EDITTYPE,
|
||||||
CLICK_TO_CELL_EDIT,
|
CLICK_TO_CELL_EDIT,
|
||||||
DBCLICK_TO_CELL_EDIT,
|
DBCLICK_TO_CELL_EDIT,
|
||||||
DELAY_FOR_DBCLICK
|
DELAY_FOR_DBCLICK
|
||||||
@@ -14,3 +15,5 @@ export default (options = {}) => ({
|
|||||||
DELAY_FOR_DBCLICK,
|
DELAY_FOR_DBCLICK,
|
||||||
options
|
options
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const Type = EDITTYPE;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table2-editor",
|
"name": "react-bootstrap-table2-editor",
|
||||||
"version": "0.1.5",
|
"version": "0.2.1",
|
||||||
"description": "it's the editor addon for react-bootstrap-table2",
|
"description": "it's the editor addon for react-bootstrap-table2",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
61
packages/react-bootstrap-table2-editor/src/checkbox-editor.js
vendored
Normal file
61
packages/react-bootstrap-table2-editor/src/checkbox-editor.js
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import cs from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
class CheckBoxEditor extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
checked: props.defaultValue.toString() === props.value.split(':')[0]
|
||||||
|
};
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.checkbox.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
const [positive, negative] = this.props.value.split(':');
|
||||||
|
return this.checkbox.checked ? positive : negative;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(e) {
|
||||||
|
if (this.props.onChange) this.props.onChange(e);
|
||||||
|
const { target } = e;
|
||||||
|
this.setState(() => ({ checked: target.checked }));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { defaultValue, className, ...rest } = this.props;
|
||||||
|
const editorClass = cs('editor edit-chseckbox checkbox', className);
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
ref={ node => this.checkbox = node }
|
||||||
|
type="checkbox"
|
||||||
|
className={ editorClass }
|
||||||
|
{ ...rest }
|
||||||
|
checked={ this.state.checked }
|
||||||
|
onChange={ this.handleChange }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBoxEditor.propTypes = {
|
||||||
|
className: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.object
|
||||||
|
]),
|
||||||
|
value: PropTypes.string,
|
||||||
|
defaultValue: PropTypes.any,
|
||||||
|
onChange: PropTypes.func
|
||||||
|
};
|
||||||
|
CheckBoxEditor.defaultProps = {
|
||||||
|
className: '',
|
||||||
|
value: 'on:off',
|
||||||
|
defaultValue: false,
|
||||||
|
onChange: undefined
|
||||||
|
};
|
||||||
|
export default CheckBoxEditor;
|
||||||
@@ -2,3 +2,11 @@ export const TIME_TO_CLOSE_MESSAGE = 3000;
|
|||||||
export const DELAY_FOR_DBCLICK = 200;
|
export const DELAY_FOR_DBCLICK = 200;
|
||||||
export const CLICK_TO_CELL_EDIT = 'click';
|
export const CLICK_TO_CELL_EDIT = 'click';
|
||||||
export const DBCLICK_TO_CELL_EDIT = 'dbclick';
|
export const DBCLICK_TO_CELL_EDIT = 'dbclick';
|
||||||
|
|
||||||
|
export const EDITTYPE = {
|
||||||
|
TEXT: 'text',
|
||||||
|
SELECT: 'select',
|
||||||
|
TEXTAREA: 'textarea',
|
||||||
|
CHECKBOX: 'checkbox',
|
||||||
|
DATE: 'date'
|
||||||
|
};
|
||||||
|
|||||||
42
packages/react-bootstrap-table2-editor/src/date-editor.js
vendored
Normal file
42
packages/react-bootstrap-table2-editor/src/date-editor.js
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import cs from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
class DateEditor extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
const { defaultValue } = this.props;
|
||||||
|
this.date.valueAsDate = new Date(defaultValue);
|
||||||
|
this.date.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.date.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { defaultValue, className, ...rest } = this.props;
|
||||||
|
const editorClass = cs('form-control editor edit-date', className);
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
ref={ node => this.date = node }
|
||||||
|
type="date"
|
||||||
|
className={ editorClass }
|
||||||
|
{ ...rest }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DateEditor.propTypes = {
|
||||||
|
className: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.object
|
||||||
|
]),
|
||||||
|
defaultValue: PropTypes.string
|
||||||
|
};
|
||||||
|
DateEditor.defaultProps = {
|
||||||
|
className: '',
|
||||||
|
defaultValue: ''
|
||||||
|
};
|
||||||
|
export default DateEditor;
|
||||||
61
packages/react-bootstrap-table2-editor/src/dropdown-editor.js
vendored
Normal file
61
packages/react-bootstrap-table2-editor/src/dropdown-editor.js
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import cs from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
class DropDownEditor extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
const { defaultValue } = this.props;
|
||||||
|
this.select.value = defaultValue;
|
||||||
|
this.select.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.select.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { defaultValue, className, options, ...rest } = this.props;
|
||||||
|
const editorClass = cs('form-control editor edit-select', className);
|
||||||
|
|
||||||
|
const attr = {
|
||||||
|
...rest,
|
||||||
|
className: editorClass
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
{ ...attr }
|
||||||
|
ref={ node => this.select = node }
|
||||||
|
defaultValue={ defaultValue }
|
||||||
|
>
|
||||||
|
{
|
||||||
|
options.map(({ label, value }) => (
|
||||||
|
<option key={ value } value={ value }>{ label }</option>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropDownEditor.propTypes = {
|
||||||
|
defaultValue: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.number
|
||||||
|
]),
|
||||||
|
className: PropTypes.string,
|
||||||
|
style: PropTypes.object,
|
||||||
|
options: PropTypes.oneOfType([
|
||||||
|
PropTypes.arrayOf(PropTypes.shape({
|
||||||
|
label: PropTypes.string,
|
||||||
|
value: PropTypes.any
|
||||||
|
}))
|
||||||
|
]).isRequired
|
||||||
|
};
|
||||||
|
DropDownEditor.defaultProps = {
|
||||||
|
className: '',
|
||||||
|
defaultValue: '',
|
||||||
|
style: {}
|
||||||
|
};
|
||||||
|
export default DropDownEditor;
|
||||||
@@ -6,9 +6,13 @@ import React, { Component } from 'react';
|
|||||||
import cs from 'classnames';
|
import cs from 'classnames';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import DropdownEditor from './dropdown-editor';
|
||||||
|
import TextAreaEditor from './textarea-editor';
|
||||||
|
import CheckBoxEditor from './checkbox-editor';
|
||||||
|
import DateEditor from './date-editor';
|
||||||
import TextEditor from './text-editor';
|
import TextEditor from './text-editor';
|
||||||
import EditorIndicator from './editor-indicator';
|
import EditorIndicator from './editor-indicator';
|
||||||
import { TIME_TO_CLOSE_MESSAGE } from './const';
|
import { TIME_TO_CLOSE_MESSAGE, EDITTYPE } from './const';
|
||||||
|
|
||||||
export default _ =>
|
export default _ =>
|
||||||
class EditingCell extends Component {
|
class EditingCell extends Component {
|
||||||
@@ -73,8 +77,8 @@ export default _ =>
|
|||||||
}, timeToCloseMessage);
|
}, timeToCloseMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeComplete(row, column, newValue) {
|
beforeComplete(newValue) {
|
||||||
const { onUpdate } = this.props;
|
const { onUpdate, row, column } = this.props;
|
||||||
if (_.isFunction(column.validator)) {
|
if (_.isFunction(column.validator)) {
|
||||||
const validateForm = column.validator(newValue, row, column);
|
const validateForm = column.validator(newValue, row, column);
|
||||||
if (_.isObject(validateForm) && !validateForm.valid) {
|
if (_.isObject(validateForm) && !validateForm.valid) {
|
||||||
@@ -89,28 +93,20 @@ export default _ =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleBlur() {
|
handleBlur() {
|
||||||
const { onEscape, blurToSave, row, column } = this.props;
|
const { onEscape, blurToSave } = this.props;
|
||||||
if (blurToSave) {
|
if (blurToSave) {
|
||||||
const value = this.editor.text.value;
|
this.beforeComplete(this.editor.getValue());
|
||||||
if (!_.isDefined(value)) {
|
|
||||||
// TODO: for other custom or embed editor
|
|
||||||
}
|
|
||||||
this.beforeComplete(row, column, value);
|
|
||||||
} else {
|
} else {
|
||||||
onEscape();
|
onEscape();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown(e) {
|
handleKeyDown(e) {
|
||||||
const { onEscape, row, column } = this.props;
|
const { onEscape } = this.props;
|
||||||
if (e.keyCode === 27) { // ESC
|
if (e.keyCode === 27) { // ESC
|
||||||
onEscape();
|
onEscape();
|
||||||
} else if (e.keyCode === 13) { // ENTER
|
} else if (e.keyCode === 13) { // ENTER
|
||||||
const value = e.currentTarget.value;
|
this.beforeComplete(this.editor.getValue());
|
||||||
if (!_.isDefined(value)) {
|
|
||||||
// TODO: for other custom or embed editor
|
|
||||||
}
|
|
||||||
this.beforeComplete(row, column, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,17 +120,13 @@ export default _ =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { invalidMessage } = this.state;
|
let editor;
|
||||||
const { row, column, className, style, rowIndex, columnIndex } = this.props;
|
const { row, column, className, style, rowIndex, columnIndex } = this.props;
|
||||||
const { dataField } = column;
|
const { dataField } = column;
|
||||||
|
|
||||||
const value = _.get(row, dataField);
|
const value = _.get(row, dataField);
|
||||||
const editorAttrs = {
|
const hasError = _.isDefined(this.state.invalidMessage);
|
||||||
onKeyDown: this.handleKeyDown,
|
|
||||||
onBlur: this.handleBlur
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasError = _.isDefined(invalidMessage);
|
|
||||||
let customEditorClass = column.editorClasses || '';
|
let customEditorClass = column.editorClasses || '';
|
||||||
if (_.isFunction(column.editorClasses)) {
|
if (_.isFunction(column.editorClasses)) {
|
||||||
customEditorClass = column.editorClasses(value, row, rowIndex, columnIndex);
|
customEditorClass = column.editorClasses(value, row, rowIndex, columnIndex);
|
||||||
@@ -150,20 +142,51 @@ export default _ =>
|
|||||||
shake: hasError
|
shake: hasError
|
||||||
}, customEditorClass);
|
}, customEditorClass);
|
||||||
|
|
||||||
|
let editorProps = {
|
||||||
|
ref: node => this.editor = node,
|
||||||
|
defaultValue: value,
|
||||||
|
style: editorStyle,
|
||||||
|
className: editorClass,
|
||||||
|
onKeyDown: this.handleKeyDown,
|
||||||
|
onBlur: this.handleBlur
|
||||||
|
};
|
||||||
|
|
||||||
|
const isDefaultEditorDefined = _.isObject(column.editor);
|
||||||
|
|
||||||
|
if (isDefaultEditorDefined) {
|
||||||
|
editorProps = {
|
||||||
|
...editorProps,
|
||||||
|
...column.editor
|
||||||
|
};
|
||||||
|
} else if (_.isFunction(column.editorRenderer)) {
|
||||||
|
editorProps = {
|
||||||
|
...editorProps,
|
||||||
|
onUpdate: this.beforeComplete
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isFunction(column.editorRenderer)) {
|
||||||
|
editor = column.editorRenderer(editorProps, value, row, column, rowIndex, columnIndex);
|
||||||
|
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.SELECT) {
|
||||||
|
editor = <DropdownEditor { ...editorProps } />;
|
||||||
|
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.TEXTAREA) {
|
||||||
|
editor = <TextAreaEditor { ...editorProps } />;
|
||||||
|
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.CHECKBOX) {
|
||||||
|
editor = <CheckBoxEditor { ...editorProps } />;
|
||||||
|
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.DATE) {
|
||||||
|
editor = <DateEditor { ...editorProps } />;
|
||||||
|
} else {
|
||||||
|
editor = <TextEditor { ...editorProps } />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<td
|
<td
|
||||||
className={ cs('react-bootstrap-table-editing-cell', className) }
|
className={ cs('react-bootstrap-table-editing-cell', className) }
|
||||||
style={ style }
|
style={ style }
|
||||||
onClick={ this.handleClick }
|
onClick={ this.handleClick }
|
||||||
>
|
>
|
||||||
<TextEditor
|
{ editor }
|
||||||
ref={ node => this.editor = node }
|
{ hasError ? <EditorIndicator invalidMessage={ this.state.invalidMessage } /> : null }
|
||||||
defaultValue={ value }
|
|
||||||
style={ editorStyle }
|
|
||||||
className={ editorClass }
|
|
||||||
{ ...editorAttrs }
|
|
||||||
/>
|
|
||||||
{ hasError ? <EditorIndicator invalidMessage={ invalidMessage } /> : null }
|
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ class TextEditor extends Component {
|
|||||||
this.text.focus();
|
this.text.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.text.value;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { defaultValue, className, ...rest } = this.props;
|
const { defaultValue, className, ...rest } = this.props;
|
||||||
const editorClass = cs('form-control editor edit-text', className);
|
const editorClass = cs('form-control editor edit-text', className);
|
||||||
|
|||||||
60
packages/react-bootstrap-table2-editor/src/textarea-editor.js
vendored
Normal file
60
packages/react-bootstrap-table2-editor/src/textarea-editor.js
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import cs from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
class TextAreaEditor extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { defaultValue } = this.props;
|
||||||
|
this.text.value = defaultValue;
|
||||||
|
this.text.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.text.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown(e) {
|
||||||
|
if (e.keyCode === 13 && !e.shiftKey) return;
|
||||||
|
if (this.props.onKeyDown) {
|
||||||
|
this.props.onKeyDown(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { defaultValue, className, ...rest } = this.props;
|
||||||
|
const editorClass = cs('form-control editor edit-textarea', className);
|
||||||
|
return (
|
||||||
|
<textarea
|
||||||
|
ref={ node => this.text = node }
|
||||||
|
type="textarea"
|
||||||
|
className={ editorClass }
|
||||||
|
{ ...rest }
|
||||||
|
onKeyDown={ this.handleKeyDown }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextAreaEditor.propTypes = {
|
||||||
|
className: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.object
|
||||||
|
]),
|
||||||
|
defaultValue: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.number
|
||||||
|
]),
|
||||||
|
onKeyDown: PropTypes.func
|
||||||
|
};
|
||||||
|
TextAreaEditor.defaultProps = {
|
||||||
|
className: '',
|
||||||
|
defaultValue: '',
|
||||||
|
onKeyDown: undefined
|
||||||
|
};
|
||||||
|
export default TextAreaEditor;
|
||||||
@@ -6,7 +6,12 @@ import { shallow, mount } from 'enzyme';
|
|||||||
|
|
||||||
import _ from 'react-bootstrap-table-next/src/utils';
|
import _ from 'react-bootstrap-table-next/src/utils';
|
||||||
import editingCellFactory from '../src/editing-cell';
|
import editingCellFactory from '../src/editing-cell';
|
||||||
|
import * as constants from '../src/const';
|
||||||
import TextEditor from '../src/text-editor';
|
import TextEditor from '../src/text-editor';
|
||||||
|
import DateEditor from '../src/date-editor';
|
||||||
|
import DropDownEditor from '../src/dropdown-editor';
|
||||||
|
import TextAreaEditor from '../src/textarea-editor';
|
||||||
|
import CheckBoxEditor from '../src/checkbox-editor';
|
||||||
import EditorIndicator from '../src/editor-indicator';
|
import EditorIndicator from '../src/editor-indicator';
|
||||||
|
|
||||||
const EditingCell = editingCellFactory(_);
|
const EditingCell = editingCellFactory(_);
|
||||||
@@ -39,7 +44,7 @@ describe('EditingCell', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
onEscape = sinon.stub();
|
onEscape = sinon.stub();
|
||||||
onUpdate = sinon.stub();
|
onUpdate = sinon.stub();
|
||||||
wrapper = shallow(
|
wrapper = mount(
|
||||||
<EditingCell
|
<EditingCell
|
||||||
row={ row }
|
row={ row }
|
||||||
rowIndex={ rowIndex }
|
rowIndex={ rowIndex }
|
||||||
@@ -74,7 +79,8 @@ describe('EditingCell', () => {
|
|||||||
it('when press ENTER on TextEditor should call onUpdate correctly', () => {
|
it('when press ENTER on TextEditor should call onUpdate correctly', () => {
|
||||||
const newValue = 'test';
|
const newValue = 'test';
|
||||||
const textEditor = wrapper.find(TextEditor);
|
const textEditor = wrapper.find(TextEditor);
|
||||||
textEditor.simulate('keyDown', { keyCode: 13, currentTarget: { value: newValue } });
|
sinon.stub(textEditor.instance(), 'getValue').returns(newValue);
|
||||||
|
textEditor.simulate('keyDown', { keyCode: 13 });
|
||||||
expect(onUpdate.callCount).toBe(1);
|
expect(onUpdate.callCount).toBe(1);
|
||||||
expect(onUpdate.calledWith(row, column, newValue)).toBe(true);
|
expect(onUpdate.calledWith(row, column, newValue)).toBe(true);
|
||||||
});
|
});
|
||||||
@@ -311,7 +317,7 @@ describe('EditingCell', () => {
|
|||||||
onEscape={ onEscape }
|
onEscape={ onEscape }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
wrapper.instance().beforeComplete(row, column, newValue);
|
wrapper.instance().beforeComplete(newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call column.validator successfully', () => {
|
it('should call column.validator successfully', () => {
|
||||||
@@ -357,7 +363,17 @@ describe('EditingCell', () => {
|
|||||||
text: 'ID',
|
text: 'ID',
|
||||||
validator: validatorCallBack
|
validator: validatorCallBack
|
||||||
};
|
};
|
||||||
wrapper.instance().beforeComplete(row, column, newValue);
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
wrapper.instance().beforeComplete(newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call column.validator successfully', () => {
|
it('should call column.validator successfully', () => {
|
||||||
@@ -370,4 +386,156 @@ describe('EditingCell', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('if column.editorRenderer is defined', () => {
|
||||||
|
const TestEditor = () => <input type="text" />;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
editorRenderer: sinon.stub().returns(<TestEditor />)
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call column.editorRenderer correctly', () => {
|
||||||
|
expect(column.editorRenderer.callCount).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render correctly', () => {
|
||||||
|
expect(wrapper.find(TestEditor)).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('if column.editor is select', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
editor: {
|
||||||
|
type: constants.EDITTYPE.SELECT,
|
||||||
|
options: [{
|
||||||
|
value: 1,
|
||||||
|
label: 'A'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render dropdown editor successfully', () => {
|
||||||
|
const editor = wrapper.find(DropDownEditor);
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(editor.length).toBe(1);
|
||||||
|
expect(editor.props().options).toEqual(column.editor.options);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('if column.editor is textarea', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
editor: {
|
||||||
|
type: constants.EDITTYPE.TEXTAREA
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render textarea editor successfully', () => {
|
||||||
|
const editor = wrapper.find(TextAreaEditor);
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(editor.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('if column.editor is checkbox', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
editor: {
|
||||||
|
type: constants.EDITTYPE.CHECKBOX
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render checkbox editor successfully', () => {
|
||||||
|
const editor = wrapper.find(CheckBoxEditor);
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(editor.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('if column.editor is date', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
column = {
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID',
|
||||||
|
editor: {
|
||||||
|
type: constants.EDITTYPE.DATE
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper = mount(
|
||||||
|
<EditingCell
|
||||||
|
row={ row }
|
||||||
|
rowIndex={ rowIndex }
|
||||||
|
columnIndex={ columnIndex }
|
||||||
|
column={ column }
|
||||||
|
onUpdate={ onUpdate }
|
||||||
|
onEscape={ onEscape }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render date editor successfully', () => {
|
||||||
|
const editor = wrapper.find(DateEditor);
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(editor.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ const columns = [{
|
|||||||
|
|
||||||
<BootstrapTable id="bar" keyField='id' data={ products } columns={ columns } />
|
<BootstrapTable id="bar" keyField='id' data={ products } columns={ columns } />
|
||||||
<BootstrapTable classes="foo" keyField='id' data={ products } columns={ columns } />
|
<BootstrapTable classes="foo" keyField='id' data={ products } columns={ columns } />
|
||||||
|
<BootstrapTable wrapperClasses="boo" keyField="id" data={ products } columns={ columns } />
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default () => (
|
export default () => (
|
||||||
@@ -43,6 +44,9 @@ export default () => (
|
|||||||
<h4> Customized table className </h4>
|
<h4> Customized table className </h4>
|
||||||
<BootstrapTable classes="foo" keyField="id" data={ products } columns={ columns } />
|
<BootstrapTable classes="foo" keyField="id" data={ products } columns={ columns } />
|
||||||
|
|
||||||
|
<h4> Customized wrapper className </h4>
|
||||||
|
<BootstrapTable wrapperClasses="boo" keyField="id" data={ products } columns={ columns } />
|
||||||
|
|
||||||
<Code>{ sourceCode }</Code>
|
<Code>{ sourceCode }</Code>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
64
packages/react-bootstrap-table2-example/examples/cell-edit/checkbox-editor-table.js
vendored
Normal file
64
packages/react-bootstrap-table2-example/examples/cell-edit/checkbox-editor-table.js
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/* eslint react/prefer-stateless-function: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { todosGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const todos = todosGenerator();
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Todo ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'todo',
|
||||||
|
text: 'Todo Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'done',
|
||||||
|
text: 'Done',
|
||||||
|
editor: {
|
||||||
|
type: Type.CHECKBOX,
|
||||||
|
value: 'Y:N'
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Todo ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'todo',
|
||||||
|
text: 'Todo Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'done',
|
||||||
|
text: 'Done',
|
||||||
|
editor: {
|
||||||
|
type: Type.CHECKBOX,
|
||||||
|
value: 'Y:N'
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ todos }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Dropdown Editor</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ todos }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
130
packages/react-bootstrap-table2-example/examples/cell-edit/custom-editor-table.js
vendored
Normal file
130
packages/react-bootstrap-table2-example/examples/cell-edit/custom-editor-table.js
vendored
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/* eslint react/prefer-stateless-function: 0 */
|
||||||
|
/* eslint no-return-assign: 0 */
|
||||||
|
/* eslint no-unused-vars: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { productsQualityGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const products = productsQualityGenerator();
|
||||||
|
|
||||||
|
class QualityRanger extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.number,
|
||||||
|
onUpdate: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
static defaultProps = {
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return parseInt(this.range.value, 10);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { value, onUpdate, ...rest } = this.props;
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
{ ...rest }
|
||||||
|
key="range"
|
||||||
|
ref={ node => this.range = node }
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
/>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-default"
|
||||||
|
onClick={ () => onUpdate(this.getValue()) }
|
||||||
|
>
|
||||||
|
done
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quality',
|
||||||
|
editorRenderer: (editorProps, value, row, column, rowIndex, columnIndex) => (
|
||||||
|
<QualityRanger { ...editorProps } value={ value } />
|
||||||
|
)
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
class QualityRanger extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.number,
|
||||||
|
onUpdate: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
static defaultProps = {
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return parseInt(this.range.value, 10);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { value, onUpdate, ...rest } = this.props;
|
||||||
|
return [
|
||||||
|
<input
|
||||||
|
{ ...rest }
|
||||||
|
key="range"
|
||||||
|
ref={ node => this.range = node }
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
/>,
|
||||||
|
<button
|
||||||
|
key="submit"
|
||||||
|
className="btn btn-default"
|
||||||
|
onClick={ () => onUpdate(this.getValue()) }
|
||||||
|
>
|
||||||
|
done
|
||||||
|
</button>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Product ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Product Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'quality',
|
||||||
|
text: 'Product Quality',
|
||||||
|
editorRenderer: (editorProps, value, row, rowIndex, columnIndex) => (
|
||||||
|
<QualityRanger { ...editorProps } value={ value } />
|
||||||
|
)
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Dropdown Editor</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ products }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
77
packages/react-bootstrap-table2-example/examples/cell-edit/date-editor-table.js
vendored
Normal file
77
packages/react-bootstrap-table2-example/examples/cell-edit/date-editor-table.js
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/* eslint prefer-template: 0 */
|
||||||
|
/* eslint react/prefer-stateless-function: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { stockGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const stocks = stockGenerator();
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'Stock Date',
|
||||||
|
formatter: (cell) => {
|
||||||
|
let dateObj = cell;
|
||||||
|
if (typeof cell !== 'object') {
|
||||||
|
dateObj = new Date(cell);
|
||||||
|
}
|
||||||
|
return `${('0' + dateObj.getDate()).slice(-2)}/${('0' + (dateObj.getMonth() + 1)).slice(-2)}/${dateObj.getFullYear()}`;
|
||||||
|
},
|
||||||
|
editor: {
|
||||||
|
type: Type.DATE
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'inStockDate',
|
||||||
|
text: 'Stock Date',
|
||||||
|
formatter: (cell) => {
|
||||||
|
let dateObj = cell;
|
||||||
|
if (typeof cell !== 'object') {
|
||||||
|
dateObj = new Date(cell);
|
||||||
|
}
|
||||||
|
return \`$\{('0' + dateObj.getDate()).slice(-2)}/$\{('0' + (dateObj.getMonth() + 1)).slice(-2)}/$\{dateObj.getFullYear()}\`;
|
||||||
|
},
|
||||||
|
editor: {
|
||||||
|
type: Type.DATE
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ stocks }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Dropdown Editor</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ stocks }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
100
packages/react-bootstrap-table2-example/examples/cell-edit/dropdown-editor-table.js
vendored
Normal file
100
packages/react-bootstrap-table2-example/examples/cell-edit/dropdown-editor-table.js
vendored
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/* eslint react/prefer-stateless-function: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { jobsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const jobs = jobsGenerator();
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Job ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Job Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'owner',
|
||||||
|
text: 'Job Owner'
|
||||||
|
}, {
|
||||||
|
dataField: 'type',
|
||||||
|
text: 'Job Type',
|
||||||
|
editor: {
|
||||||
|
type: Type.SELECT,
|
||||||
|
options: [{
|
||||||
|
value: 'A',
|
||||||
|
label: 'A'
|
||||||
|
}, {
|
||||||
|
value: 'B',
|
||||||
|
label: 'B'
|
||||||
|
}, {
|
||||||
|
value: 'C',
|
||||||
|
label: 'C'
|
||||||
|
}, {
|
||||||
|
value: 'D',
|
||||||
|
label: 'D'
|
||||||
|
}, {
|
||||||
|
value: 'E',
|
||||||
|
label: 'E'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Job ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Job Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'owner',
|
||||||
|
text: 'Job Owner'
|
||||||
|
}, {
|
||||||
|
dataField: 'type',
|
||||||
|
text: 'Job Type',
|
||||||
|
editor: {
|
||||||
|
type: Type.SELECT,
|
||||||
|
options: [{
|
||||||
|
value: 'A',
|
||||||
|
label: 'A'
|
||||||
|
}, {
|
||||||
|
value: 'B',
|
||||||
|
label: 'B'
|
||||||
|
}, {
|
||||||
|
value: 'C',
|
||||||
|
label: 'C'
|
||||||
|
}, {
|
||||||
|
value: 'D',
|
||||||
|
label: 'D'
|
||||||
|
}, {
|
||||||
|
value: 'E',
|
||||||
|
label: 'E'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ jobs }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Dropdown Editor</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ jobs }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
68
packages/react-bootstrap-table2-example/examples/cell-edit/textarea-editor-table.js
vendored
Normal file
68
packages/react-bootstrap-table2-example/examples/cell-edit/textarea-editor-table.js
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/* eslint react/prefer-stateless-function: 0 */
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
import Code from 'components/common/code-block';
|
||||||
|
import { jobsGenerator } from 'utils/common';
|
||||||
|
|
||||||
|
const jobs = jobsGenerator();
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Job ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Job Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'owner',
|
||||||
|
text: 'Job Owner'
|
||||||
|
}, {
|
||||||
|
dataField: 'type',
|
||||||
|
text: 'Job Type',
|
||||||
|
editor: {
|
||||||
|
type: Type.TEXTAREA
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
const sourceCode = `\
|
||||||
|
import BootstrapTable from 'react-bootstrap-table-next';
|
||||||
|
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
dataField: 'id',
|
||||||
|
text: 'Job ID'
|
||||||
|
}, {
|
||||||
|
dataField: 'name',
|
||||||
|
text: 'Job Name'
|
||||||
|
}, {
|
||||||
|
dataField: 'owner',
|
||||||
|
text: 'Job Owner'
|
||||||
|
}, {
|
||||||
|
dataField: 'type',
|
||||||
|
text: 'Job Type',
|
||||||
|
editor: {
|
||||||
|
type: Type.TEXTAREA
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ jobs }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div>
|
||||||
|
<h3>Dropdown Editor</h3>
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
data={ jobs }
|
||||||
|
columns={ columns }
|
||||||
|
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
|
||||||
|
/>
|
||||||
|
<Code>{ sourceCode }</Code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -65,6 +65,7 @@ const options = {
|
|||||||
prePageTitle: 'Pre page',
|
prePageTitle: 'Pre page',
|
||||||
firstPageTitle: 'Next page',
|
firstPageTitle: 'Next page',
|
||||||
lastPageTitle: 'Last page',
|
lastPageTitle: 'Last page',
|
||||||
|
showTotal: true,
|
||||||
sizePerPageList: [{
|
sizePerPageList: [{
|
||||||
text: '5', value: 5
|
text: '5', value: 5
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table2-example",
|
"name": "react-bootstrap-table2-example",
|
||||||
"version": "0.1.6",
|
"version": "0.1.8",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint no-mixed-operators: 0 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* products generator for stories
|
* products generator for stories
|
||||||
*
|
*
|
||||||
@@ -27,12 +29,34 @@ export const productsQualityGenerator = (quantity = 5) =>
|
|||||||
quality: index % 3
|
quality: index % 3
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const jobType = ['A', 'B', 'C', 'D', 'E'];
|
||||||
|
|
||||||
|
const jobOwner = ['Allen', 'Bob', 'Cindy'];
|
||||||
|
|
||||||
export const jobsGenerator = (quantity = 5) =>
|
export const jobsGenerator = (quantity = 5) =>
|
||||||
Array.from({ length: quantity }, (value, index) => ({
|
Array.from({ length: quantity }, (value, index) => ({
|
||||||
id: index,
|
id: index,
|
||||||
name: `Job name ${index}`,
|
name: `Job name ${index}`,
|
||||||
owner: Math.floor(Math.random() * 3),
|
owner: jobOwner[Math.floor((Math.random() * 2) + 1)],
|
||||||
type: Math.floor(Math.random() * 5)
|
type: jobType[Math.floor((Math.random() * 4) + 1)]
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const todosGenerator = (quantity = 5) =>
|
||||||
|
Array.from({ length: quantity }, (value, index) => ({
|
||||||
|
id: index,
|
||||||
|
todo: `Todo item ${index}`,
|
||||||
|
done: Math.random() > 0.4 ? 'Y' : 'N'
|
||||||
|
}));
|
||||||
|
|
||||||
|
const startDate = new Date(2017, 0, 1);
|
||||||
|
const endDate = new Date();
|
||||||
|
|
||||||
|
export const stockGenerator = (quantity = 5) =>
|
||||||
|
Array.from({ length: quantity }, (value, index) => ({
|
||||||
|
id: index,
|
||||||
|
name: `Todo item ${index}`,
|
||||||
|
inStockDate:
|
||||||
|
new Date(startDate.getTime() + Math.random() * (endDate.getTime() - startDate.getTime()))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
|||||||
@@ -79,6 +79,11 @@ import CellEditStyleTable from 'examples/cell-edit/cell-edit-style-table';
|
|||||||
import CellEditClassTable from 'examples/cell-edit/cell-edit-class-table';
|
import CellEditClassTable from 'examples/cell-edit/cell-edit-class-table';
|
||||||
import EditorStyleTable from 'examples/cell-edit/editor-style-table';
|
import EditorStyleTable from 'examples/cell-edit/editor-style-table';
|
||||||
import EditorClassTable from 'examples/cell-edit/editor-class-table';
|
import EditorClassTable from 'examples/cell-edit/editor-class-table';
|
||||||
|
import DropdownEditorTable from 'examples/cell-edit/dropdown-editor-table';
|
||||||
|
import TextareaEditorTable from 'examples/cell-edit/textarea-editor-table';
|
||||||
|
import CheckboxEditorTable from 'examples/cell-edit/checkbox-editor-table';
|
||||||
|
import DateEditorTable from 'examples/cell-edit/date-editor-table';
|
||||||
|
import CustomEditorTable from 'examples/cell-edit/custom-editor-table';
|
||||||
|
|
||||||
// work on row selection
|
// work on row selection
|
||||||
import SingleSelectionTable from 'examples/row-selection/single-selection';
|
import SingleSelectionTable from 'examples/row-selection/single-selection';
|
||||||
@@ -200,7 +205,12 @@ storiesOf('Cell Editing', module)
|
|||||||
.add('Custom Cell Style', () => <CellEditStyleTable />)
|
.add('Custom Cell Style', () => <CellEditStyleTable />)
|
||||||
.add('Custom Cell Classes', () => <CellEditClassTable />)
|
.add('Custom Cell Classes', () => <CellEditClassTable />)
|
||||||
.add('Custom Editor Classes', () => <EditorClassTable />)
|
.add('Custom Editor Classes', () => <EditorClassTable />)
|
||||||
.add('Custom Editor Style', () => <EditorStyleTable />);
|
.add('Custom Editor Style', () => <EditorStyleTable />)
|
||||||
|
.add('Dropdown Editor', () => <DropdownEditorTable />)
|
||||||
|
.add('Textarea Editor', () => <TextareaEditorTable />)
|
||||||
|
.add('Checkbox Editor', () => <CheckboxEditorTable />)
|
||||||
|
.add('Date Editor', () => <DateEditorTable />)
|
||||||
|
.add('Custom Editor', () => <CustomEditorTable />);
|
||||||
|
|
||||||
storiesOf('Row Selection', module)
|
storiesOf('Row Selection', module)
|
||||||
.add('Single Selection', () => <SingleSelectionTable />)
|
.add('Single Selection', () => <SingleSelectionTable />)
|
||||||
|
|||||||
@@ -5,3 +5,7 @@ table.foo {
|
|||||||
table#bar {
|
table#bar {
|
||||||
background-color: $light-blue;
|
background-color: $light-blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.boo {
|
||||||
|
border: 2px solid salmon;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table2-filter",
|
"name": "react-bootstrap-table2-filter",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"description": "it's a column filter addon for react-bootstrap-table2",
|
"description": "it's a column filter addon for react-bootstrap-table2",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -30,13 +30,11 @@ export default (Base, {
|
|||||||
// I think this condition only isRemoteFilter is enough
|
// I think this condition only isRemoteFilter is enough
|
||||||
store.filteredData = store.getAllData();
|
store.filteredData = store.getAllData();
|
||||||
this.setState(() => ({ isDataChanged: true, currFilters: store.filters }));
|
this.setState(() => ({ isDataChanged: true, currFilters: store.filters }));
|
||||||
} else if (isDataChanged) {
|
} else {
|
||||||
if (!isRemoteFilter && Object.keys(this.state.currFilters).length > 0) {
|
if (Object.keys(this.state.currFilters).length > 0) {
|
||||||
store.filteredData = filters(store, columns, _)(this.state.currFilters);
|
store.filteredData = filters(store, columns, _)(this.state.currFilters);
|
||||||
}
|
}
|
||||||
this.setState(() => ({ isDataChanged }));
|
this.setState(() => ({ isDataChanged }));
|
||||||
} else {
|
|
||||||
this.setState(() => ({ isDataChanged: false }));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +48,8 @@ export default (Base, {
|
|||||||
onFilter(column, filterType) {
|
onFilter(column, filterType) {
|
||||||
return (filterVal) => {
|
return (filterVal) => {
|
||||||
const { store, columns } = this.props;
|
const { store, columns } = this.props;
|
||||||
const currFilters = Object.assign({}, this.state.currFilters);
|
// watch out here if migration to context API, #334
|
||||||
|
const currFilters = Object.assign({}, store.filters);
|
||||||
const { dataField, filter } = column;
|
const { dataField, filter } = column;
|
||||||
|
|
||||||
if (!_.isDefined(filterVal) || filterVal === '') {
|
if (!_.isDefined(filterVal) || filterVal === '') {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table2-paginator",
|
"name": "react-bootstrap-table2-paginator",
|
||||||
"version": "0.1.1",
|
"version": "0.1.3",
|
||||||
"description": "it's the pagination addon for react-bootstrap-table2",
|
"description": "it's the pagination addon for react-bootstrap-table2",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/* eslint no-mixed-operators: 0 */
|
/* eslint no-mixed-operators: 0 */
|
||||||
|
import Const from './const';
|
||||||
|
|
||||||
export default ExtendBase =>
|
export default ExtendBase =>
|
||||||
class PageResolver extends ExtendBase {
|
class PageResolver extends ExtendBase {
|
||||||
backToPrevPage() {
|
backToPrevPage() {
|
||||||
@@ -27,6 +29,23 @@ export default ExtendBase =>
|
|||||||
return pageStartIndex + totalPages - 1;
|
return pageStartIndex + totalPages - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
calculateFromTo() {
|
||||||
|
const {
|
||||||
|
dataSize,
|
||||||
|
currPage,
|
||||||
|
currSizePerPage,
|
||||||
|
pageStartIndex
|
||||||
|
} = this.props;
|
||||||
|
const offset = Math.abs(Const.PAGE_START_INDEX - pageStartIndex);
|
||||||
|
|
||||||
|
let from = ((currPage - pageStartIndex) * currSizePerPage);
|
||||||
|
from = dataSize === 0 ? 0 : from + 1;
|
||||||
|
let to = Math.min((currSizePerPage * (currPage + offset) - 1), dataSize);
|
||||||
|
if (to >= dataSize) to -= 1;
|
||||||
|
|
||||||
|
return [from, to];
|
||||||
|
}
|
||||||
|
|
||||||
calculatePages(
|
calculatePages(
|
||||||
totalPages = this.state.totalPages,
|
totalPages = this.state.totalPages,
|
||||||
lastPage = this.state.lastPage) {
|
lastPage = this.state.lastPage) {
|
||||||
|
|||||||
16
packages/react-bootstrap-table2-paginator/src/pagination-total.js
vendored
Normal file
16
packages/react-bootstrap-table2-paginator/src/pagination-total.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const PaginationTotal = props => (
|
||||||
|
<span>
|
||||||
|
Showing rows { props.from } to { props.to + 1 } of { props.dataSize }
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
PaginationTotal.propTypes = {
|
||||||
|
from: PropTypes.number.isRequired,
|
||||||
|
to: PropTypes.number.isRequired,
|
||||||
|
dataSize: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PaginationTotal;
|
||||||
@@ -6,6 +6,7 @@ import PropTypes from 'prop-types';
|
|||||||
import pageResolver from './page-resolver';
|
import pageResolver from './page-resolver';
|
||||||
import SizePerPageDropDown from './size-per-page-dropdown';
|
import SizePerPageDropDown from './size-per-page-dropdown';
|
||||||
import PaginationList from './pagination-list';
|
import PaginationList from './pagination-list';
|
||||||
|
import PaginationTotal from './pagination-total';
|
||||||
import Const from './const';
|
import Const from './const';
|
||||||
|
|
||||||
class Pagination extends pageResolver(Component) {
|
class Pagination extends pageResolver(Component) {
|
||||||
@@ -89,13 +90,14 @@ class Pagination extends pageResolver(Component) {
|
|||||||
render() {
|
render() {
|
||||||
const { totalPages, lastPage, dropdownOpen: open } = this.state;
|
const { totalPages, lastPage, dropdownOpen: open } = this.state;
|
||||||
const {
|
const {
|
||||||
|
showTotal,
|
||||||
sizePerPageList,
|
sizePerPageList,
|
||||||
currSizePerPage,
|
currSizePerPage,
|
||||||
hideSizePerPage,
|
hideSizePerPage,
|
||||||
hidePageListOnlyOnePage
|
hidePageListOnlyOnePage
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const pages = this.calculatePageStatus(this.calculatePages(totalPages), lastPage);
|
const pages = this.calculatePageStatus(this.calculatePages(totalPages), lastPage);
|
||||||
|
const [from, to] = this.calculateFromTo();
|
||||||
const pageListClass = cs(
|
const pageListClass = cs(
|
||||||
'react-bootstrap-table-pagination-list',
|
'react-bootstrap-table-pagination-list',
|
||||||
'col-md-6 col-xs-6 col-sm-6 col-lg-6', {
|
'col-md-6 col-xs-6 col-sm-6 col-lg-6', {
|
||||||
@@ -117,6 +119,14 @@ class Pagination extends pageResolver(Component) {
|
|||||||
/>
|
/>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
showTotal ?
|
||||||
|
<PaginationTotal
|
||||||
|
from={ from }
|
||||||
|
to={ to }
|
||||||
|
dataSize={ this.props.dataSize }
|
||||||
|
/> : null
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className={ pageListClass }>
|
<div className={ pageListClass }>
|
||||||
<PaginationList pages={ pages } onPageChange={ this.handleChangePage } />
|
<PaginationList pages={ pages } onPageChange={ this.handleChangePage } />
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ export default (Base, {
|
|||||||
alwaysShowAllBtns={ alwaysShowAllBtns }
|
alwaysShowAllBtns={ alwaysShowAllBtns }
|
||||||
hideSizePerPage={ hideSizePerPage }
|
hideSizePerPage={ hideSizePerPage }
|
||||||
hidePageListOnlyOnePage={ hidePageListOnlyOnePage }
|
hidePageListOnlyOnePage={ hidePageListOnlyOnePage }
|
||||||
|
showTotal={ options.showTotal }
|
||||||
firstPageText={ options.firstPageText || Const.FIRST_PAGE_TEXT }
|
firstPageText={ options.firstPageText || Const.FIRST_PAGE_TEXT }
|
||||||
prePageText={ options.prePageText || Const.PRE_PAGE_TEXT }
|
prePageText={ options.prePageText || Const.PRE_PAGE_TEXT }
|
||||||
nextPageText={ options.nextPageText || Const.NEXT_PAGE_TEXT }
|
nextPageText={ options.nextPageText || Const.NEXT_PAGE_TEXT }
|
||||||
|
|||||||
@@ -110,6 +110,19 @@ describe('PageResolver', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('calculateFromTo', () => {
|
||||||
|
const props = createMockProps();
|
||||||
|
beforeEach(() => {
|
||||||
|
const mockElement = React.createElement(MockComponent, props, null);
|
||||||
|
wrapper = shallow(mockElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return correct array with from and to value', () => {
|
||||||
|
const instance = wrapper.instance();
|
||||||
|
expect(instance.calculateFromTo()).toEqual([1, props.currSizePerPage - 1]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('calculateTotalPage', () => {
|
describe('calculateTotalPage', () => {
|
||||||
const props = createMockProps();
|
const props = createMockProps();
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ describe('Wrapper', () => {
|
|||||||
expect(pagination.prop('nextPageTitle')).toEqual(Const.NEXT_PAGE_TITLE);
|
expect(pagination.prop('nextPageTitle')).toEqual(Const.NEXT_PAGE_TITLE);
|
||||||
expect(pagination.prop('lastPageTitle')).toEqual(Const.LAST_PAGE_TITLE);
|
expect(pagination.prop('lastPageTitle')).toEqual(Const.LAST_PAGE_TITLE);
|
||||||
expect(pagination.prop('hideSizePerPage')).toEqual(Const.HIDE_SIZE_PER_PAGE);
|
expect(pagination.prop('hideSizePerPage')).toEqual(Const.HIDE_SIZE_PER_PAGE);
|
||||||
|
expect(pagination.prop('showTotal')).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('componentWillReceiveProps', () => {
|
describe('componentWillReceiveProps', () => {
|
||||||
@@ -247,6 +248,20 @@ describe('Wrapper', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when options.showTotal is defined', () => {
|
||||||
|
const props = createTableProps({ options: { showTotal: true } });
|
||||||
|
beforeEach(() => {
|
||||||
|
createPaginationWrapper(props);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rendering Pagination correctly', () => {
|
||||||
|
const pagination = wrapper.find(Pagination);
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(pagination.length).toBe(1);
|
||||||
|
expect(pagination.prop('showTotal')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('when options.pageStartIndex is defined', () => {
|
describe('when options.pageStartIndex is defined', () => {
|
||||||
const pageStartIndex = -1;
|
const pageStartIndex = -1;
|
||||||
const props = createTableProps({ options: { pageStartIndex } });
|
const props = createTableProps({ options: { pageStartIndex } });
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-bootstrap-table-next",
|
"name": "react-bootstrap-table-next",
|
||||||
"version": "0.1.8",
|
"version": "0.1.12",
|
||||||
"description": "Next generation of react-bootstrap-table",
|
"description": "Next generation of react-bootstrap-table",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -52,9 +52,12 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
|||||||
caption,
|
caption,
|
||||||
rowStyle,
|
rowStyle,
|
||||||
rowClasses,
|
rowClasses,
|
||||||
|
wrapperClasses,
|
||||||
rowEvents
|
rowEvents
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
const tableWrapperClass = cs('react-bootstrap-table', wrapperClasses);
|
||||||
|
|
||||||
const tableClass = cs('table', {
|
const tableClass = cs('table', {
|
||||||
'table-striped': striped,
|
'table-striped': striped,
|
||||||
'table-hover': hover,
|
'table-hover': hover,
|
||||||
@@ -75,7 +78,7 @@ class BootstrapTable extends PropsBaseResolver(Component) {
|
|||||||
const tableCaption = (caption && <Caption>{ caption }</Caption>);
|
const tableCaption = (caption && <Caption>{ caption }</Caption>);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="react-bootstrap-table">
|
<div className={ tableWrapperClass }>
|
||||||
<table id={ id } className={ tableClass }>
|
<table id={ id } className={ tableClass }>
|
||||||
{ tableCaption }
|
{ tableCaption }
|
||||||
<Header
|
<Header
|
||||||
@@ -120,6 +123,7 @@ BootstrapTable.propTypes = {
|
|||||||
hover: PropTypes.bool,
|
hover: PropTypes.bool,
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
classes: PropTypes.string,
|
classes: PropTypes.string,
|
||||||
|
wrapperClasses: PropTypes.string,
|
||||||
condensed: PropTypes.bool,
|
condensed: PropTypes.bool,
|
||||||
caption: PropTypes.oneOfType([
|
caption: PropTypes.oneOfType([
|
||||||
PropTypes.node,
|
PropTypes.node,
|
||||||
|
|||||||
4
packages/react-bootstrap-table2/src/cell.js
vendored
4
packages/react-bootstrap-table2/src/cell.js
vendored
@@ -88,7 +88,9 @@ class Cell extends Component {
|
|||||||
cellAttrs.onDoubleClick = this.handleEditingCell;
|
cellAttrs.onDoubleClick = this.handleEditingCell;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<td { ...cellAttrs }>{ content }</td>
|
<td { ...cellAttrs }>
|
||||||
|
{ typeof content === 'boolean' ? `${content}` : content }
|
||||||
|
</td>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,11 +127,13 @@ HeaderCell.propTypes = {
|
|||||||
sort: PropTypes.bool,
|
sort: PropTypes.bool,
|
||||||
sortFunc: PropTypes.func,
|
sortFunc: PropTypes.func,
|
||||||
onSort: PropTypes.func,
|
onSort: PropTypes.func,
|
||||||
|
editor: PropTypes.object,
|
||||||
editable: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
|
editable: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
|
||||||
editCellStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
editCellStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||||
editCellClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
editCellClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||||
editorStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
editorStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||||
editorClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
editorClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||||
|
editorRenderer: PropTypes.func,
|
||||||
validator: PropTypes.func,
|
validator: PropTypes.func,
|
||||||
filter: PropTypes.object,
|
filter: PropTypes.object,
|
||||||
filterValue: PropTypes.func
|
filterValue: PropTypes.func
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import _ from './utils';
|
|||||||
|
|
||||||
const events = [
|
const events = [
|
||||||
'onClick',
|
'onClick',
|
||||||
|
'onDoubleClick',
|
||||||
'onMouseEnter',
|
'onMouseEnter',
|
||||||
'onMouseLeave'
|
'onMouseLeave'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -74,6 +74,25 @@ describe('BootstrapTable', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when props.wrapperClasses was defined', () => {
|
||||||
|
const classes = 'foo';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = shallow(
|
||||||
|
<BootstrapTable
|
||||||
|
keyField="id"
|
||||||
|
columns={ columns }
|
||||||
|
data={ data }
|
||||||
|
store={ store }
|
||||||
|
wrapperClasses={ classes }
|
||||||
|
/>);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display customized classes correctly', () => {
|
||||||
|
expect(wrapper.find(`.${classes}`).length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('when props.id was defined', () => {
|
describe('when props.id was defined', () => {
|
||||||
const id = 'foo';
|
const id = 'foo';
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,25 @@ describe('Cell', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when content is bool value', () => {
|
||||||
|
const column = {
|
||||||
|
dataField: 'col1',
|
||||||
|
text: 'column 1'
|
||||||
|
};
|
||||||
|
const aRowWithBoolValue = { col1: true };
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = shallow(
|
||||||
|
<Cell row={ aRowWithBoolValue } columnIndex={ 1 } rowIndex={ 1 } column={ column } />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render successfully', () => {
|
||||||
|
expect(wrapper.length).toBe(1);
|
||||||
|
expect(wrapper.text()).toEqual(aRowWithBoolValue[column.dataField].toString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('when column.formatter prop is defined', () => {
|
describe('when column.formatter prop is defined', () => {
|
||||||
const rowIndex = 1;
|
const rowIndex = 1;
|
||||||
const column = {
|
const column = {
|
||||||
|
|||||||
Reference in New Issue
Block a user