Skip to content
This repository has been archived by the owner on Apr 2, 2019. It is now read-only.

Add accessibility features as noted in Feature Request #612. #626

Merged
merged 1 commit into from
Jun 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions lib/backgrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -2077,7 +2077,7 @@ var HeaderCell = Backgrid.HeaderCell = Backbone.View.extend({

/** @property */
events: {
"click a": "onClick"
"click button": "onClick"
},

/**
Expand Down Expand Up @@ -2176,7 +2176,7 @@ var HeaderCell = Backgrid.HeaderCell = Backbone.View.extend({
var sortable = Backgrid.callByNeed(column.sortable(), column, this.collection);
var label;
if(sortable){
label = $("<a>").text(column.get("label")).append("<b class='sort-caret'></b>");
label = $("<button>").text(column.get("label")).append("<span class='sort-caret' aria-hidden='true'></span>");
} else {
label = document.createTextNode(column.get("label"));
}
Expand Down Expand Up @@ -2819,6 +2819,8 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
options.columns = new Columns(options.columns || this.columns);
}
this.columns = options.columns;

this.caption = options.caption;

var filteredOptions = _.omit(options, ["el", "id", "attributes",
"className", "tagName", "events"]);
Expand Down Expand Up @@ -2904,6 +2906,10 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
*/
render: function () {
this.$el.empty();

if (this.caption) {
this.$el.append($("<caption>").text(this.caption));
}

if (this.header) {
this.$el.append(this.header.render().$el);
Expand Down
5 changes: 4 additions & 1 deletion src/backgrid.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,11 @@
background-color: #f9f9f9;
}

.backgrid thead th a {
.backgrid thead th button {
display: block;
border: none;
background: none;
padding: 0;
}

.backgrid.backgrid-striped tbody tr:nth-child(even) {
Expand Down
9 changes: 8 additions & 1 deletion src/grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
@param {Object} options
@param {Backbone.Collection.<Backgrid.Columns>|Array.<Backgrid.Column>|Array.<Object>} options.columns Column metadata.
@param {Backbone.Collection} options.collection The collection of tabular model data to display.
@param {string} [options.caption=string] An optional caption to be added to the table.
@param {Backgrid.Header} [options.header=Backgrid.Header] An optional Header class to override the default.
@param {Backgrid.Body} [options.body=Backgrid.Body] An optional Body class to override the default.
@param {Backgrid.Row} [options.row=Backgrid.Row] An optional Row class to override the default.
Expand All @@ -88,6 +89,8 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
options.columns = new Columns(options.columns || this.columns);
}
this.columns = options.columns;

this.caption = options.caption;

var filteredOptions = _.omit(options, ["el", "id", "attributes",
"className", "tagName", "events"]);
Expand Down Expand Up @@ -167,12 +170,16 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
},

/**
Renders the grid's header, then footer, then finally the body. Triggers a
Renders the grid's caption, then header, then footer, then finally the body. Triggers a
Backbone `backgrid:rendered` event along with a reference to the grid when
the it has successfully been rendered.
*/
render: function () {
this.$el.empty();

if (this.caption) {
this.$el.append($("<caption>").text(this.caption));
}

if (this.header) {
this.$el.append(this.header.render().$el);
Expand Down
4 changes: 2 additions & 2 deletions src/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var HeaderCell = Backgrid.HeaderCell = Backbone.View.extend({

/** @property */
events: {
"click a": "onClick"
"click button": "onClick"
},

/**
Expand Down Expand Up @@ -120,7 +120,7 @@ var HeaderCell = Backgrid.HeaderCell = Backbone.View.extend({
var sortable = Backgrid.callByNeed(column.sortable(), column, this.collection);
var label;
if(sortable){
label = $("<a>").text(column.get("label")).append("<b class='sort-caret'></b>");
label = $("<button>").text(column.get("label")).append("<span class='sort-caret' aria-hidden='true'></span>");
} else {
label = document.createTextNode(column.get("label"));
}
Expand Down
21 changes: 19 additions & 2 deletions test/grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,23 @@ describe("A Grid", function () {
expect(grid.body.rows[0].className).not.toBe("class-name");
expect(grid.footer.className).not.toBe("class-name");
});

it("will render a table with a caption element", function () {
var caption = "Table of data"
grid = new Backgrid.Grid({
columns: [{
name: "title",
cell: "string"
}],
collection: books,
caption: caption,
});

grid.render();

expect($(grid.el).find("caption"));
expect($(grid.el).find("caption").text()).toBe(caption);
});

it("will clean up all its decendant views when remove is called", function () {
expect(grid.remove().constructor).toBe(Backgrid.Grid);
Expand Down Expand Up @@ -122,8 +139,8 @@ describe("A Grid", function () {
var thead = grid.el.childNodes[0];
expect(thead.tagName == "THEAD").toBe(true);
expect($(thead).find("tr").length).toBe(1);
expect($(thead).find("tr > th.editable.sortable.renderable.id > a > b.sort-caret").length).toBe(1);
expect($(thead).find("tr > th.editable.sortable.renderable.id > a").text()).toBe("id");
expect($(thead).find("tr > th.editable.sortable.renderable.id > button > span.sort-caret").length).toBe(1);
expect($(thead).find("tr > th.editable.sortable.renderable.id > button").text()).toBe("id");

var tfoot = grid.el.childNodes[1];
expect(tfoot.tagName == "TFOOT").toBe(true);
Expand Down
55 changes: 28 additions & 27 deletions test/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ describe("A HeaderCell", function () {

it("renders a table header cell with the label text and an optional anchor with sort-caret", function () {
expect(cell.el.tagName).toBe("TH");
expect(cell.$el.find("a").text()).toBe("id");
expect(cell.$el.find("button").text()).toBe("id");
expect(cell.$el.find(".sort-caret").length).toBe(1);
expect(cell.$el.find(".sort-caret").attr("aria-hidden")).toEqual("true");

cell.column.set("sortable", false);
cell.render();
Expand Down Expand Up @@ -124,15 +125,15 @@ describe("A HeaderCell", function () {
});

it("will rerender with the column name and/or label changes", function () {
expect(cell.$el.find("a").text(), "id");
expect(cell.$el.find("button").text(), "id");
expect(cell.$el.hasClass("id"), true);

cell.column.set("name", "name");
expect(cell.$el.find("name"), true);
expect(cell.$el.hasClass("name"), true);

cell.column.set("label", "Name");
expect(cell.$el.find("a").text(), "Name");
expect(cell.$el.find("button").text(), "Name");
expect(cell.$el.hasClass("Name"), true);
});

Expand All @@ -149,15 +150,15 @@ describe("A HeaderCell", function () {
cell.render();

expect(cell.el.tagName).toBe("TH");
expect(cell.$el.find("a").text()).toBe("id");
expect(cell.$el.find("button").text()).toBe("id");
expect(cell.$el.find(".sort-caret").length).toBe(1);
expect(cell.$el.hasClass("descending")).toBe(true);
});

it("triggers `backgrid:sort` with the column and direction set to 'ascending' if the column's direction is not set", function () {
var column, direction;
cell.collection.on("backgrid:sort", function (col, dir) { column = col; direction = dir; });
cell.$el.find("a").click();
cell.$el.find("button").click();
expect(column).toBe(cell.column);
expect(direction).toBe("ascending");
});
Expand All @@ -166,7 +167,7 @@ describe("A HeaderCell", function () {
var column, direction;
cell.collection.on("backgrid:sort", function (col, dir) { column = col; direction = dir; });
cell.column.set("direction", "ascending");
cell.$el.find("a").click();
cell.$el.find("button").click();
expect(column).toBe(cell.column);
expect(direction).toBe("descending");
});
Expand All @@ -175,7 +176,7 @@ describe("A HeaderCell", function () {
var column, direction;
cell.collection.on("backgrid:sort", function (col, dir) { column = col; direction = dir; });
cell.column.set("direction", "descending");
cell.$el.find("a").click();
cell.$el.find("button").click();
expect(column).toBe(cell.column);
expect(direction).toBeNull();
});
Expand Down Expand Up @@ -224,7 +225,7 @@ describe("A HeaderCell", function () {
var column, direction;
cell.column.set("sortType", "toggle");
cell.collection.on("backgrid:sort", function (col, dir) { column = col; direction = dir; });
cell.$el.find("a").click();
cell.$el.find("button").click();
expect(column).toBe(cell.column);
expect(direction).toBe("ascending");
});
Expand All @@ -234,7 +235,7 @@ describe("A HeaderCell", function () {
cell.column.set("sortType", "toggle");
cell.column.set("direction", "ascending");
cell.collection.on("backgrid:sort", function (col, dir) { column = col; direction = dir; });
cell.$el.find("a").click();
cell.$el.find("button").click();
expect(column).toBe(cell.column);
expect(direction).toBe("descending");
});
Expand All @@ -244,7 +245,7 @@ describe("A HeaderCell", function () {
cell.column.set("sortType", "toggle");
cell.column.set("direction", "descending");
cell.collection.on("backgrid:sort", function (col, dir) { column = col; direction = dir; });
cell.$el.find("a").click();
cell.$el.find("button").click();
expect(column).toBe(cell.column);
expect(direction).toBe("ascending");
});
Expand Down Expand Up @@ -296,23 +297,23 @@ describe("A HeaderRow", function () {
expect(th1.hasClass("sortable")).toBe(true);
expect(th1.hasClass("renderable")).toBe(true);
expect(th1.hasClass("name")).toBe(true);
expect(th1.find("a").text()).toBe("name");
expect(th1.find("a").eq(1).is($("b", {className: "sort-caret"})));
expect(th1.find("button").text()).toBe("name");
expect(th1.find("button").eq(1).is($("b", {className: "sort-caret"})));

var th2 = $(row.el.childNodes[1]);
expect(th2.hasClass("editable")).toBe(true);
expect(th2.hasClass("sortable")).toBe(true);
expect(th2.hasClass("renderable")).toBe(true);
expect(th2.hasClass("year")).toBe(true);
expect(th2.find("a").text()).toBe("year");
expect(th2.find("a > b:last-child").eq(0).hasClass("sort-caret")).toBe(true);
expect(th2.find("button").text()).toBe("year");
expect(th2.find("button > span:last-child").eq(0).hasClass("sort-caret")).toBe(true);
});

it("resets the carets of the non-sorting columns", function () {
row.$el.find("a").eq(0).click(); // ascending
row.$el.find("a").eq(1).click(); // ascending, resets the previous
expect(row.$el.find("a").eq(0).hasClass("ascending")).toBe(false);
expect(row.$el.find("a").eq(1).hasClass("ascending")).toBe(false);
row.$el.find("button").eq(0).click(); // ascending
row.$el.find("button").eq(1).click(); // ascending, resets the previous
expect(row.$el.find("button").eq(0).hasClass("ascending")).toBe(false);
expect(row.$el.find("button").eq(1).hasClass("ascending")).toBe(false);
});

it("inserts or removes a cell if a column is added or removed", function () {
Expand All @@ -323,12 +324,12 @@ describe("A HeaderRow", function () {
expect(lastTh.hasClass("sortable")).toBe(true);
expect(lastTh.hasClass("renderable")).toBe(true);
expect(lastTh.hasClass("price")).toBe(true);
expect(lastTh.find("a").text()).toBe("price");
expect(lastTh.find("a > b:last-child").eq(0).hasClass("sort-caret")).toBe(true);
expect(lastTh.find("button").text()).toBe("price");
expect(lastTh.find("button > span:last-child").eq(0).hasClass("sort-caret")).toBe(true);

row.columns.add({name: "publisher", cell: "string", renderable: false});
expect(row.$el.children().length).toBe(4);
expect(row.$el.children().last().find("a").text()).toBe("publisher");
expect(row.$el.children().last().find("button").text()).toBe("publisher");
expect(row.$el.children().last().hasClass("renderable")).toBe(false);

row.columns.remove(row.columns.first());
Expand All @@ -338,8 +339,8 @@ describe("A HeaderRow", function () {
expect(firstTh.hasClass("sortable")).toBe(true);
expect(firstTh.hasClass("renderable")).toBe(true);
expect(firstTh.hasClass("year")).toBe(true);
expect(firstTh.find("a").text()).toBe("year");
expect(firstTh.find("a > b:last-child").eq(0).hasClass("sort-caret")).toBe(true);
expect(firstTh.find("button").text()).toBe("year");
expect(firstTh.find("button > span:last-child").eq(0).hasClass("sort-caret")).toBe(true);
});

});
Expand Down Expand Up @@ -390,16 +391,16 @@ describe("A Header", function () {
expect(th1.hasClass("sortable")).toBe(true);
expect(th1.hasClass("renderable")).toBe(true);
expect(th1.hasClass("name")).toBe(true);
expect(th1.find("a").text()).toBe("name");
expect(th1.find("a").eq(1).is($("b", {className: "sort-caret"})));
expect(th1.find("button").text()).toBe("name");
expect(th1.find("button").eq(1).is($("b", {className: "sort-caret"})));

var th2 = $(head.row.el.childNodes[1]);
expect(th2.hasClass("editable")).toBe(true);
expect(th2.hasClass("sortable")).toBe(true);
expect(th2.hasClass("renderable")).toBe(true);
expect(th2.hasClass("year")).toBe(true);
expect(th2.find("a").text()).toBe("year");
expect(th2.find("a > b:last-child").eq(0).hasClass("sort-caret")).toBe(true);
expect(th2.find("button").text()).toBe("year");
expect(th2.find("button > span:last-child").eq(0).hasClass("sort-caret")).toBe(true);
});

});