Core/widgets: update unbinding events to prevent removing all binds

This appears to be a jQuery bug when unbinding events in versions between 1.7 & 1.8 - see http://jsfiddle.net/Mottie/zL6uory0/
This commit is contained in:
Mottie 2015-02-09 15:59:15 -06:00
parent fec49e144a
commit 9993d77f38
9 changed files with 67 additions and 53 deletions

View File

@ -204,7 +204,7 @@
if ($out.length) {
$out[ ($out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
// rebind startRow/page inputs
$out.find('.ts-startRow, .ts-page').unbind('change').bind('change', function(){
$out.find('.ts-startRow, .ts-page').unbind('change.pager').bind('change.pager', function(){
var v = $(this).val(),
pg = $(this).hasClass('ts-startRow') ? Math.floor( v/p.size ) + 1 : v;
c.$table.trigger('pageSet.pager', [ pg ]);
@ -768,7 +768,7 @@
table.config.appender = null; // remove pager appender function
p.initialized = false;
delete table.config.rowsCopy;
$(table).unbind(pagerEvents.split(' ').join('.pager '));
$(table).unbind( $.trim(pagerEvents.split(' ').join('.pager ')) );
if (ts.storage) {
ts.storage(table, p.storageKey, '');
}
@ -848,7 +848,7 @@
p.regexRows = new RegExp('(' + (wo.filter_filteredRow || 'filtered') + '|' + c.selectorRemove.slice(1) + '|' + c.cssChildRow + ')');
$t
.unbind(pagerEvents.split(' ').join('.pager '))
.unbind( $.trim(pagerEvents.split(' ').join('.pager ')) )
.bind('filterInit.pager filterStart.pager', function(e, filters) {
p.currentFilters = $.isArray(filters) ? filters : c.$table.data('lastSearch');
// don't change page if filters are the same (pager updating, etc)
@ -945,8 +945,8 @@
p.$goto = pager.find(p.cssGoto);
if ( p.$goto.length ) {
p.$goto
.unbind('change')
.bind('change', function(){
.unbind('change.pager')
.bind('change.pager', function(){
p.page = $(this).val() - 1;
moveToPage(table, p, true);
updatePageDisplay(table, p, false);

View File

@ -851,12 +851,12 @@
function bindMethods(table){
var c = table.config,
$table = c.$table,
events = 'sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache' +
events = 'sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache ' +
'updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave '.split(' ')
.join(c.namespace + ' ');
// apply easy methods that trigger bound events
$table
.unbind( $.trim( events ) )
.unbind( $.trim(events) )
.bind('sortReset' + c.namespace, function(e, callback){
e.stopPropagation();
c.sortList = [];
@ -1330,8 +1330,8 @@
$headers
// http://stackoverflow.com/questions/5312849/jquery-find-self;
.find(c.selectorSort).add( $headers.filter(c.selectorSort) )
.unbind('mousedown mouseup sort keyup '.split(' ').join(c.namespace + ' '))
.bind('mousedown mouseup sort keyup '.split(' ').join(c.namespace + ' '), function(e, external) {
.unbind( $.trim('mousedown mouseup sort keyup '.split(' ').join(c.namespace + ' ')) )
.bind( $.trim('mousedown mouseup sort keyup '.split(' ').join(c.namespace + ' ')), function(e, external) {
var cell, type = e.type;
// only recognize left clicks or enter
if ( ((e.which || e.button) !== 1 && !/sort|keyup/.test(type)) || (type === 'keyup' && e.which !== 13) ) {
@ -1387,7 +1387,9 @@
if (!table.hasInitialized) { return; }
// remove all widgets
ts.removeWidget(table, true, false);
var $t = $(table), c = table.config,
var events,
$t = $(table),
c = table.config,
$h = $t.find('thead:first'),
$r = $h.find('tr.' + ts.css.headerRow).removeClass(ts.css.headerRow + ' ' + c.cssHeaderRow),
$f = $t.find('tfoot:first > tr').children('th, td');
@ -1399,15 +1401,18 @@
// remove widget added rows, just in case
$h.find('tr').not($r).remove();
// disable tablesorter
events = 'sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache ' +
'applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState '.split(' ')
.join(c.namespace + ' ');
$t
.removeData('tablesorter')
.unbind('sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState '.split(' ').join(c.namespace + ' '));
.unbind( $.trim(events) );
c.$headers.add($f)
.removeClass( [ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone].join(' ') )
.removeAttr('data-column')
.removeAttr('aria-label')
.attr('aria-disabled', 'true');
$r.find(c.selectorSort).unbind('mousedown mouseup keypress '.split(' ').join(c.namespace + ' '));
$r.find(c.selectorSort).unbind( $.trim('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')) );
ts.restoreHeaders(table);
$t.toggleClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false);
// clear flag in case the plugin is initialized again

View File

@ -429,11 +429,12 @@ ts.addWidget({
remove: function(table, c, wo, refreshing) {
var tbodyIndex, $tbody,
$table = c.$table,
$tbodies = c.$tbodies;
$tbodies = c.$tbodies,
events = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '.split(' ').join(c.namespace + 'filter ');
$table
.removeClass('hasFilters')
// add .tsfilter namespace to all BUT search
.unbind('addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '.split(' ').join(c.namespace + 'filter '))
.unbind( $.trim(events) )
// remove the filter row even if refreshing, because the column might have been moved
.find('.' + ts.css.filterRow).remove();
if (refreshing) { return; }
@ -660,7 +661,7 @@ ts.filter = {
}
txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '.split(' ').join(c.namespace + 'filter ');
c.$table.bind(txt, function(event, filter) {
c.$table.bind( $.trim(txt), function(event, filter) {
val = (wo.filter_hideEmpty && $.isEmptyObject(c.cache) && !(c.delayInit && event.type === 'appendCache'));
// hide filter row using the "filtered" class name
c.$table.find('.' + ts.css.filterRow).toggleClass(wo.filter_filteredRow, val ); // fixes #450
@ -752,7 +753,9 @@ ts.filter = {
// show processing icon
if (c.showProcessing) {
c.$table.bind('filterStart' + c.namespace + 'filter filterEnd' + c.namespace + 'filter', function(event, columns) {
c.$table
.unbind( $.trim('filterStart filterEnd '.split(' ').join(c.namespace + 'filter ')) )
.bind( $.trim('filterStart filterEnd '.split(' ').join(c.namespace + 'filter ')), function(event, columns) {
// only add processing to certain columns to all columns
$header = (columns) ? c.$table.find('.' + ts.css.header).filter('[data-column]').filter(function() {
return columns[$(this).data('column')] !== '';
@ -765,7 +768,9 @@ ts.filter = {
c.filteredRows = c.totalRows;
// add default values
c.$table.bind('tablesorter-initialized pagerBeforeInitialized', function() {
c.$table
.unbind( $.trim('tablesorter-initialized pagerBeforeInitialized '.split(' ').join(c.namespace + 'filter ')) )
.bind( $.trim('tablesorter-initialized pagerBeforeInitialized '.split(' ').join(c.namespace + 'filter ')), function() {
// redefine "wo" as it does not update properly inside this callback
var wo = this.config.widgetOptions;
filters = ts.filter.setDefaults(table, c, wo) || [];
@ -937,7 +942,7 @@ ts.filter = {
$el
// use data attribute instead of jQuery data since the head is cloned without including the data/binding
.attr('data-lastSearchTime', new Date().getTime())
.unbind('keypress keyup search change '.split(' ').join(c.namespace + 'filter '))
.unbind( $.trim('keypress keyup search change '.split(' ').join(c.namespace + 'filter ')) )
// include change for select - fixes #473
.bind('keyup' + c.namespace + 'filter', function(event) {
$(this).attr('data-lastSearchTime', new Date().getTime());
@ -958,7 +963,7 @@ ts.filter = {
// change event = no delay; last true flag tells getFilters to skip newest timed input
ts.filter.searching( table, true, true );
})
.bind('search change keypress '.split(' ').join(c.namespace + 'filter '), function(event){
.bind( $.trim('search change keypress '.split(' ').join(c.namespace + 'filter ')), function(event){
var column = $(this).data('column');
// don't allow "change" event to process if the input value is the same - fixes #685
if (event.which === 13 || event.type === 'search' || event.type === 'change' && this.value !== c.lastSearch[column]) {
@ -1772,7 +1777,7 @@ ts.addWidget({
// update sticky header class names to match real header after sorting
$table
.addClass('hasStickyHeaders')
.bind('pagerComplete' + namespace, function() {
.bind( $.trim('pagerComplete' + namespace), function() {
resizeHeader();
});
@ -1791,8 +1796,8 @@ ts.addWidget({
// make it sticky!
$xScroll.add($yScroll)
.unbind('scroll resize '.split(' ').join( namespace ) )
.bind('scroll resize '.split(' ').join( namespace ), function(event) {
.unbind( $.trim('scroll resize '.split(' ').join( namespace )) )
.bind( $.trim('scroll resize '.split(' ').join( namespace )), function(event) {
if (!$table.is(':visible')) { return; } // fixes #278
// Detect nested tables - fixes #724
nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
@ -1833,7 +1838,7 @@ ts.addWidget({
// look for filter widget
if ($table.hasClass('hasFilters') && wo.filter_columnFilters) {
// scroll table into view after filtering, if sticky header is active - #482
$table.bind('filterEnd' + namespace, function() {
$table.bind( $.trim('filterEnd' + namespace), function() {
// $(':focus') needs jQuery 1.6+
var $td = $(document.activeElement).closest('td'),
column = $td.parent().children().index($td);
@ -1861,14 +1866,14 @@ ts.addWidget({
var namespace = c.namespace + 'stickyheaders ';
c.$table
.removeClass('hasStickyHeaders')
.unbind( 'pagerComplete filterEnd '.split(' ').join(namespace) )
.unbind( $.trim('pagerComplete filterEnd '.split(' ').join(namespace)) )
.next('.' + ts.css.stickyWrap).remove();
if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table
$(window)
.add(wo.stickyHeaders_xScroll)
.add(wo.stickyHeaders_yScroll)
.add(wo.stickyHeaders_attachTo)
.unbind( 'scroll resize '.split(' ').join(namespace) );
.unbind( $.trim('scroll resize '.split(' ').join(namespace)) );
ts.addHeaderResizeEvent(table, false);
}
});

View File

@ -59,8 +59,8 @@
}
$win
.unbind('scroll resize '.split(' ').join(namespace))
.bind('scroll resize '.split(' ').join(namespace), function() {
.unbind( $.trim('scroll resize '.split(' ').join(namespace)) )
.bind( $.trim('scroll resize '.split(' ').join(namespace)), function() {
// make sure "wo" is current otherwise changes to widgetOptions
// are not dynamic (like the add caption button in the demo)
wo = c.widgetOptions;
@ -126,7 +126,7 @@
setTransform( $cells, finalY );
});
$table.unbind('filterEnd' + namespace).bind('filterEnd' + namespace, function() {
$table.unbind( $.trim('filterEnd' + namespace) ).bind( $.trim('filterEnd' + namespace), function() {
if (wo.cssStickyHeaders_filteredToTop) {
// scroll top of table into view
window.scrollTo(0, $table.position().top);
@ -137,9 +137,9 @@
remove: function(table, c, wo, refreshing) {
if (refreshing) { return; }
var namespace = c.namespace + 'cssstickyheader ';
$(window).unbind('scroll resize '.split(' ').join(namespace));
$(window).unbind( $.trim('scroll resize '.split(' ').join(namespace)) );
c.$table
.unbind('filterEnd scroll resize '.split(' ').join(namespace))
.unbind( $.trim('filterEnd scroll resize '.split(' ').join(namespace)) )
.add( c.$table.children('thead').children().children() )
.children('thead, caption').css({
'transform' : '',

View File

@ -95,13 +95,13 @@ var tse = $.tablesorter.editable = {
bindEvents: function( c, wo ) {
c.$table
.off( 'updateComplete pagerComplete '.split( ' ' ).join( '.tseditable' ) )
.on( 'updateComplete pagerComplete '.split( ' ' ).join( '.tseditable' ), function() {
.off( $.trim( 'updateComplete pagerComplete '.split( ' ' ).join( '.tseditable' ) ) )
.on( $.trim( 'updateComplete pagerComplete '.split( ' ' ).join( '.tseditable' ) ), function() {
tse.update( c, c.widgetOptions );
});
c.$tbodies
.off( 'mouseleave focus blur focusout keydown '.split( ' ' ).join( '.tseditable ' ) )
.off( $.trim( 'mouseleave focus blur focusout keydown '.split( ' ' ).join( '.tseditable ' ) ) )
.on( 'mouseleave.tseditable', function() {
if ( c.$table.data( 'contentFocused' ) ) {
// change to 'true' instead of element to allow focusout to process
@ -140,7 +140,7 @@ var tse = $.tablesorter.editable = {
}
}
})
.on( 'blur focusout keydown '.split( ' ' ).join( '.tseditable ' ), '[contenteditable]', function( e ) {
.on( $.trim( 'blur focusout keydown '.split( ' ' ).join( '.tseditable ' ) ), '[contenteditable]', function( e ) {
if ( !c.$table.data( 'contentFocused' ) ) { return; }
var t, validate,
valid = false,

View File

@ -10,9 +10,11 @@
ts.formatter = {
init : function( c ) {
var events = $.trim( c.widgetOptions.formatter_event ) + ' pagerComplete updateComplete '
.split(' ').join('.tsformatter ');
c.$table.on( events, function() {
var events = $.trim( c.widgetOptions.formatter_event ) +
' pagerComplete updateComplete '.split(' ').join('.tsformatter ');
c.$table
.off( $.trim(events) )
.on( $.trim(events), function() {
ts.formatter.setup( c );
});
ts.formatter.setup( c );

View File

@ -8,10 +8,12 @@
"use strict";
var ts = $.tablesorter,
events = $.trim( ( 'tablesorter-initialized update updateAll updateRows addRows updateCell ' +
'filterReset filterEnd recalculate ' ).split(' ').join('.tsmath ') ),
math = {
events : ( 'tablesorter-initialized update updateAll updateRows addRows updateCell ' +
'filterReset filterEnd recalculate ' ).split(' ').join('.tsmath '),
// get all of the row numerical values in an arry
getRow : function(table, wo, $el, dataAttrib) {
var $t, txt,
@ -390,8 +392,8 @@
},
init : function(table, thisWidget, c, wo){
c.$table
.off(events + ' updateComplete.tsmath')
.on(events, function(e){
.off( $.trim(math.events) + ' updateComplete.tsmath' )
.on( $.trim(math.events), function(e){
var init = e.type === 'tablesorter-initialized';
if (e.type === 'updateAll') {
// redo data-column indexes in case columns were rearranged
@ -412,7 +414,7 @@
remove: function(table, c, wo, refreshing){
if (refreshing) { return; }
$(table)
.off(events + ' updateComplete.tsmath')
.off( $trim(math.events) + ' updateComplete.tsmath' )
.find('[data-' + wo.math_data + ']').empty();
}
});

View File

@ -229,7 +229,7 @@ tsp = ts.pager = {
s = wo.pager_selectors;
c.$table
.off(p.events.split(' ').join('.pager '))
.off( $.trim(p.events.split(' ').join('.pager ')) )
.on('filterInit.pager filterStart.pager', function(e, filters) {
p.currentFilters = $.isArray(filters) ? filters : c.$table.data('lastSearch');
// don't change page if filters are the same (pager updating, etc)
@ -330,8 +330,8 @@ tsp = ts.pager = {
if ( p.$goto.length ) {
p.$goto
.off('change')
.on('change', function(){
.off('change.pager')
.on('change.pager', function(){
p.page = $(this).val() - 1;
tsp.moveToPage(table, p, true);
tsp.updatePageDisplay(table, c, false);
@ -443,7 +443,7 @@ tsp = ts.pager = {
if ($out.length) {
$out[ ($out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
// rebind startRow/page inputs
$out.find('.ts-startRow, .ts-page').off('change').on('change', function(){
$out.find('.ts-startRow, .ts-page').off('change.pager').on('change.pager', function(){
var v = $(this).val(),
pg = $(this).hasClass('ts-startRow') ? Math.floor( v/p.size ) + 1 : v;
c.$table.trigger('pageSet.pager', [ pg ]);
@ -1012,7 +1012,7 @@ tsp = ts.pager = {
destroyPager: function(table, c, refreshing){
var p = c.pager;
p.initialized = false;
c.$table.off(p.events.split(' ').join('.pager '));
c.$table.off( $.trim(p.events.split(' ').join('.pager ')) );
if (refreshing) { return; }
tsp.showAllRows(table, c);
p.$container.hide(); // hide pager

View File

@ -17,7 +17,7 @@
var ts = $.tablesorter,
// events triggered on the table that update this widget
events = 'staticRowsRefresh updateComplete '.split(' ').join('.tsstaticrows '),
events = $.trim( 'staticRowsRefresh updateComplete '.split(' ').join('.tsstaticrows ') ),
// add/refresh row indexes
addIndexes = function(table){