From 5d5151aa00aab2704e25f16c8a51a0af6a78e7fd Mon Sep 17 00:00:00 2001 From: Bebe Peng Date: Mon, 10 Nov 2014 10:20:15 -0500 Subject: [PATCH] feat(table-sortable): columns can be sortable or unsortable [#80914122] Signed-off-by: Geoff Pleiss --- src/pivotal-ui/components/tables.scss | 9 +- src/pivotal-ui/javascripts/table-sortable.jsx | 22 ++-- test/spec/javascripts/table_sortable_spec.js | 123 ++++++++++++------ 3 files changed, 103 insertions(+), 51 deletions(-) diff --git a/src/pivotal-ui/components/tables.scss b/src/pivotal-ui/components/tables.scss index 696669a0a..0ba5b6bc2 100644 --- a/src/pivotal-ui/components/tables.scss +++ b/src/pivotal-ui/components/tables.scss @@ -345,15 +345,18 @@ $(function() { var columns = [ { name: 'name', - title: 'Name' + title: 'Name', + sortable: true }, { name: 'instances', - title: 'Instances' + title: 'Instances', + sortable: true }, { name: 'cpu', - title: 'CPU' + title: 'CPU', + sortable: true }, { name: 'synergy', diff --git a/src/pivotal-ui/javascripts/table-sortable.jsx b/src/pivotal-ui/javascripts/table-sortable.jsx index 17fbf8fa4..b44b9bebf 100644 --- a/src/pivotal-ui/javascripts/table-sortable.jsx +++ b/src/pivotal-ui/javascripts/table-sortable.jsx @@ -6,22 +6,26 @@ var _ = require('lodash'); var TableHeader = React.createClass({ handleClick: function handleClick(e) { - this.props.onTableHeaderClick(this); + if (this.props.sortable) { + this.props.onSortableTableHeaderClick(this); + } }, render: function render() { var sortClass; - if (this.props.sortState.column !== this.props.key) { - sortClass = 'sorted-none'; - } else if (this.props.sortState.order === 'asc') { - sortClass = 'sorted-asc'; - } else { - sortClass = 'sorted-desc'; + if (this.props.sortable) { + if (this.props.sortState.column !== this.props.key) { + sortClass = 'sortable sorted-none'; + } else if (this.props.sortState.order === 'asc') { + sortClass = 'sortable sorted-asc'; + } else { + sortClass = 'sortable sorted-desc'; + } } return ( - + {this.props.children} ); @@ -86,7 +90,7 @@ var TableSortable = module.exports = React.createClass({ render: function render() { var headings = _.map(this.props.columns, function(column) { return ( - + {column.title} ); diff --git a/test/spec/javascripts/table_sortable_spec.js b/test/spec/javascripts/table_sortable_spec.js index 76807d2fe..8157e0971 100644 --- a/test/spec/javascripts/table_sortable_spec.js +++ b/test/spec/javascripts/table_sortable_spec.js @@ -13,25 +13,35 @@ describe('TableSortable', function() { this.columns = [ { name: 'title', - title: 'Title' + title: 'Title', + sortable: true }, { name: 'instances', - title: 'Instances' + title: 'Instances', + sortable: true + }, + { + name: 'unsortable', + title: 'Unsortable', + sortable: false } ]; this.data = [ { instances: '1', - title: 'foo' + title: 'foo', + unsortable: '14' }, { instances: '3', - title: 'sup' + title: 'sup', + unsortable: '22' }, { title: 'yee', - instances: '2' + instances: '2', + unsortable: '1' } ]; @@ -42,68 +52,103 @@ describe('TableSortable', function() { }), this.node ); + + this.$table = $('#container table.table-sortable'); }); afterEach(function() { React.unmountComponentAtNode(this.node); }); + it('adds the class "sortable" on all sortable columns', function() { + expect(this.$table.find('th:contains("Title")')).toHaveClass('sortable'); + expect(this.$table.find('th:contains("Instances")')).toHaveClass('sortable'); + expect(this.$table.find('th:contains("Unsortable")')).not.toHaveClass('sortable'); + }); + it('sorts table rows by the first column in ascending order by default', function() { - expect($('th:contains("Title")')).toHaveClass('sorted-asc'); - expect($('td').eq(0)).toContainText('foo'); - expect($('td').eq(1)).toContainText('1'); - expect($('td').eq(2)).toContainText('sup'); - expect($('td').eq(3)).toContainText('3'); - expect($('td').eq(4)).toContainText('yee'); - expect($('td').eq(5)).toContainText('2'); + expect(this.$table.find('th:contains("Title")')).toHaveClass('sorted-asc'); + + expect(this.$table.find('tbody tr:nth-of-type(1) > td').eq(0)).toContainText('foo'); + expect(this.$table.find('tbody tr:nth-of-type(2) > td').eq(0)).toContainText('sup'); + expect(this.$table.find('tbody tr:nth-of-type(3) > td').eq(0)).toContainText('yee'); + + expect(this.$table.find('tbody tr:nth-of-type(1) > td').eq(1)).toContainText('1'); + expect(this.$table.find('tbody tr:nth-of-type(2) > td').eq(1)).toContainText('3'); + expect(this.$table.find('tbody tr:nth-of-type(3) > td').eq(1)).toContainText('2'); }); describe('clicking on the already asc-sorted column', function() { beforeEach(function() { - TestUtils.Simulate.click($("th:contains('Title')").get(0)); + TestUtils.Simulate.click(this.$table.find('th:contains("Title")').get(0)); }); it('reverses the sort order', function() { - expect($('th:contains("Title")')).toHaveClass('sorted-desc'); - expect($('td').eq(0)).toContainText('yee'); - expect($('td').eq(1)).toContainText('2'); - expect($('td').eq(2)).toContainText('sup'); - expect($('td').eq(3)).toContainText('3'); - expect($('td').eq(4)).toContainText('foo'); - expect($('td').eq(5)).toContainText('1'); + expect(this.$table.find('th:contains("Title")')).toHaveClass('sorted-desc'); + + expect(this.$table.find('tbody tr:nth-of-type(1) > td').eq(0)).toContainText('yee'); + expect(this.$table.find('tbody tr:nth-of-type(2) > td').eq(0)).toContainText('sup'); + expect(this.$table.find('tbody tr:nth-of-type(3) > td').eq(0)).toContainText('foo'); + + expect(this.$table.find('tbody tr:nth-of-type(1) > td').eq(1)).toContainText('2'); + expect(this.$table.find('tbody tr:nth-of-type(2) > td').eq(1)).toContainText('3'); + expect(this.$table.find('tbody tr:nth-of-type(3) > td').eq(1)).toContainText('1'); }); describe('clicking on the already desc-sorted column', function() { beforeEach(function() { - TestUtils.Simulate.click($("th:contains('Title')").get(0)); + TestUtils.Simulate.click(this.$table.find('th:contains("Title")').get(0)); }); it('reverses the sort order', function() { - expect($('th:contains("Title")')).toHaveClass('sorted-asc'); - expect($('td').eq(0)).toContainText('foo'); - expect($('td').eq(1)).toContainText('1'); - expect($('td').eq(2)).toContainText('sup'); - expect($('td').eq(3)).toContainText('3'); - expect($('td').eq(4)).toContainText('yee'); - expect($('td').eq(5)).toContainText('2'); + expect(this.$table.find('th:contains("Title")')).toHaveClass('sorted-asc'); + + expect(this.$table.find('tbody tr:nth-of-type(1) > td').eq(0)).toContainText('foo'); + expect(this.$table.find('tbody tr:nth-of-type(2) > td').eq(0)).toContainText('sup'); + expect(this.$table.find('tbody tr:nth-of-type(3) > td').eq(0)).toContainText('yee'); + + expect(this.$table.find('tbody tr:nth-of-type(1) > td').eq(1)).toContainText('1'); + expect(this.$table.find('tbody tr:nth-of-type(2) > td').eq(1)).toContainText('3'); + expect(this.$table.find('tbody tr:nth-of-type(3) > td').eq(1)).toContainText('2'); }); }); }); - describe('clicking on the instances column', function() { + describe('clicking on a sortable column', function() { beforeEach(function() { - TestUtils.Simulate.click($("th:contains('Instances')").get(0)); + TestUtils.Simulate.click(this.$table.find('th:contains("Instances")').get(0)); }); - it('sorts table rows by asc-instances', function() { - expect($('th:contains("Instances")')).toHaveClass('sorted-asc'); - expect($('th:contains("Title")')).not.toHaveClass('sorted-asc'); - expect($('td').eq(0)).toContainText('foo'); - expect($('td').eq(1)).toContainText('1'); - expect($('td').eq(2)).toContainText('yee'); - expect($('td').eq(3)).toContainText('2'); - expect($('td').eq(4)).toContainText('sup'); - expect($('td').eq(5)).toContainText('3'); + it('sorts table rows by that column', function() { + expect(this.$table.find('th:contains("Instances")')).toHaveClass('sorted-asc'); + expect(this.$table.find('th:contains("Title")')).not.toHaveClass('sorted-asc'); + + expect(this.$table.find('tbody tr:nth-of-type(1) > td').eq(0)).toContainText('foo'); + expect(this.$table.find('tbody tr:nth-of-type(2) > td').eq(0)).toContainText('yee'); + expect(this.$table.find('tbody tr:nth-of-type(3) > td').eq(0)).toContainText('sup'); + + expect(this.$table.find('tbody tr:nth-of-type(1) > td').eq(1)).toContainText('1'); + expect(this.$table.find('tbody tr:nth-of-type(2) > td').eq(1)).toContainText('2'); + expect(this.$table.find('tbody tr:nth-of-type(3) > td').eq(1)).toContainText('3'); + }); + }); + + describe('clicking on a non-sortable column', function() { + beforeEach(function() { + TestUtils.Simulate.click(this.$table.find('th:contains("Unsortable")').get(0)); + }); + + it('does not change the sort', function() { + expect(this.$table.find('th:contains("Unsortable")')).not.toHaveClass('sorted-asc'); + expect(this.$table.find('th:contains("Title")')).toHaveClass('sorted-asc'); + + expect(this.$table.find('tbody tr:nth-of-type(1) > td').eq(0)).toContainText('foo'); + expect(this.$table.find('tbody tr:nth-of-type(2) > td').eq(0)).toContainText('sup'); + expect(this.$table.find('tbody tr:nth-of-type(3) > td').eq(0)).toContainText('yee'); + + expect(this.$table.find('tbody tr:nth-of-type(1) > td').eq(1)).toContainText('1'); + expect(this.$table.find('tbody tr:nth-of-type(2) > td').eq(1)).toContainText('3'); + expect(this.$table.find('tbody tr:nth-of-type(3) > td').eq(1)).toContainText('2'); }); }); });