Parser: input-select updates. See #971

- Prevent javascript error.
- Include thead checkbox code to update tbody column checkboxes.
- Add thead checkbox updating with indeterminate state.
This commit is contained in:
Rob Garrison 2015-11-14 19:27:27 -06:00
parent 7a89f5323e
commit 8a9e52827e
2 changed files with 81 additions and 18 deletions

View File

@ -1,2 +1,2 @@
/*! Parser: input & select - updated 10/31/2015 (v2.24.0) */ /*! Parser: input & select - updated 10/31/2015 (v2.24.0) */
!function(a){"use strict";var b=function(a,b,c){};a.tablesorter.addParser({id:"inputs",is:function(){return!1},format:function(b,c,d){var e=a(d).find("input");return e.length?e.val():b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"inputs-numeric",is:function(){return!1},format:function(b,c,d){var e=a(d).find("input"),f=e.length?e.val():b,g=a.tablesorter.formatFloat((f||"").replace(/[^\w,. \-()]/g,""),c);return b&&"number"==typeof g?g:b?a.trim(b&&c.config.ignoreCase?b.toLocaleLowerCase():b):b},parsed:!0,type:"numeric"}),a.tablesorter.addParser({id:"checkbox",is:function(){return!1},format:function(b,c,d,e){var f=a(d),g=f.closest("tr"),h=c.config.widgetOptions,i=c.config.checkboxClass||"checked",j=h.group_checkbox?h.group_checkbox:["checked","unchecked"],k=f.find('input[type="checkbox"]'),l=k.length?k[0].checked:"";return g.toggleClass(i+"-"+e,l),l?g.addClass(i):g.length&&!(g[0].className||"").match(i+"-")&&g.removeClass(i),k.length?j[l?0:1]:b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"select",is:function(){return!1},format:function(b,c,d){var e=a(d).find("select");return e.length?e.val():b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"select-text",is:function(){return!1},format:function(b,c,d){var e=a(d).find("select");return e.length?e.find("option:selected").text()||"":b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"textarea",is:function(){return!1},format:function(b,c,d){var e=a(d).find("textarea");return e.length?e.val():b},parsed:!0,type:"text"}),a(function(){a("table").on("tablesorter-initialized updateComplete",function(){var c=".parser-forms",d=function(b){b&&a(":focus").blur()};a(this).children("tbody").off(c).on("mouseleave"+c,function(a){d("TBODY"===a.target.nodeName)}).on("focus"+c,"select, input, textarea",function(){a(this).data("ts-original-value",this.value)}).on("blur"+c,"input, textarea",function(){this.value=a(this).data("ts-original-value")}).on("change keyup ".split(" ").join(c+" "),"select, input, textarea",function(c){if(27===c.which)return void(this.value=a(this).data("ts-original-value"));if("change"===c.type||"keyup"===c.type&&13===c.which&&("INPUT"===c.target.nodeName||"TEXTAREA"===c.target.nodeName&&c.altKey)){var d,e=a(c.target),f=e.closest("td"),g=f.closest("table"),h=f[0].cellIndex,i=g[0].config||!1,j=i&&i.$headerIndexed&&i.$headerIndexed[h]||[],k=e.val();if(j.length&&(j.hasClass("parser-false")||j.hasClass("sorter-false")&&j.hasClass("filter-false")))return;(i&&k!==e.data("ts-original-value")||"checkbox"===c.target.type)&&(e.data("ts-original-value",k),a.tablesorter.updateCell(i,f,d,function(){b(c,g,e)}))}})})})}(jQuery); !function(a){"use strict";var b=function(a,b,c){};a.tablesorter.addParser({id:"inputs",is:function(){return!1},format:function(b,c,d){var e=a(d).find("input");return e.length?e.val():b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"inputs-numeric",is:function(){return!1},format:function(b,c,d){var e=a(d).find("input"),f=e.length?e.val():b,g=a.tablesorter.formatFloat((f||"").replace(/[^\w,. \-()]/g,""),c);return b&&"number"==typeof g?g:b?a.trim(b&&c.config.ignoreCase?b.toLocaleLowerCase():b):b},parsed:!0,type:"numeric"}),a.tablesorter.addParser({id:"checkbox",is:function(){return!1},format:function(b,c,d,e){var f=a(d),g=f.closest("tr"),h=c.config.widgetOptions,i=c.config.checkboxClass||"checked",j=h.group_checkbox?h.group_checkbox:["checked","unchecked"],k=f.find('input[type="checkbox"]'),l=k.length?k[0].checked:"";return g.toggleClass(i+"-"+e,l),l?g.addClass(i):g.length&&!(g[0].className||"").match(i+"-")&&g.removeClass(i),k.length?j[l?0:1]:b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"select",is:function(){return!1},format:function(b,c,d){var e=a(d).find("select");return e.length?e.val():b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"select-text",is:function(){return!1},format:function(b,c,d){var e=a(d).find("select");return e.length?e.find("option:selected").text()||"":b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"textarea",is:function(){return!1},format:function(b,c,d){var e=a(d).find("textarea");return e.length?e.val():b},parsed:!0,type:"text"}),a(function(){a.fn.on&&a("table").on("tablesorter-initialized updateComplete",function(){this.tablesorterBusy=!1;var c=".parser-forms";a(this).children("tbody").off(c).on("mouseleave"+c,function(b){"TBODY"===b.target.nodeName&&a(":focus").blur()}).on("focus"+c,"select, input, textarea",function(){a(this).data("ts-original-value",this.value)}).on("blur"+c,"input, textarea",function(){this.value=a(this).data("ts-original-value")}).on("change keyup ".split(" ").join(c+" "),"select, input, textarea",function(c){if(27===c.which)return void(this.value=a(this).data("ts-original-value"));if("change"===c.type||"keyup"===c.type&&13===c.which&&("INPUT"===c.target.nodeName||"TEXTAREA"===c.target.nodeName&&c.altKey)){var d,e=a(c.target),f="checkbox"===c.target.type,g=e.closest("td"),h=g.closest("table"),i=g[0].cellIndex,j=h[0].config||!1,k=h.length&&h[0].tablesorterBusy,l=j&&j.$headerIndexed&&j.$headerIndexed[i]||[],m=f?c.target.checked:e.val();if(a.isEmptyObject(j)||k!==!1||l.length&&(l.hasClass("parser-false")||l.hasClass("sorter-false")&&l.hasClass("filter-false"))||"change"===c.type&&j.table.isUpdating)return;(j&&m!==e.data("ts-original-value")||f)&&(e.data("ts-original-value",m),h[0].tablesorterBusy=!0,a.tablesorter.updateCell(j,g,d,function(){b(c,h,e),h[0].tablesorterBusy=!1}))}}),a(this).children("thead").find('input[type="checkbox"]')&&a(this).off(c).on("tablesorter-ready"+c,function(){var b,c,d,e=a(this),f=e.length&&e[0].config;a.isEmptyObject(f)||(this.tablesorterBusy=!0,b=f&&f.checkboxClass||"checked",c=e.children("tbody").children(":visible"),d=c.length,a(this).children("thead").find('input[type="checkbox"]').each(function(){var e=a(this).closest("td, th").attr("data-column"),f=c.filter("."+b+"-"+e).length,g=f===d;0===f||g?(this.checked=g,this.indeterminate=!1):this.indeterminate=!0}),this.tablesorterBusy=!1)}).children("thead").off(c).on("change"+c,'input[type="checkbox"]',function(c){var d,e,f,g,h=a(this),i=h.closest("table"),j=i.length&&i[0].config,k=this.checked;return i.length&&j&&!i[0].tablesorterBusy&&(f=parseInt(h.closest("td, th").attr("data-column"),10),e=i.length&&j.checkboxVisible,i[0].tablesorterBusy=!0,g=i.children("tbody").children("tr"+("undefined"==typeof e||e===!0?":visible":"")).children(":nth-child("+(f+1)+")").find('input[type="checkbox"]').prop("checked",k),a.tablesorter.update(j,d,function(){b(c,i,g),i[0].tablesorterBusy=!1})),!1})})})}(jQuery);

View File

@ -10,7 +10,8 @@
// do something here to update your server, if needed // do something here to update your server, if needed
// event = change event object // event = change event object
// $table = jQuery object of the table that was just updated // $table = jQuery object of the table that was just updated
// $input = jQuery object of the input or select that was modified // $input = jQuery object(s) of the input or select that was modified; in v2.24.6,
// if the thead has a checkbox, $input may include multiple elements
}; };
// Custom parser for parsing input values // Custom parser for parsing input values
@ -125,22 +126,20 @@
// you can change it to use delegate (v1.4.3+) or live (v1.3+) as desired // you can change it to use delegate (v1.4.3+) or live (v1.3+) as desired
// if this code interferes somehow, target the specific table $('#mytable'), instead of $('table') // if this code interferes somehow, target the specific table $('#mytable'), instead of $('table')
$( function() { $( function() {
if ( !$.fn.on ) { return; }
$( 'table' ).on( 'tablesorter-initialized updateComplete', function() { $( 'table' ).on( 'tablesorter-initialized updateComplete', function() {
var namespace = '.parser-forms', this.tablesorterBusy = false;
restoreValue = function( isTbody ) { var namespace = '.parser-forms';
// make sure we restore original values (trigger blur)
// isTbody is needed to prevent the select from closing in IE
// see https://connect.microsoft.com/IE/feedbackdetail/view/962618/
if ( isTbody ) {
$( ':focus' ).blur();
}
return;
};
// bind to .tablesorter (default class name) // bind to .tablesorter (default class name)
$( this ).children( 'tbody' ) $( this ).children( 'tbody' )
.off( namespace ) .off( namespace )
.on( 'mouseleave' + namespace, function( event ) { .on( 'mouseleave' + namespace, function( event ) {
restoreValue( event.target.nodeName === 'TBODY' ); // make sure we restore original values (trigger blur)
// isTbody is needed to prevent the select from closing in IE
// see https://connect.microsoft.com/IE/feedbackdetail/view/962618/
if ( event.target.nodeName === 'TBODY' ) {
$( ':focus' ).blur();
}
}) })
.on( 'focus' + namespace, 'select, input, textarea', function() { .on( 'focus' + namespace, 'select, input, textarea', function() {
$( this ).data( 'ts-original-value', this.value ); $( this ).data( 'ts-original-value', this.value );
@ -162,28 +161,92 @@
( event.target.nodeName === 'INPUT' || event.target.nodeName === 'TEXTAREA' && event.altKey ) ) ) { ( event.target.nodeName === 'INPUT' || event.target.nodeName === 'TEXTAREA' && event.altKey ) ) ) {
var undef, var undef,
$target = $( event.target ), $target = $( event.target ),
isCheckbox = event.target.type === 'checkbox',
$cell = $target.closest( 'td' ), $cell = $target.closest( 'td' ),
$table = $cell.closest( 'table' ), $table = $cell.closest( 'table' ),
indx = $cell[ 0 ].cellIndex, indx = $cell[ 0 ].cellIndex,
c = $table[ 0 ].config || false, c = $table[ 0 ].config || false,
busy = $table.length && $table[ 0 ].tablesorterBusy,
$hdr = c && c.$headerIndexed && c.$headerIndexed[ indx ] || [], $hdr = c && c.$headerIndexed && c.$headerIndexed[ indx ] || [],
val = $target.val(); val = isCheckbox ? event.target.checked : $target.val();
// abort if not a tablesorter table, or don't use updateCell if column is set // abort if not a tablesorter table, or busy, or don't use updateCell if column is set
// to 'sorter-false' and 'filter-false', or column is set to 'parser-false' // to 'sorter-false' and 'filter-false', or column is set to 'parser-false'
if ( $hdr.length && ( $hdr.hasClass( 'parser-false' ) || if ( $.isEmptyObject( c ) || busy !== false || $hdr.length && ( $hdr.hasClass( 'parser-false' ) ||
( $hdr.hasClass( 'sorter-false' ) && $hdr.hasClass( 'filter-false' ) ) ) ) { ( $hdr.hasClass( 'sorter-false' ) && $hdr.hasClass( 'filter-false' ) ) ) ||
// table already updating; get out of here, we might be in an endless loop (in IE)! See #971
( event.type === 'change' && c.table.isUpdating ) ) {
return; return;
} }
// ignore change event if nothing changed // ignore change event if nothing changed
if ( c && val !== $target.data( 'ts-original-value' ) || event.target.type === 'checkbox' ) { if ( c && val !== $target.data( 'ts-original-value' ) || isCheckbox ) {
$target.data( 'ts-original-value', val ); $target.data( 'ts-original-value', val );
$table[ 0 ].tablesorterBusy = true;
// pass undefined resort value so it falls back to config.resort setting // pass undefined resort value so it falls back to config.resort setting
$.tablesorter.updateCell( c, $cell, undef, function() { $.tablesorter.updateCell( c, $cell, undef, function() {
updateServer( event, $table, $target ); updateServer( event, $table, $target );
$table[ 0 ].tablesorterBusy = false;
}); });
} }
} }
}); });
// add code for a checkbox in the header to set/unset all checkboxes in a column
if ( $( this ).children( 'thead' ).find( 'input[type="checkbox"]' ) ) {
$( this )
.off( namespace )
.on( 'tablesorter-ready' + namespace, function() {
var checkboxClass, $rows, len,
$table = $( this ),
c = $table.length && $table[ 0 ].config;
if ( !$.isEmptyObject( c ) ) {
this.tablesorterBusy = true;
checkboxClass = c && c.checkboxClass || 'checked';
$rows = $table.children( 'tbody' ).children( ':visible' ); // (include child rows?)
len = $rows.length;
// set indeterminate state on header checkbox
$( this ).children( 'thead' ).find( 'input[type="checkbox"]' ).each( function() {
var column = $( this ).closest( 'td, th' ).attr( 'data-column' ),
vis = $rows.filter( '.' + checkboxClass + '-' + column ).length,
allChecked = vis === len;
if ( vis === 0 || allChecked ) {
this.checked = allChecked;
this.indeterminate = false;
} else {
this.indeterminate = true;
}
});
this.tablesorterBusy = false;
}
})
.children( 'thead' )
.off( namespace )
// modified from http://jsfiddle.net/abkNM/6163/
.on( 'change' + namespace, 'input[type="checkbox"]', function( event ) {
var undef, onlyVisible, column, $target,
$checkbox = $( this ),
$table = $checkbox.closest( 'table' ),
c = $table.length && $table[ 0 ].config,
isChecked = this.checked;
if ( $table.length && c && !$table[ 0 ].tablesorterBusy ) {
column = parseInt( $checkbox.closest( 'td, th' ).attr( 'data-column' ), 10 );
onlyVisible = $table.length && c.checkboxVisible;
$table[ 0 ].tablesorterBusy = true; // prevent "change" event from calling updateCell numerous times (see #971)
$target = $table
.children( 'tbody' )
.children( 'tr' + ( typeof onlyVisible === 'undefined' || onlyVisible === true ? ':visible' : '' ) )
.children( ':nth-child(' + ( column + 1 ) + ')' )
.find( 'input[type="checkbox"]' )
.prop( 'checked', isChecked );
$.tablesorter.update( c, undef, function() {
updateServer( event, $table, $target );
$table[ 0 ].tablesorterBusy = false;
});
}
// update already going on, don't do anything!
return false;
});
}
}); });
}); });