From 20bb9c0d1b08e68b625b63fbe3a97e6236b4c7a6 Mon Sep 17 00:00:00 2001 From: Allen Date: Sat, 26 Aug 2017 02:24:00 -0500 Subject: [PATCH] Implement column title (#22) fix #21 --- .../src/index.js | 60 ++++++++++++++++++- packages/react-bootstrap-table2/src/cell.js | 19 ++++-- .../react-bootstrap-table2/src/header-cell.js | 32 +++++++--- packages/react-bootstrap-table2/src/header.js | 5 +- .../react-bootstrap-table2/test/cell.test.js | 49 +++++++++++++++ .../test/header-cell.test.js | 58 ++++++++++++++++-- 6 files changed, 203 insertions(+), 20 deletions(-) diff --git a/packages/react-bootstrap-table2-example/src/index.js b/packages/react-bootstrap-table2-example/src/index.js index 642fdb1..e6730f5 100644 --- a/packages/react-bootstrap-table2-example/src/index.js +++ b/packages/react-bootstrap-table2-example/src/index.js @@ -3,8 +3,64 @@ import ReactDom from 'react-dom'; import { BootstrapTable } from 'react-bootstrap-table2'; -const data = [1, 2, 3, 4]; +const products = []; + +function addProducts(quantity) { + const startId = products.length; + for (let i = 0; i < quantity; i += 1) { + const id = startId + i; + products.push({ + id, + name: `Item name ${id}`, + price: 2100 + i, + nest: { + address: 'Address 1', + postcal: '0922-1234' + } + }); + } +} + +addProducts(5); + +const columns = [{ + dataField: 'id', + text: 'Product ID', + style: { + backgroundColor: 'red' + }, + headerTitle: (column, colIndex) => { + console.log(column); + console.log(colIndex); + return 'yes~~~ oh'; + }, + classes: 'my-xxx' +}, { + dataField: 'name', + text: 'Product Name', + headerTitle: true, + formatter: (cell, row) => + (

{ cell }::: ${ row.price }

) +}, { + dataField: 'price', + text: 'Product Price', + style: (cell, row, colIndex) => { + console.log(cell); + console.log(row); + console.log(colIndex); + return { + backgroundColor: 'blue' + }; + } +}, { + dataField: 'nest.address', + text: 'Address' +}, { + dataField: 'nest.postcal', + text: 'Postal' +}]; + ReactDom.render( - , + , document.getElementById('example')); diff --git a/packages/react-bootstrap-table2/src/cell.js b/packages/react-bootstrap-table2/src/cell.js index a585d20..8d082fe 100644 --- a/packages/react-bootstrap-table2/src/cell.js +++ b/packages/react-bootstrap-table2/src/cell.js @@ -9,19 +9,28 @@ const Cell = ({ row, rowIndex, column, columnIndex }) => { formatter, formatExtraData, style, - classes + classes, + title } = column; let content = _.get(row, dataField); + let cellTitle; + + const attrs = {}; const cellStyle = _.isFunction(style) ? style(content, row, columnIndex) : style; const cellClasses = _.isFunction(classes) ? classes(content, row, columnIndex) : classes; + + if (title) { + cellTitle = _.isFunction(title) ? title(content, row, columnIndex) : content; + attrs.title = cellTitle; + } + if (formatter) { content = column.formatter(content, row, rowIndex, formatExtraData); } - const attrs = { - style: cellStyle, - className: cellClasses - }; + attrs.style = cellStyle; + attrs.className = cellClasses; + return ( { content } ); diff --git a/packages/react-bootstrap-table2/src/header-cell.js b/packages/react-bootstrap-table2/src/header-cell.js index e43713b..2385017 100644 --- a/packages/react-bootstrap-table2/src/header-cell.js +++ b/packages/react-bootstrap-table2/src/header-cell.js @@ -1,18 +1,36 @@ import React from 'react'; import PropTypes from 'prop-types'; +import _ from './utils'; -const HeaderCell = ({ column }) => ( - - { column.text } - -); + +const HeaderCell = ({ column, index }) => { + const { headerTitle, text } = column; + const attrs = {}; + + if (headerTitle) { + attrs.title = _.isFunction(headerTitle) ? headerTitle(column, index) : text; + } + + return ( + + { column.text } + + ); +}; HeaderCell.propTypes = { column: PropTypes.shape({ dataField: PropTypes.string.isRequired, - text: PropTypes.string.isRequired - }).isRequired + text: PropTypes.string.isRequired, + formatter: PropTypes.func, + formatExtraData: PropTypes.any, + classes: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), + style: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), + headerTitle: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]), + title: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]) + }).isRequired, + index: PropTypes.number.isRequired }; export default HeaderCell; diff --git a/packages/react-bootstrap-table2/src/header.js b/packages/react-bootstrap-table2/src/header.js index 692e920..eddf6a2 100644 --- a/packages/react-bootstrap-table2/src/header.js +++ b/packages/react-bootstrap-table2/src/header.js @@ -7,7 +7,10 @@ import HeaderCell from './header-cell'; const Header = ({ columns }) => ( - { columns.map(column => ) } + { + columns.map((column, i) => + ) + } ); diff --git a/packages/react-bootstrap-table2/test/cell.test.js b/packages/react-bootstrap-table2/test/cell.test.js index 45157c2..1b204ed 100644 --- a/packages/react-bootstrap-table2/test/cell.test.js +++ b/packages/react-bootstrap-table2/test/cell.test.js @@ -161,4 +161,53 @@ describe('Cell', () => { }); }); }); + + describe('when column.title prop is defined', () => { + let column; + const columnIndex = 1; + + beforeEach(() => { + column = { + dataField: 'id', + text: 'ID' + }; + }); + + describe('when title is boolean', () => { + beforeEach(() => { + column.title = true; + wrapper = shallow( + ); + }); + + it('should render title as cell value as default', () => { + expect(wrapper.length).toBe(1); + expect(wrapper.find('td').prop('title')).toEqual(row[column.dataField]); + }); + }); + + describe('when title is custom function', () => { + const customTitle = 'test_title'; + let titleCallBack; + + beforeEach(() => { + titleCallBack = sinon.stub() + .withArgs(row[column.dataField], row, columnIndex) + .returns(customTitle); + column.title = titleCallBack; + wrapper = shallow( + ); + }); + + it('should render title correctly by custom title function', () => { + expect(wrapper.length).toBe(1); + expect(wrapper.find('td').prop('title')).toBe(customTitle); + }); + + it('should call custom title function correctly', () => { + expect(titleCallBack.callCount).toBe(1); + expect(titleCallBack.calledWith(row[column.dataField], row, columnIndex)).toBe(true); + }); + }); + }); }); diff --git a/packages/react-bootstrap-table2/test/header-cell.test.js b/packages/react-bootstrap-table2/test/header-cell.test.js index e0cc3f7..56a9727 100644 --- a/packages/react-bootstrap-table2/test/header-cell.test.js +++ b/packages/react-bootstrap-table2/test/header-cell.test.js @@ -1,18 +1,21 @@ import React from 'react'; +import sinon from 'sinon'; import { shallow } from 'enzyme'; import HeaderCell from '../src/header-cell'; describe('HeaderCell', () => { let wrapper; - const column = { - dataField: 'id', - text: 'ID' - }; + const index = 1; describe('simplest header cell', () => { + const column = { + dataField: 'id', + text: 'ID' + }; + beforeEach(() => { - wrapper = shallow(); + wrapper = shallow(); }); it('should render successfully', () => { @@ -21,4 +24,49 @@ describe('HeaderCell', () => { expect(wrapper.contains({ column.text })).toBe(true); }); }); + + describe('when column.headerTitle prop is defined', () => { + let column; + beforeEach(() => { + column = { + dataField: 'id', + text: 'ID' + }; + }); + + describe('when headerTitle is boolean', () => { + beforeEach(() => { + column.headerTitle = true; + wrapper = shallow(); + }); + + it('should render title as column.text as default', () => { + expect(wrapper.length).toBe(1); + expect(wrapper.find('th').prop('title')).toBe(column.text); + }); + }); + + describe('when headerTitle is custom function', () => { + const customTitle = 'test_title'; + let titleCallBack; + + beforeEach(() => { + titleCallBack = sinon.stub() + .withArgs(column) + .returns(customTitle); + column.headerTitle = titleCallBack; + wrapper = shallow(); + }); + + it('should render title correctly by custom title function', () => { + expect(wrapper.length).toBe(1); + expect(wrapper.find('th').prop('title')).toBe(customTitle); + }); + + it('should call custom title function correctly', () => { + expect(titleCallBack.callCount).toBe(1); + expect(titleCallBack.calledWith(column)).toBe(true); + }); + }); + }); });