From 94d21fee772015d802500842b69722493be3959d Mon Sep 17 00:00:00 2001 From: Daniil Khanin Date: Tue, 10 Oct 2017 09:52:32 +0300 Subject: [PATCH] fix #66 --- .../cell-edit/cell-level-editable-table.js | 55 +++++++++++++++++++ .../stories/index.js | 4 +- packages/react-bootstrap-table2/src/cell.js | 15 +++-- .../react-bootstrap-table2/src/header-cell.js | 2 +- packages/react-bootstrap-table2/src/row.js | 11 +++- .../test/editing-cell.test.js | 35 +++++++++++- .../test/test-helpers/productGenerator.js | 21 +++++++ 7 files changed, 131 insertions(+), 12 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/cell-edit/cell-level-editable-table.js create mode 100644 packages/react-bootstrap-table2/test/test-helpers/productGenerator.js diff --git a/packages/react-bootstrap-table2-example/examples/cell-edit/cell-level-editable-table.js b/packages/react-bootstrap-table2-example/examples/cell-edit/cell-level-editable-table.js new file mode 100644 index 0000000..da825d1 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/cell-edit/cell-level-editable-table.js @@ -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' +}; + + +`; + +const cellEdit = { + mode: 'click' +}; +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 7c43434..605d5d8 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -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', () => ) .add('Column Level Editable', () => ) .add('Rich Hook Functions', () => ) - .add('Validation', () => ); + .add('Validation', () => ) + .add('Cell Level Editable', () => ); diff --git a/packages/react-bootstrap-table2/src/cell.js b/packages/react-bootstrap-table2/src/cell.js index e4431e6..d9e3582 100644 --- a/packages/react-bootstrap-table2/src/cell.js +++ b/packages/react-bootstrap-table2/src/cell.js @@ -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 ( { content } diff --git a/packages/react-bootstrap-table2/src/header-cell.js b/packages/react-bootstrap-table2/src/header-cell.js index 1b9c42a..13c6727 100644 --- a/packages/react-bootstrap-table2/src/header-cell.js +++ b/packages/react-bootstrap-table2/src/header-cell.js @@ -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, diff --git a/packages/react-bootstrap-table2/src/row.js b/packages/react-bootstrap-table2/src/row.js index ed76102..117dce4 100644 --- a/packages/react-bootstrap-table2/src/row.js +++ b/packages/react-bootstrap-table2/src/row.js @@ -26,12 +26,17 @@ const Row = (props) => { { 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 ( { } return ( { 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(); + 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(); + }); + }); }); diff --git a/packages/react-bootstrap-table2/test/test-helpers/productGenerator.js b/packages/react-bootstrap-table2/test/test-helpers/productGenerator.js new file mode 100644 index 0000000..4049e60 --- /dev/null +++ b/packages/react-bootstrap-table2/test/test-helpers/productGenerator.js @@ -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 + })) + ); +};