This commit is contained in:
Daniil Khanin 2017-10-10 09:52:32 +03:00 committed by Allen
parent c2e22d5710
commit 94d21fee77
7 changed files with 131 additions and 12 deletions

View File

@ -0,0 +1,55 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import { BootstrapTableful } from 'react-bootstrap-table2';
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',
editable: (content, row, rowIndex, columnIndex) => content > 2101
}];
const sourceCode = `\
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
editable: (content, row, rowIndex, columnIndex) => content > 2101
}];
const cellEdit = {
mode: 'click'
};
<BootstrapTableful
keyField='id'
data={ products }
columns={ columns }
cellEdit={ cellEdit }
/>
`;
const cellEdit = {
mode: 'click'
};
export default () => (
<div>
<BootstrapTableful keyField="id" data={ products } columns={ columns } cellEdit={ cellEdit } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -41,6 +41,7 @@ import DoubleClickToEditTable from 'examples/cell-edit/dbclick-to-edit-table';
import BlurToSaveTable from 'examples/cell-edit/blur-to-save-table';
import RowLevelEditableTable from 'examples/cell-edit/row-level-editable-table';
import ColumnLevelEditableTable from 'examples/cell-edit/column-level-editable-table';
import CellLevelEditable from 'examples/cell-edit/cell-level-editable-table';
import CellEditHooks from 'examples/cell-edit/cell-edit-hooks-table';
import CellEditValidator from 'examples/cell-edit/cell-edit-validator-table';
@ -94,4 +95,5 @@ storiesOf('Cell Editing', module)
.add('Row Level Editable', () => <RowLevelEditableTable />)
.add('Column Level Editable', () => <ColumnLevelEditableTable />)
.add('Rich Hook Functions', () => <CellEditHooks />)
.add('Validation', () => <CellEditValidator />);
.add('Validation', () => <CellEditValidator />)
.add('Cell Level Editable', () => <CellLevelEditable />);

View File

@ -60,6 +60,14 @@ class Cell extends Component {
? classes(content, row, rowIndex, columnIndex)
: classes;
const setEditMode = () => {
if (editMode === Const.CLICK_TO_CELL_EDIT) {
cellAttrs.onClick = this.handleEditingCell;
} else {
cellAttrs.onDoubleClick = this.handleEditingCell;
}
};
if (style) {
cellStyle = _.isFunction(style) ? style(content, row, rowIndex, columnIndex) : style;
}
@ -85,13 +93,8 @@ class Cell extends Component {
if (cellClasses) cellAttrs.className = cellClasses;
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
if (editable && editMode !== Const.UNABLE_TO_CELL_EDIT) {
if (editMode === Const.CLICK_TO_CELL_EDIT) { // click to edit
cellAttrs.onClick = this.handleEditingCell;
} else { // dbclick to edit
cellAttrs.onDoubleClick = this.handleEditingCell;
}
setEditMode();
}
return (
<td { ...cellAttrs }>{ content }</td>

View File

@ -100,7 +100,7 @@ HeaderCell.propTypes = {
align: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
sort: PropTypes.bool,
sortFunc: PropTypes.func,
editable: PropTypes.bool,
editable: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
validator: PropTypes.func
}).isRequired,
index: PropTypes.number.isRequired,

View File

@ -26,12 +26,17 @@ const Row = (props) => {
<tr>
{
columns.map((column, index) => {
const { dataField } = column;
const content = _.get(row, dataField);
let editable = _.isDefined(column.editable) ? column.editable : true;
if (column.dataField === keyField || !editableRow) editable = false;
if (dataField === keyField || !editableRow) editable = false;
if (_.isFunction(column.editable)) {
editable = column.editable(content, row, rowIndex, index);
}
if (rowIndex === editingRowIdx && index === editingColIdx) {
return (
<EditingCell
key={ _.get(row, column.dataField) }
key={ content }
row={ row }
column={ column }
{ ...rest }
@ -40,7 +45,7 @@ const Row = (props) => {
}
return (
<Cell
key={ _.get(row, column.dataField) }
key={ content }
row={ row }
rowIndex={ rowIndex }
columnIndex={ index }

View File

@ -4,10 +4,13 @@ import sinon from 'sinon';
import { shallow, mount } from 'enzyme';
import { TableRowWrapper } from './test-helpers/table-wrapper';
import BootstrapTable from '../src/bootstrap-table';
import EditingCell from '../src/editing-cell';
import TextEditor from '../src/text-editor';
import EditorIndicator from '../src/editor-indicator';
import { productsGenerator } from './test-helpers/productGenerator';
import Row from '../src/row';
import Cell from '../src/cell';
describe('EditingCell', () => {
let wrapper;
@ -170,4 +173,34 @@ describe('EditingCell', () => {
});
});
});
describe('when column.editable is function', () => {
const products = productsGenerator();
const mockFunction = jest.fn(content => content > 2102);
const col = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
editable: mockFunction
}];
const renderComponent = mount(<BootstrapTable keyField="id" data={ products } columns={ col } />);
const rowComponent = renderComponent.find(Row);
it(`column.editable function should be called ${products.length} times`, () => {
expect(mockFunction).toHaveBeenCalledTimes(products.length);
});
it('should call callBack with right args', () => {
expect(mockFunction).toHaveBeenLastCalledWith(2104, { id: 4, name: 'Item name 4', price: 2104 }, 4, 2);
});
it('should be "editable" === false', () => {
expect(rowComponent.at(2).find(Cell).at(2).props().editable).toBeFalsy();
});
it('should be "editable" === true', () => {
expect(rowComponent.at(3).find(Cell).at(2).props().editable).toBeTruthy();
});
});
});

View File

@ -0,0 +1,21 @@
/**
* products generator for stories
*
* @param {Number} quantity - quantity of products
* @param {Function} callback - callback func which is similiar to 'mapFunction'
* aims to customize product format
*
* @return {Array} - products array
*/
export const productsGenerator = (quantity = 5, callback) => {
if (callback) return Array.from({ length: quantity }, callback);
// if no given callback, retrun default product format.
return (
Array.from({ length: quantity }, (value, index) => ({
id: index,
name: `Item name ${index}`,
price: 2100 + index
}))
);
};