mirror of
https://github.com/Mottie/tablesorter.git
synced 2025-01-12 15:24:21 +00:00
Improve accessibility & add unsorted header class
This commit is contained in:
parent
3256926f29
commit
0e438e4bbd
@ -115,10 +115,12 @@
|
||||
r = 'removeClass',
|
||||
d = p.cssDisabled,
|
||||
dis = !!disable,
|
||||
first = ( dis || p.page === 0 ),
|
||||
last = ( dis || p.page === tp - 1 || p.totalPages === 0 ),
|
||||
tp = Math.min( p.totalPages, p.filteredPages );
|
||||
if ( p.updateArrows ) {
|
||||
p.$container.find(p.cssFirst + ',' + p.cssPrev)[ ( dis || p.page === 0 ) ? a : r ](d);
|
||||
p.$container.find(p.cssNext + ',' + p.cssLast)[ ( dis || p.page === tp - 1 || p.totalPages === 0 ) ? a : r ](d);
|
||||
p.$container.find(p.cssFirst + ',' + p.cssPrev)[ first ? a : r ](d).attr('aria-disabled', first);
|
||||
p.$container.find(p.cssNext + ',' + p.cssLast)[ last ? a : r ](d).attr('aria-disabled', last);
|
||||
}
|
||||
},
|
||||
|
||||
@ -251,7 +253,8 @@
|
||||
if (c.debug) {
|
||||
ts.log('Ajax Error', xhr, exception);
|
||||
}
|
||||
$err = $('<tr class="' + p.cssErrorRow + '"><td style="text-align:center;" colspan="' + hl + '">' + (
|
||||
$err = $('<tr class="' + p.cssErrorRow + '" role="alert" aria-live="assertive">' +
|
||||
'<td style="text-align:center;" colspan="' + hl + '">' + (
|
||||
xhr.status === 0 ? 'Not connected, verify Network' :
|
||||
xhr.status === 404 ? 'Requested page not found [404]' :
|
||||
xhr.status === 500 ? 'Internal Server Error [500]' :
|
||||
@ -470,7 +473,10 @@
|
||||
p.page = 0;
|
||||
p.size = p.totalRows;
|
||||
p.totalPages = 1;
|
||||
$(table).addClass('pagerDisabled').find('tr.pagerSavedHeightSpacer').remove();
|
||||
$(table)
|
||||
.addClass('pagerDisabled')
|
||||
.removeAttr('aria-describedby')
|
||||
.find('tr.pagerSavedHeightSpacer').remove();
|
||||
renderTable(table, table.config.rowsCopy, p);
|
||||
if (table.config.debug) {
|
||||
ts.log('pager disabled');
|
||||
@ -478,7 +484,7 @@
|
||||
}
|
||||
// disable size selector
|
||||
p.$size.add(p.$goto).each(function(){
|
||||
$(this).addClass(p.cssDisabled)[0].disabled = true;
|
||||
$(this).attr('aria-disabled', 'true').addClass(p.cssDisabled)[0].disabled = true;
|
||||
});
|
||||
},
|
||||
|
||||
@ -568,7 +574,7 @@
|
||||
p.$size.add(p.$goto).removeClass(p.cssDisabled).removeAttr('disabled').attr('aria-disabled', 'false');
|
||||
p.isDisabled = false;
|
||||
p.page = $.data(table, 'pagerLastPage') || p.page || 0;
|
||||
p.size = $.data(table, 'pagerLastSize') || parseInt(pg.find('option[selected]').val(), 10) || p.size || 10;
|
||||
p.size = $.data(table, 'pagerLastSize') || parseInt(p.$size.find('option[selected]').val(), 10) || p.size || 10;
|
||||
p.$size.val(p.size); // set page size
|
||||
p.totalPages = Math.ceil( Math.min( p.totalRows, p.filteredRows ) / p.size );
|
||||
// if table id exists, include page display with aria info
|
||||
@ -678,6 +684,7 @@
|
||||
ctrls = [ p.cssFirst, p.cssPrev, p.cssNext, p.cssLast ];
|
||||
fxn = [ moveToFirstPage, moveToPrevPage, moveToNextPage, moveToLastPage ];
|
||||
pager.find(ctrls.join(','))
|
||||
.attr("tabindex", 0)
|
||||
.unbind('click.pager')
|
||||
.bind('click.pager', function(e){
|
||||
e.stopPropagation();
|
||||
|
@ -82,6 +82,7 @@
|
||||
tableClass : '',
|
||||
cssAsc : '',
|
||||
cssDesc : '',
|
||||
cssNone : '',
|
||||
cssHeader : '',
|
||||
cssHeaderRow : '',
|
||||
cssProcessing : '', // processing icon applied to header during sort/filter
|
||||
@ -120,7 +121,18 @@
|
||||
info : 'tablesorter-infoOnly',
|
||||
processing : 'tablesorter-processing',
|
||||
sortAsc : 'tablesorter-headerAsc',
|
||||
sortDesc : 'tablesorter-headerDesc'
|
||||
sortDesc : 'tablesorter-headerDesc',
|
||||
sortNone : 'tablesorter-headerUnSorted'
|
||||
};
|
||||
|
||||
// labels applied to sortable headers for accessibility (aria) support
|
||||
ts.language = {
|
||||
sortAsc : 'Ascending sort applied, ',
|
||||
sortDesc : 'Descending sort applied, ',
|
||||
sortNone : 'No sort applied, ',
|
||||
nextAsc : 'activate to apply an ascending sort',
|
||||
nextDesc : 'activate to apply a descending sort',
|
||||
nextNone : 'activate to remove the sort'
|
||||
};
|
||||
|
||||
/* debuging utils */
|
||||
@ -443,9 +455,12 @@
|
||||
// add cell to headerList
|
||||
c.headerList[index] = this;
|
||||
// add to parent in case there are multiple rows
|
||||
$t.parent().addClass(ts.css.headerRow + ' ' + c.cssHeaderRow);
|
||||
$t.parent().addClass(ts.css.headerRow + ' ' + c.cssHeaderRow).attr('role', 'row');
|
||||
// allow keyboard cursor to focus on element
|
||||
if (c.tabIndex) { $t.attr("tabindex", 0); }
|
||||
}).attr({
|
||||
scope: 'col',
|
||||
role : 'columnheader'
|
||||
});
|
||||
// enable/disable sorting
|
||||
updateHeader(table);
|
||||
@ -467,11 +482,20 @@
|
||||
}
|
||||
|
||||
function updateHeader(table) {
|
||||
var s, c = table.config;
|
||||
var s, $th, c = table.config;
|
||||
c.$headers.each(function(index, th){
|
||||
$th = $(th);
|
||||
s = ts.getData( th, c.headers[index], 'sorter' ) === 'false';
|
||||
th.sortDisabled = s;
|
||||
$(th)[ s ? 'addClass' : 'removeClass' ]('sorter-false');
|
||||
$th[ s ? 'addClass' : 'removeClass' ]('sorter-false').attr('aria-disabled', '' + s);
|
||||
// aria-controls - requires table ID
|
||||
if (table.id) {
|
||||
if (s) {
|
||||
$th.removeAttr('aria-controls');
|
||||
} else {
|
||||
$th.attr('aria-controls', table.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -479,11 +503,15 @@
|
||||
var f, i, j, l,
|
||||
c = table.config,
|
||||
list = c.sortList,
|
||||
none = ts.css.sortNone + ' ' + c.cssNone,
|
||||
css = [ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc],
|
||||
aria = ['ascending', 'descending'],
|
||||
// find the footer
|
||||
$t = $(table).find('tfoot tr').children().removeClass(css.join(' '));
|
||||
// remove all header information
|
||||
c.$headers.removeClass(css.join(' '));
|
||||
c.$headers
|
||||
.removeClass(css.join(' '))
|
||||
.addClass(none).attr('aria-sort', 'none');
|
||||
l = list.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
// direction = 2 means reset!
|
||||
@ -493,7 +521,7 @@
|
||||
if (f.length) {
|
||||
for (j = 0; j < f.length; j++) {
|
||||
if (!f[j].sortDisabled) {
|
||||
f.eq(j).addClass(css[list[i][1]]);
|
||||
f.eq(j).removeClass(none).addClass(css[list[i][1]]).attr('aria-sort', aria[list[i][1]]);
|
||||
// add sorted class to footer, if it exists
|
||||
if ($t.length) {
|
||||
$t.filter('[data-column="' + list[i][0] + '"]').eq(j).addClass(css[list[i][1]]);
|
||||
@ -503,6 +531,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
// add verbose aria labels
|
||||
c.$headers.not('.sorter-false').each(function(){
|
||||
var $this = $(this),
|
||||
nextSort = this.order[(this.count + 1) % (c.sortReset ? 3 : 2)],
|
||||
txt = $this.text() + ': ' +
|
||||
ts.language[ $this.hasClass(ts.css.sortAsc) ? 'sortAsc' : $this.hasClass(ts.css.sortDesc) ? 'sortDesc' : 'sortNone' ] +
|
||||
ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ];
|
||||
$this.attr('aria-label', txt );
|
||||
});
|
||||
}
|
||||
|
||||
// automatically add col group, and column sizes if set
|
||||
@ -901,8 +938,17 @@
|
||||
if (!/tablesorter\-/.test($table.attr('class'))) {
|
||||
k = (c.theme !== '' ? ' tablesorter-' + c.theme : '');
|
||||
}
|
||||
c.$table = $table.addClass(ts.css.table + ' ' + c.tableClass + k);
|
||||
c.$tbodies = $table.children('tbody:not(.' + c.cssInfoBlock + ')');
|
||||
c.$table = $table
|
||||
.addClass(ts.css.table + ' ' + c.tableClass + k)
|
||||
.attr({ role : 'grid'});
|
||||
c.$tbodies = $table.children('tbody:not(.' + c.cssInfoBlock + ')').attr({
|
||||
'aria-live' : 'polite',
|
||||
'aria-relevant' : 'all'
|
||||
});
|
||||
//
|
||||
if (c.$table.find('caption').length) {
|
||||
c.$table.attr('aria-labelledby', 'theCaption');
|
||||
}
|
||||
c.widgetInit = {}; // keep a list of initialized widgets
|
||||
// build headers
|
||||
buildHeaders(table);
|
||||
@ -929,9 +975,12 @@
|
||||
// if user has supplied a sort list to constructor
|
||||
if (c.sortList.length > 0) {
|
||||
$table.trigger("sorton", [c.sortList, {}, !c.initWidgets]);
|
||||
} else if (c.initWidgets) {
|
||||
// apply widget format
|
||||
ts.applyWidget(table);
|
||||
} else {
|
||||
setHeadersCss(table);
|
||||
if (c.initWidgets) {
|
||||
// apply widget format
|
||||
ts.applyWidget(table);
|
||||
}
|
||||
}
|
||||
|
||||
// show processesing icon
|
||||
|
@ -251,6 +251,7 @@ tsp = ts.pager = {
|
||||
ctrls = [ s.first, s.prev, s.next, s.last ];
|
||||
fxn = [ 'moveToFirstPage', 'moveToPrevPage', 'moveToNextPage', 'moveToLastPage' ];
|
||||
p.$container.find(ctrls.join(','))
|
||||
.attr("tabindex", 0)
|
||||
.unbind('click.pager')
|
||||
.bind('click.pager', function(e){
|
||||
e.stopPropagation();
|
||||
@ -296,12 +297,14 @@ tsp = ts.pager = {
|
||||
pagerArrows: function(c, disable) {
|
||||
var p = c.pager,
|
||||
dis = !!disable,
|
||||
first = dis || p.page === 0,
|
||||
last = dis || p.page === tp - 1 || p.totalPages === 0,
|
||||
wo = c.widgetOptions,
|
||||
s = wo.pager_selectors,
|
||||
tp = Math.min( p.totalPages, p.filteredPages );
|
||||
if ( wo.pager_updateArrows ) {
|
||||
p.$container.find(s.first + ',' + s.prev).toggleClass(wo.pager_css.disabled, dis || p.page === 0);
|
||||
p.$container.find(s.next + ',' + s.last).toggleClass(wo.pager_css.disabled, dis || p.page === tp - 1 || p.totalPages === 0);
|
||||
p.$container.find(s.first + ',' + s.prev).toggleClass(wo.pager_css.disabled, first).attr('aria-disabled', first);
|
||||
p.$container.find(s.next + ',' + s.last).toggleClass(wo.pager_css.disabled, last).attr('aria-disabled', last);
|
||||
}
|
||||
},
|
||||
|
||||
@ -313,7 +316,7 @@ tsp = ts.pager = {
|
||||
t = (c.widgetOptions && c.widgetOptions.filter_filteredRow || 'filtered') + ',' + c.selectorRemove +
|
||||
(wo.pager_countChildRows ? '' : ',.' + c.cssChildRow),
|
||||
sz = p.size || 10; // don't allow dividing by zero
|
||||
p.$size.add(p.$goto).removeClass(wo.pager_css.disabled).removeAttr('disabled');
|
||||
p.$size.add(p.$goto).removeClass(wo.pager_css.disabled).removeAttr('disabled').attr('aria-disabled', 'false');
|
||||
p.totalPages = Math.ceil( p.totalRows / sz ); // needed for "pageSize" method
|
||||
p.filteredRows = (f) ? c.$tbodies.eq(0).children('tr').not('.' + t).length : p.totalRows;
|
||||
p.filteredPages = (f) ? Math.ceil( p.filteredRows / sz ) || 1 : p.totalPages;
|
||||
@ -440,7 +443,8 @@ tsp = ts.pager = {
|
||||
if (c.debug) {
|
||||
ts.log('Ajax Error', xhr, exception);
|
||||
}
|
||||
$err = $('<tr class="' + wo.pager_css.errorRow + '"><td style="text-align:center;" colspan="' +
|
||||
$err = $('<tr class="' + wo.pager_css.errorRow + '" role="alert" aria-live="assertive">' +
|
||||
'<td style="text-align:center;" colspan="' +
|
||||
hl + '">' + exception.message + ' (' + xhr.status + ')</td></tr>')
|
||||
.click(function(){
|
||||
$(this).remove();
|
||||
@ -662,7 +666,10 @@ tsp = ts.pager = {
|
||||
p.page = 0;
|
||||
p.size = p.totalRows;
|
||||
p.totalPages = 1;
|
||||
c.$table.addClass('pagerDisabled').find('tr.pagerSavedHeightSpacer').remove();
|
||||
c.$table
|
||||
.addClass('pagerDisabled')
|
||||
.removeAttr('aria-describedby')
|
||||
.find('tr.pagerSavedHeightSpacer').remove();
|
||||
tsp.renderTable(table, c.rowsCopy);
|
||||
if (c.debug) {
|
||||
ts.log('pager disabled');
|
||||
@ -670,7 +677,7 @@ tsp = ts.pager = {
|
||||
}
|
||||
// disable size selector
|
||||
p.$size.add(p.$goto).each(function(){
|
||||
$(this).addClass(wo.pager_css.disabled)[0].disabled = true;
|
||||
$(this).attr('aria-disabled', 'true').addClass(wo.pager_css.disabled)[0].disabled = true;
|
||||
});
|
||||
c.$table.trigger('applyWidgets');
|
||||
},
|
||||
@ -758,13 +765,19 @@ tsp = ts.pager = {
|
||||
},
|
||||
|
||||
enablePager: function(table, c, triggered){
|
||||
var p = c.pager;
|
||||
var info, p = c.pager;
|
||||
p.isDisabled = false;
|
||||
p.page = $.data(table, 'pagerLastPage') || p.page || 0;
|
||||
p.size = $.data(table, 'pagerLastSize') || parseInt(p.$size.find('option[selected]').val(), 10) || p.size || 10;
|
||||
p.$size.val(p.size); // set page size
|
||||
p.totalPages = Math.ceil( Math.min( p.totalRows, p.filteredRows ) / p.size );
|
||||
c.$table.removeClass('pagerDisabled');
|
||||
// if table id exists, include page display with aria info
|
||||
if ( table.id ) {
|
||||
info = table.id + '_pager_info';
|
||||
p.$container.find(wo.pager_selectors.pageDisplay).attr('id', info);
|
||||
c.$table.attr('aria-describedby', info);
|
||||
}
|
||||
if ( triggered ) {
|
||||
c.$table.trigger('updateRows');
|
||||
tsp.setPageSize(table, p.size, c);
|
||||
|
Loading…
Reference in New Issue
Block a user