' ).wrapInner( wo.editable_wrapContent ).children().length || $.isFunction( wo.editable_wrapContent ),
- cols = tse.getColumns( c, wo ).join( ',' );
-
- // turn off contenteditable to allow dynamically setting the wo.editable_noEdit
- // class on table cells - see issue #900
- c.$tbodies.find( cols ).find( '[contenteditable]' ).prop( 'contenteditable', false );
-
- // IE does not allow making TR/TH/TD cells directly editable ( issue #404 )
- // so add a div or span inside ( it's faster than using wrapInner() )
- c.$tbodies.find( cols ).not( '.' + wo.editable_noEdit ).each( function() {
- // test for children, if they exist, then make the children editable
- $t = $( this );
-
- if ( tmp && $t.children( 'div, span' ).length === 0 ) {
- $t.wrapInner( wo.editable_wrapContent );
+ getColumns : function( c, wo ) {
+ var indx, tmp,
+ colIndex = [],
+ cols = [];
+ if ( !wo.editable_columnsArray && $.type( wo.editable_columns ) === 'string' && wo.editable_columns.indexOf( '-' ) >= 0 ) {
+ // editable_columns can contain a range string ( i.e. '2-4' )
+ tmp = wo.editable_columns.split( /\s*-\s*/ );
+ indx = parseInt( tmp[ 0 ], 10 ) || 0;
+ tmp = parseInt( tmp[ 1 ], 10 ) || ( c.columns - 1 );
+ if ( tmp > c.columns ) {
+ tmp = c.columns - 1;
+ }
+ for ( ; indx <= tmp; indx++ ) {
+ colIndex.push( indx );
+ cols.push( 'td:nth-child(' + ( indx + 1 ) + ')' );
+ }
+ } else if ( $.isArray( wo.editable_columns ) ) {
+ $.each( wo.editable_columnsArray || wo.editable_columns, function( i, col ) {
+ if ( col < c.columns ) {
+ colIndex.push( col );
+ cols.push( 'td:nth-child(' + ( col + 1 ) + ')' );
+ }
+ });
}
- if ( $t.children( 'div, span' ).length ) {
- // make div/span children content editable
- $t.children( 'div, span' ).not( '.' + wo.editable_noEdit ).each( function() {
- var $this = $( this );
+ if ( !wo.editable_columnsArray ) {
+ wo.editable_columnsArray = colIndex;
+ wo.editable_columnsArray.sort(function(a, b){ return a - b; });
+ }
+ return cols;
+ },
+
+ update: function( c, wo ) {
+ var $t,
+ tmp = $( '
' ).wrapInner( wo.editable_wrapContent ).children().length || $.isFunction( wo.editable_wrapContent ),
+ cols = tse.getColumns( c, wo ).join( ',' );
+
+ // turn off contenteditable to allow dynamically setting the wo.editable_noEdit
+ // class on table cells - see issue #900
+ c.$tbodies.find( cols ).find( '[contenteditable]' ).prop( 'contenteditable', false );
+
+ // IE does not allow making TR/TH/TD cells directly editable ( issue #404 )
+ // so add a div or span inside ( it's faster than using wrapInner() )
+ c.$tbodies.find( cols ).not( '.' + wo.editable_noEdit ).each( function() {
+ // test for children, if they exist, then make the children editable
+ $t = $( this );
+
+ if ( tmp && $t.children( 'div, span' ).length === 0 ) {
+ $t.wrapInner( wo.editable_wrapContent );
+ }
+ if ( $t.children( 'div, span' ).length ) {
+ // make div/span children content editable
+ $t.children( 'div, span' ).not( '.' + wo.editable_noEdit ).each( function() {
+ var $this = $( this );
+ if ( wo.editable_trimContent ) {
+ $this.html( function( i, txt ) {
+ return $.trim( txt );
+ });
+ }
+ $this.prop( 'contenteditable', true );
+ });
+ } else {
if ( wo.editable_trimContent ) {
- $this.html( function( i, txt ) {
+ $t.html( function( i, txt ) {
return $.trim( txt );
});
}
- $this.prop( 'contenteditable', true );
- });
- } else {
- if ( wo.editable_trimContent ) {
- $t.html( function( i, txt ) {
- return $.trim( txt );
- });
- }
- $t.prop( 'contenteditable', true );
- }
- });
- },
-
- bindEvents: function( c, wo ) {
- var namespace = tse.namespace;
- c.$table
- .off( ( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' ) )
- .on( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ), function() {
- tse.update( c, c.widgetOptions );
- })
- // prevent sort initialized by user click on the header from changing the row indexing before
- // updateCell can finish processing the change
- .children( 'thead' )
- .add( $( c.namespace + '_extra_table' ).children( 'thead' ) )
- .off( 'mouseenter' + namespace )
- .on( 'mouseenter' + namespace, function() {
- if ( c.$table.data( 'contentFocused' ) ) {
- // change to 'true' instead of element to allow focusout to process
- c.$table.data( 'contentFocused', true );
- $( ':focus' ).trigger( 'focusout' );
+ $t.prop( 'contenteditable', true );
}
});
+ },
- c.$tbodies
- .off( ( 'focus blur focusout keydown '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' ) )
- .on( 'focus' + namespace, '[contenteditable]', function( e ) {
- clearTimeout( $( this ).data( 'timer' ) );
- c.$table.data( 'contentFocused', e.target );
- c.table.isUpdating = true; // prevent sorting while editing
- var $this = $( this ),
- selAll = wo.editable_selectAll,
- column = $this.closest( 'td' ).index(),
- txt = $this.html();
- if ( wo.editable_trimContent ) {
- txt = $.trim( txt );
- }
- // prevent enter from adding into the content
- $this
- .off( 'keydown' + namespace )
- .on( 'keydown' + namespace, function( e ){
- if ( wo.editable_enterToAccept && e.which === 13 && !e.shiftKey ) {
- e.preventDefault();
- }
- });
- $this.data({ before : txt, original: txt });
+ bindEvents: function( c, wo ) {
+ var namespace = tse.namespace;
+ c.$table
+ .off( ( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' ) )
+ .on( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ), function() {
+ tse.update( c, c.widgetOptions );
+ })
+ // prevent sort initialized by user click on the header from changing the row indexing before
+ // updateCell can finish processing the change
+ .children( 'thead' )
+ .add( $( c.namespace + '_extra_table' ).children( 'thead' ) )
+ .off( 'mouseenter' + namespace )
+ .on( 'mouseenter' + namespace, function() {
+ if ( c.$table.data( 'contentFocused' ) ) {
+ // change to 'true' instead of element to allow focusout to process
+ c.$table.data( 'contentFocused', true );
+ $( ':focus' ).trigger( 'focusout' );
+ }
+ });
- if ( typeof wo.editable_focused === 'function' ) {
- wo.editable_focused( txt, column, $this );
- }
+ c.$tbodies
+ .off( ( 'focus blur focusout keydown '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' ) )
+ .on( 'focus' + namespace, '[contenteditable]', function( e ) {
+ clearTimeout( $( this ).data( 'timer' ) );
+ c.$table.data( 'contentFocused', e.target );
+ c.table.isUpdating = true; // prevent sorting while editing
+ var $this = $( this ),
+ selAll = wo.editable_selectAll,
+ column = $this.closest( 'td' ).index(),
+ txt = $this.html();
+ if ( wo.editable_trimContent ) {
+ txt = $.trim( txt );
+ }
+ // prevent enter from adding into the content
+ $this
+ .off( 'keydown' + namespace )
+ .on( 'keydown' + namespace, function( e ){
+ if ( wo.editable_enterToAccept && e.which === 13 && !e.shiftKey ) {
+ e.preventDefault();
+ }
+ });
+ $this.data({ before : txt, original: txt });
- if ( selAll ) {
- if ( typeof selAll === 'function' ) {
- if ( selAll( txt, column, $this ) ) {
+ if ( typeof wo.editable_focused === 'function' ) {
+ wo.editable_focused( txt, column, $this );
+ }
+
+ if ( selAll ) {
+ if ( typeof selAll === 'function' ) {
+ if ( selAll( txt, column, $this ) ) {
+ tse.selectAll( $this[0] );
+ }
+ } else {
tse.selectAll( $this[0] );
}
- } else {
- tse.selectAll( $this[0] );
}
- }
- })
- .on( 'blur focusout keydown '.split( ' ' ).join( namespace + ' ' ), '[contenteditable]', function( e ) {
- if ( !c.$table.data( 'contentFocused' ) ) { return; }
- var t, validate,
- valid = false,
- $this = $( e.target ),
- txt = $this.html(),
- column = $this.closest( 'td' ).index();
- if ( wo.editable_trimContent ) {
- txt = $.trim( txt );
- }
- if ( e.which === 27 ) {
- // user cancelled
- $this.html( $this.data( 'original' ) ).trigger( 'blur' + namespace );
- c.$table.data( 'contentFocused', false );
- c.table.isUpdating = false;
- return false;
- }
- // accept on enter ( if set ), alt-enter ( always ) or if autoAccept is set and element is blurred or unfocused
- t = e.which === 13 && !e.shiftKey && ( wo.editable_enterToAccept || e.altKey ) || wo.editable_autoAccept && e.type !== 'keydown';
- // change if new or user hits enter ( if option set )
- if ( t && $this.data( 'before' ) !== txt ) {
-
- validate = wo.editable_validate;
- valid = txt;
-
- if ( typeof( validate ) === 'function' ) {
- valid = validate( txt, $this.data( 'original' ), column, $this );
- } else if ( typeof ( validate = $.tablesorter.getColumnData( c.table, validate, column ) ) === 'function' ) {
- valid = validate( txt, $this.data( 'original' ), column, $this );
+ })
+ .on( 'blur focusout keydown '.split( ' ' ).join( namespace + ' ' ), '[contenteditable]', function( e ) {
+ if ( !c.$table.data( 'contentFocused' ) ) { return; }
+ var t, validate,
+ valid = false,
+ $this = $( e.target ),
+ txt = $this.html(),
+ column = $this.closest( 'td' ).index();
+ if ( wo.editable_trimContent ) {
+ txt = $.trim( txt );
}
-
- if ( t && valid !== false ) {
- c.$table.find( '.' + tse.lastEdited ).removeClass( tse.lastEdited );
- $this
- .addClass( tse.lastEdited )
- .html( valid )
- .data( 'before', valid )
- .data( 'original', valid )
- .trigger( 'change' );
- c.$table.trigger( 'updateCell', [ $this.closest( 'td' ), false, function() {
- if ( wo.editable_autoResort ) {
- setTimeout( function() {
- c.$table.trigger( 'sorton', [ c.sortList, function() {
- tse.editComplete( c, wo, c.$table.data( 'contentFocused' ), true );
- }, true ] );
- }, 10 );
- } else {
- tse.editComplete( c, wo, c.$table.data( 'contentFocused' ) );
- }
- } ] );
+ if ( e.which === 27 ) {
+ // user cancelled
+ $this.html( $this.data( 'original' ) ).trigger( 'blur' + namespace );
+ c.$table.data( 'contentFocused', false );
+ c.table.isUpdating = false;
return false;
}
- } else if ( !valid && e.type !== 'keydown' ) {
- clearTimeout( $this.data( 'timer' ) );
- $this.data( 'timer', setTimeout( function() {
- c.table.isUpdating = false; // clear flag or sorting will be disabled
+ // accept on enter ( if set ), alt-enter ( always ) or if autoAccept is set and element is blurred or unfocused
+ t = e.which === 13 && !e.shiftKey && ( wo.editable_enterToAccept || e.altKey ) || wo.editable_autoAccept && e.type !== 'keydown';
+ // change if new or user hits enter ( if option set )
+ if ( t && $this.data( 'before' ) !== txt ) {
- if ( $.isFunction( wo.editable_blur ) ) {
- txt = $this.html();
- wo.editable_blur( wo.editable_trimContent ? $.trim( txt ) : txt, column, $this );
+ validate = wo.editable_validate;
+ valid = txt;
+
+ if ( typeof validate === 'function' ) {
+ valid = validate( txt, $this.data( 'original' ), column, $this );
+ } else if ( typeof ( validate = $.tablesorter.getColumnData( c.table, validate, column ) ) === 'function' ) {
+ valid = validate( txt, $this.data( 'original' ), column, $this );
}
- }, 100 ) );
- // restore original content on blur
- $this.html( $this.data( 'original' ) );
- }
- });
- },
- destroy : function( c, wo ) {
- var namespace = tse.namespace,
- cols = tse.getColumns( c, wo ),
- tmp = ( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' );
- c.$table.off( tmp );
+ if ( t && valid !== false ) {
+ c.$table.find( '.' + tse.lastEdited ).removeClass( tse.lastEdited );
+ $this
+ .addClass( tse.lastEdited )
+ .html( valid )
+ .data( 'before', valid )
+ .data( 'original', valid )
+ .trigger( 'change' );
+ c.$table.trigger( 'updateCell', [ $this.closest( 'td' ), false, function() {
+ if ( wo.editable_autoResort ) {
+ setTimeout( function() {
+ c.$table.trigger( 'sorton', [ c.sortList, function() {
+ tse.editComplete( c, wo, c.$table.data( 'contentFocused' ), true );
+ }, true ] );
+ }, 10 );
+ } else {
+ tse.editComplete( c, wo, c.$table.data( 'contentFocused' ) );
+ }
+ } ] );
+ return false;
+ }
+ } else if ( !valid && e.type !== 'keydown' ) {
+ clearTimeout( $this.data( 'timer' ) );
+ $this.data( 'timer', setTimeout( function() {
+ c.table.isUpdating = false; // clear flag or sorting will be disabled
- tmp = ( 'focus blur focusout keydown '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' );
- c.$tbodies
- .off( tmp )
- .find( cols.join( ',' ) )
- .find( '[contenteditable]' )
- .prop( 'contenteditable', false );
- }
+ if ( $.isFunction( wo.editable_blur ) ) {
+ txt = $this.html();
+ wo.editable_blur( wo.editable_trimContent ? $.trim( txt ) : txt, column, $this );
+ }
+ }, 100 ) );
+ // restore original content on blur
+ $this.html( $this.data( 'original' ) );
+ }
+ });
+ },
+ destroy : function( c, wo ) {
+ var namespace = tse.namespace,
+ cols = tse.getColumns( c, wo ),
-};
+ tmp = ( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' );
+ c.$table.off( tmp );
+
+ tmp = ( 'focus blur focusout keydown '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' );
+ c.$tbodies
+ .off( tmp )
+ .find( cols.join( ',' ) )
+ .find( '[contenteditable]' )
+ .prop( 'contenteditable', false );
+ }
+
+ };
$.tablesorter.addWidget({
id: 'editable',
diff --git a/js/widgets/widget-filter-formatter-html5.js b/js/widgets/widget-filter-formatter-html5.js
index 1c5e303d..67e67353 100644
--- a/js/widgets/widget-filter-formatter-html5.js
+++ b/js/widgets/widget-filter-formatter-html5.js
@@ -8,422 +8,421 @@
/*jshint browser:true, jquery:true, unused:false */
/*global jQuery: false */
;(function($){
-"use strict";
+ 'use strict';
-var ts = $.tablesorter || {},
+ var ts = $.tablesorter || {},
-// compare option selector class name (jQuery selector)
-compareSelect = '.compare-select',
+ // compare option selector class name (jQuery selector)
+ compareSelect = '.compare-select',
+ tsff = ts.filterFormatter = $.extend( {}, ts.filterFormatter, {
-tsff = ts.filterFormatter = $.extend( {}, ts.filterFormatter, {
-
- addCompare: function($cell, indx, options){
- if (options.compare && $.isArray(options.compare) && options.compare.length > 1) {
- var opt = '',
- compareSelectClass = [ compareSelect.slice(1), ' ' + compareSelect.slice(1), '' ],
- txt = options.cellText ? '
' : '';
- $.each(options.compare, function(i, c){
- opt += '
';
- });
- $cell
- .wrapInner('
')
- .prepend( txt + '
' )
- .find('select')
- .append(opt);
- }
- },
-
- updateCompare : function($cell, $input, o) {
- var val = $input.val() || '',
- num = val.replace(/\s*?[><=]\s*?/g, ''),
- compare = val.match(/[><=]/g) || '';
- if (o.compare) {
- if ($.isArray(o.compare)){
- compare = (compare || []).join('') || o.compare[o.selected || 0];
+ addCompare: function($cell, indx, options){
+ if (options.compare && $.isArray(options.compare) && options.compare.length > 1) {
+ var opt = '',
+ compareSelectClass = [ compareSelect.slice(1), ' ' + compareSelect.slice(1), '' ],
+ txt = options.cellText ? '
' : '';
+ $.each(options.compare, function(i, c){
+ opt += '
';
+ });
+ $cell
+ .wrapInner('
')
+ .prepend( txt + '
' )
+ .find('select')
+ .append(opt);
}
- $cell.find(compareSelect).val( compare );
- }
- return [ val, num ];
- },
+ },
- /**********************\
- HTML5 Number (spinner)
- \**********************/
- html5Number : function($cell, indx, def5Num) {
- var t, o = $.extend({
- value : 0,
- min : 0,
- max : 100,
- step : 1,
- delayed : true,
- disabled : false,
- addToggle : false,
- exactMatch : false,
- cellText : '',
- compare : '',
- skipTest: false
- }, def5Num),
-
- $input,
- // test browser for HTML5 range support
- $number = $('
').appendTo($cell),
- // test if HTML5 number is supported - from Modernizr
- numberSupported = o.skipTest || $number.attr('type') === 'number' && $number.val() !== 'test',
- $shcell = [],
- c = $cell.closest('table')[0].config,
-
- updateNumber = function(delayed, notrigger){
- var chkd = o.addToggle ? $cell.find('.toggle').is(':checked') : true,
- v = $cell.find('.number').val(),
- compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
- searchType = c.$table[0].hasInitialized ? (delayed ? delayed : o.delayed) || '' : true;
- $input
- // add equal to the beginning, so we filter exact numbers
- .val( !o.addToggle || chkd ? (compare ? compare : o.exactMatch ? '=' : '') + v : '' )
- .trigger( notrigger ? '' : 'search', searchType ).end()
- .find('.number').val(v);
- if ($cell.find('.number').length) {
- $cell.find('.number')[0].disabled = (o.disabled || !chkd);
- }
- // update sticky header cell
- if ($shcell.length) {
- $shcell.find('.number').val(v)[0].disabled = (o.disabled || !chkd);
- $shcell.find(compareSelect).val(compare);
- if (o.addToggle) {
- $shcell.find('.toggle')[0].checked = chkd;
+ updateCompare : function($cell, $input, o) {
+ var val = $input.val() || '',
+ num = val.replace(/\s*?[><=]\s*?/g, ''),
+ compare = val.match(/[><=]/g) || '';
+ if (o.compare) {
+ if ($.isArray(o.compare)){
+ compare = (compare || []).join('') || o.compare[o.selected || 0];
}
+ $cell.find(compareSelect).val( compare );
}
- };
- $number.remove();
+ return [ val, num ];
+ },
- if (numberSupported) {
- t = o.addToggle ? '
' +
- '
' : '';
- t += '
';
- // add HTML5 number (spinner)
- $cell
- .append(t + '
')
- .find('.toggle, .number').bind('change', function(){
- updateNumber();
- })
- .closest('thead').find('th[data-column=' + indx + ']')
- .addClass('filter-parsed') // get exact numbers from column
- // on reset
- .closest('table').bind('filterReset', function(){
- if ($.isArray(o.compare)) {
- $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
- }
- // turn off the toggle checkbox
+ /**********************\
+ HTML5 Number (spinner)
+ \**********************/
+ html5Number : function($cell, indx, def5Num) {
+ var t, o = $.extend({
+ value : 0,
+ min : 0,
+ max : 100,
+ step : 1,
+ delayed : true,
+ disabled : false,
+ addToggle : false,
+ exactMatch : false,
+ cellText : '',
+ compare : '',
+ skipTest: false
+ }, def5Num),
+
+ $input,
+ // test browser for HTML5 range support
+ $number = $('
').appendTo($cell),
+ // test if HTML5 number is supported - from Modernizr
+ numberSupported = o.skipTest || $number.attr('type') === 'number' && $number.val() !== 'test',
+ $shcell = [],
+ c = $cell.closest('table')[0].config,
+
+ updateNumber = function(delayed, notrigger){
+ var chkd = o.addToggle ? $cell.find('.toggle').is(':checked') : true,
+ v = $cell.find('.number').val(),
+ compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
+ searchType = c.$table[0].hasInitialized ? (delayed ? delayed : o.delayed) || '' : true;
+ $input
+ // add equal to the beginning, so we filter exact numbers
+ .val( !o.addToggle || chkd ? (compare ? compare : o.exactMatch ? '=' : '') + v : '' )
+ .trigger( notrigger ? '' : 'search', searchType ).end()
+ .find('.number').val(v);
+ if ($cell.find('.number').length) {
+ $cell.find('.number')[0].disabled = (o.disabled || !chkd);
+ }
+ // update sticky header cell
+ if ($shcell.length) {
+ $shcell.find('.number').val(v)[0].disabled = (o.disabled || !chkd);
+ $shcell.find(compareSelect).val(compare);
if (o.addToggle) {
- $cell.find('.toggle')[0].checked = false;
- if ($shcell.length) {
- $shcell.find('.toggle')[0].checked = false;
- }
+ $shcell.find('.toggle')[0].checked = chkd;
}
- $cell.find('.number').val( o.value );
- setTimeout(function(){
+ }
+ };
+ $number.remove();
+
+ if (numberSupported) {
+ t = o.addToggle ? '
' +
+ '
' : '';
+ t += '
';
+ // add HTML5 number (spinner)
+ $cell
+ .append(t + '
')
+ .find('.toggle, .number').bind('change', function(){
updateNumber();
- }, 0);
- });
- $input = $cell.find('input[type=hidden]').bind('change', function(){
- $cell.find('.number').val( this.value );
- updateNumber();
- });
-
- // update slider from hidden input, in case of saved filters
- c.$table.bind('filterFomatterUpdate', function(){
- var val = tsff.updateCompare($cell, $input, o)[0] || o.value;
- $cell.find('.number').val( ((val || '') + '').replace(/[><=]/g,'') );
- updateNumber(false, true);
- ts.filter.formatterUpdated($cell, indx);
- });
-
- if (o.compare) {
- // add compare select
- tsff.addCompare($cell, indx, o);
- $cell.find(compareSelect).bind('change', function(){
+ })
+ .closest('thead').find('th[data-column=' + indx + ']')
+ .addClass('filter-parsed') // get exact numbers from column
+ // on reset
+ .closest('table').bind('filterReset', function(){
+ if ($.isArray(o.compare)) {
+ $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
+ }
+ // turn off the toggle checkbox
+ if (o.addToggle) {
+ $cell.find('.toggle')[0].checked = false;
+ if ($shcell.length) {
+ $shcell.find('.toggle')[0].checked = false;
+ }
+ }
+ $cell.find('.number').val( o.value );
+ setTimeout(function(){
+ updateNumber();
+ }, 0);
+ });
+ $input = $cell.find('input[type=hidden]').bind('change', function(){
+ $cell.find('.number').val( this.value );
updateNumber();
});
- }
- // has sticky headers?
- c.$table.bind('stickyHeadersInit', function(){
- $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
- $shcell
- .append(t)
- .find('.toggle, .number').bind('change', function(){
- $cell.find('.number').val( $(this).val() );
- updateNumber();
- });
+ // update slider from hidden input, in case of saved filters
+ c.$table.bind('filterFomatterUpdate', function(){
+ var val = tsff.updateCompare($cell, $input, o)[0] || o.value;
+ $cell.find('.number').val( ((val || '') + '').replace(/[><=]/g, '') );
+ updateNumber(false, true);
+ ts.filter.formatterUpdated($cell, indx);
+ });
if (o.compare) {
// add compare select
- tsff.addCompare($shcell, indx, o);
- $shcell.find(compareSelect).bind('change', function(){
- $cell.find(compareSelect).val( $(this).val() );
+ tsff.addCompare($cell, indx, o);
+ $cell.find(compareSelect).bind('change', function(){
updateNumber();
});
}
+ // has sticky headers?
+ c.$table.bind('stickyHeadersInit', function(){
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
+ $shcell
+ .append(t)
+ .find('.toggle, .number').bind('change', function(){
+ $cell.find('.number').val( $(this).val() );
+ updateNumber();
+ });
+
+ if (o.compare) {
+ // add compare select
+ tsff.addCompare($shcell, indx, o);
+ $shcell.find(compareSelect).bind('change', function(){
+ $cell.find(compareSelect).val( $(this).val() );
+ updateNumber();
+ });
+ }
+
+ updateNumber();
+ });
+
updateNumber();
- });
- updateNumber();
-
- }
-
- return numberSupported ? $cell.find('input[type="hidden"]') : $('
');
- },
-
- /**********************\
- HTML5 range slider
- \**********************/
- html5Range : function($cell, indx, def5Range) {
- var o = $.extend({
- value : 0,
- min : 0,
- max : 100,
- step : 1,
- delayed : true,
- valueToHeader : true,
- exactMatch : true,
- cellText : '',
- compare : '',
- allText : 'all',
- skipTest : false
- }, def5Range),
-
- $input,
- // test browser for HTML5 range support
- $range = $('
').appendTo($cell),
- // test if HTML5 range is supported - from Modernizr (but I left out the method to detect in Safari 2-4)
- // see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/inputtypes.js
- rangeSupported = o.skipTest || $range.attr('type') === 'range' && $range.val() !== 'test',
- $shcell = [],
- c = $cell.closest('table')[0].config,
-
- updateRange = function(v, delayed, notrigger){
- /*jshint eqeqeq:false */
- // hidden input changes may include compare symbols
- v = ( typeof v === "undefined" ? $input.val() : v ).toString().replace(/[<>=]/g,'') || o.value;
- var compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
- t = ' (' + (compare ? compare + v : v == o.min ? o.allText : v) + ')',
- searchType = c.$table[0].hasInitialized ? (delayed ? delayed : o.delayed) || '' : true;
- $cell.find('input[type=hidden]')
- // add equal to the beginning, so we filter exact numbers
- .val( ( compare ? compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) ) )
- //( val == o.min ? '' : val + (o.exactMatch ? '=' : ''))
- .trigger( notrigger ? '' : 'search', searchType ).end()
- .find('.range').val(v);
- // or add current value to the header cell, if desired
- $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t);
- // update sticky header cell
- if ($shcell.length) {
- $shcell
- .find('.range').val(v).end()
- .find(compareSelect).val( compare );
- $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t);
}
- };
- $range.remove();
- if (rangeSupported) {
- // add HTML5 range
- $cell
- .html('
')
- .closest('thead').find('th[data-column=' + indx + ']')
- .addClass('filter-parsed') // get exact numbers from column
- // add span to header for the current slider value
- .find('.tablesorter-header-inner').append('
');
- // hidden filter update namespace trigger by filter widget
- $input = $cell.find('input[type=hidden]').bind('change' + c.namespace + 'filter', function(){
+ return numberSupported ? $cell.find('input[type="hidden"]') : $('
');
+ },
+
+ /**********************\
+ HTML5 range slider
+ \**********************/
+ html5Range : function($cell, indx, def5Range) {
+ var o = $.extend({
+ value : 0,
+ min : 0,
+ max : 100,
+ step : 1,
+ delayed : true,
+ valueToHeader : true,
+ exactMatch : true,
+ cellText : '',
+ compare : '',
+ allText : 'all',
+ skipTest : false
+ }, def5Range),
+
+ $input,
+ // test browser for HTML5 range support
+ $range = $('
').appendTo($cell),
+ // test if HTML5 range is supported - from Modernizr (but I left out the method to detect in Safari 2-4)
+ // see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/inputtypes.js
+ rangeSupported = o.skipTest || $range.attr('type') === 'range' && $range.val() !== 'test',
+ $shcell = [],
+ c = $cell.closest('table')[0].config,
+
+ updateRange = function(v, delayed, notrigger){
/*jshint eqeqeq:false */
- var v = this.value,
- compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '';
- if (v !== this.lastValue) {
- this.lastValue = ( compare ? compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) );
- this.value = this.lastValue;
- updateRange( v );
+ // hidden input changes may include compare symbols
+ v = ( typeof v === 'undefined' ? $input.val() : v ).toString().replace(/[<>=]/g, '') || o.value;
+ var compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
+ t = ' (' + (compare ? compare + v : v == o.min ? o.allText : v) + ')',
+ searchType = c.$table[0].hasInitialized ? (delayed ? delayed : o.delayed) || '' : true;
+ $cell.find('input[type=hidden]')
+ // add equal to the beginning, so we filter exact numbers
+ .val( ( compare ? compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) ) )
+ // ( val == o.min ? '' : val + (o.exactMatch ? '=' : ''))
+ .trigger( notrigger ? '' : 'search', searchType ).end()
+ .find('.range').val(v);
+ // or add current value to the header cell, if desired
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t);
+ // update sticky header cell
+ if ($shcell.length) {
+ $shcell
+ .find('.range').val(v).end()
+ .find(compareSelect).val( compare );
+ $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t);
}
- });
+ };
+ $range.remove();
- $cell.find('.range').bind('change', function(){
- updateRange( this.value );
- });
-
- // update spinner from hidden input, in case of saved filters
- c.$table.bind('filterFomatterUpdate', function(){
- var val = tsff.updateCompare($cell, $input, o)[0];
- $cell.find('.range').val( val );
- updateRange(val, false, true);
- ts.filter.formatterUpdated($cell, indx);
- });
-
- if (o.compare) {
- // add compare select
- tsff.addCompare($cell, indx, o);
- $cell.find(compareSelect).bind('change', function(){
- updateRange();
+ if (rangeSupported) {
+ // add HTML5 range
+ $cell
+ .html('
')
+ .closest('thead').find('th[data-column=' + indx + ']')
+ .addClass('filter-parsed') // get exact numbers from column
+ // add span to header for the current slider value
+ .find('.tablesorter-header-inner').append('
');
+ // hidden filter update namespace trigger by filter widget
+ $input = $cell.find('input[type=hidden]').bind('change' + c.namespace + 'filter', function(){
+ /*jshint eqeqeq:false */
+ var v = this.value,
+ compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '';
+ if (v !== this.lastValue) {
+ this.lastValue = ( compare ? compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) );
+ this.value = this.lastValue;
+ updateRange( v );
+ }
});
- }
- // has sticky headers?
- c.$table.bind('stickyHeadersInit', function(){
- $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
- $shcell
- .html('
')
- .find('.range').bind('change', function(){
- updateRange( $shcell.find('.range').val() );
- });
- updateRange();
+ $cell.find('.range').bind('change', function(){
+ updateRange( this.value );
+ });
+
+ // update spinner from hidden input, in case of saved filters
+ c.$table.bind('filterFomatterUpdate', function(){
+ var val = tsff.updateCompare($cell, $input, o)[0];
+ $cell.find('.range').val( val );
+ updateRange(val, false, true);
+ ts.filter.formatterUpdated($cell, indx);
+ });
if (o.compare) {
// add compare select
- tsff.addCompare($shcell, indx, o);
- $shcell.find(compareSelect).bind('change', function(){
- $cell.find(compareSelect).val( $(this).val() );
+ tsff.addCompare($cell, indx, o);
+ $cell.find(compareSelect).bind('change', function(){
updateRange();
});
}
- });
+ // has sticky headers?
+ c.$table.bind('stickyHeadersInit', function(){
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
+ $shcell
+ .html('
')
+ .find('.range').bind('change', function(){
+ updateRange( $shcell.find('.range').val() );
+ });
+ updateRange();
- // on reset
- $cell.closest('table').bind('filterReset', function(){
- if ($.isArray(o.compare)) {
- $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
- }
- setTimeout(function(){
- updateRange(o.value, false, true);
- }, 0);
- });
- updateRange();
+ if (o.compare) {
+ // add compare select
+ tsff.addCompare($shcell, indx, o);
+ $shcell.find(compareSelect).bind('change', function(){
+ $cell.find(compareSelect).val( $(this).val() );
+ updateRange();
+ });
+ }
- }
+ });
- return rangeSupported ? $cell.find('input[type="hidden"]') : $('
');
- },
+ // on reset
+ $cell.closest('table').bind('filterReset', function(){
+ if ($.isArray(o.compare)) {
+ $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
+ }
+ setTimeout(function(){
+ updateRange(o.value, false, true);
+ }, 0);
+ });
+ updateRange();
- /**********************\
- HTML5 Color picker
- \**********************/
- html5Color: function($cell, indx, defColor) {
- var t, o = $.extend({
- value : '#000000',
- disabled : false,
- addToggle : true,
- exactMatch : true,
- valueToHeader : false,
- skipTest : false
- }, defColor),
- $input,
- // Add a hidden input to hold the range values
- $color = $('
').appendTo($cell),
- // test if HTML5 color is supported - from Modernizr
- colorSupported = o.skipTest || $color.attr('type') === 'color' && $color.val() !== 'test',
- $shcell = [],
- c = $cell.closest('table')[0].config,
-
- updateColor = function(v, notrigger){
- v = ( typeof v === "undefined" ? $input.val() : v ).toString().replace('=','') || o.value;
- var chkd = true,
- t = ' (' + v + ')';
- if (o.addToggle) {
- chkd = $cell.find('.toggle').is(':checked');
- }
- if ($cell.find('.colorpicker').length) {
- $cell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd);
}
- $input
- .val( chkd ? v + (o.exactMatch ? '=' : '') : '' )
- .trigger( !c.$table[0].hasInitialized || notrigger ? '' : 'search' );
- if (o.valueToHeader) {
- // add current color to the header cell
- $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t);
- } else {
- // current color to span in cell
- $cell.find('.currentColor').html(t);
- }
+ return rangeSupported ? $cell.find('input[type="hidden"]') : $('
');
+ },
- // update sticky header cell
- if ($shcell.length) {
- $shcell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd);
+ /**********************\
+ HTML5 Color picker
+ \**********************/
+ html5Color: function($cell, indx, defColor) {
+ var t, o = $.extend({
+ value : '#000000',
+ disabled : false,
+ addToggle : true,
+ exactMatch : true,
+ valueToHeader : false,
+ skipTest : false
+ }, defColor),
+ $input,
+ // Add a hidden input to hold the range values
+ $color = $('
').appendTo($cell),
+ // test if HTML5 color is supported - from Modernizr
+ colorSupported = o.skipTest || $color.attr('type') === 'color' && $color.val() !== 'test',
+ $shcell = [],
+ c = $cell.closest('table')[0].config,
+
+ updateColor = function(v, notrigger) {
+ v = ( typeof v === 'undefined' ? $input.val() : v ).toString().replace('=', '') || o.value;
+ var chkd = true,
+ t = ' (' + v + ')';
if (o.addToggle) {
- $shcell.find('.toggle')[0].checked = chkd;
+ chkd = $cell.find('.toggle').is(':checked');
}
+ if ($cell.find('.colorpicker').length) {
+ $cell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd);
+ }
+
+ $input
+ .val( chkd ? v + (o.exactMatch ? '=' : '') : '' )
+ .trigger( !c.$table[0].hasInitialized || notrigger ? '' : 'search' );
if (o.valueToHeader) {
// add current color to the header cell
- $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t);
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t);
} else {
// current color to span in cell
- $shcell.find('.currentColor').html(t);
+ $cell.find('.currentColor').html(t);
}
- }
- };
- $color.remove();
- if (colorSupported) {
- t = '' + indx + Math.round(Math.random() * 100);
- // add HTML5 color picker
- t = '
';
- $cell.html(t);
- // add span to header for the current color value - only works if the line in the updateColor() function is also un-commented out
- if (o.valueToHeader) {
- $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append('
');
- }
-
- $cell.find('.toggle, .colorpicker').bind('change', function(){
- updateColor( $cell.find('.colorpicker').val() );
- });
-
- // hidden filter update namespace trigger by filter widget
- $input = $cell.find('input[type=hidden]').bind('change' + c.namespace + 'filter', function(){
- updateColor( this.value );
- });
-
- // update slider from hidden input, in case of saved filters
- c.$table.bind('filterFomatterUpdate', function(){
- updateColor( $input.val(), true );
- ts.filter.formatterUpdated($cell, indx);
- });
-
- // on reset
- $cell.closest('table').bind('filterReset', function(){
- // just turn off the colorpicker
- if (o.addToggle) {
- $cell.find('.toggle')[0].checked = false;
+ // update sticky header cell
+ if ($shcell.length) {
+ $shcell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd);
+ if (o.addToggle) {
+ $shcell.find('.toggle')[0].checked = chkd;
+ }
+ if (o.valueToHeader) {
+ // add current color to the header cell
+ $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t);
+ } else {
+ // current color to span in cell
+ $shcell.find('.currentColor').html(t);
+ }
}
- // delay needed because default color needs to be set in the filter
- // there is no compare option here, so if addToggle = false,
- // default color is #000000 (even with no value set)
- setTimeout(function(){
- updateColor();
- }, 0);
- });
+ };
+ $color.remove();
- // has sticky headers?
- c.$table.bind('stickyHeadersInit', function(){
- $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx);
- $shcell
- .html(t)
- .find('.toggle, .colorpicker').bind('change', function(){
- updateColor( $shcell.find('.colorpicker').val() );
- });
- updateColor( $shcell.find('.colorpicker').val() );
- });
+ if (colorSupported) {
+ t = '' + indx + Math.round(Math.random() * 100);
+ // add HTML5 color picker
+ t = '
';
+ $cell.html(t);
+ // add span to header for the current color value - only works if the line in the updateColor() function is also un-commented out
+ if (o.valueToHeader) {
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append('
');
+ }
- updateColor( o.value );
+ $cell.find('.toggle, .colorpicker').bind('change', function(){
+ updateColor( $cell.find('.colorpicker').val() );
+ });
+
+ // hidden filter update namespace trigger by filter widget
+ $input = $cell.find('input[type=hidden]').bind('change' + c.namespace + 'filter', function(){
+ updateColor( this.value );
+ });
+
+ // update slider from hidden input, in case of saved filters
+ c.$table.bind('filterFomatterUpdate', function(){
+ updateColor( $input.val(), true );
+ ts.filter.formatterUpdated($cell, indx);
+ });
+
+ // on reset
+ $cell.closest('table').bind('filterReset', function(){
+ // just turn off the colorpicker
+ if (o.addToggle) {
+ $cell.find('.toggle')[0].checked = false;
+ }
+ // delay needed because default color needs to be set in the filter
+ // there is no compare option here, so if addToggle = false,
+ // default color is #000000 (even with no value set)
+ setTimeout(function(){
+ updateColor();
+ }, 0);
+ });
+
+ // has sticky headers?
+ c.$table.bind('stickyHeadersInit', function(){
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx);
+ $shcell
+ .html(t)
+ .find('.toggle, .colorpicker').bind('change', function(){
+ updateColor( $shcell.find('.colorpicker').val() );
+ });
+ updateColor( $shcell.find('.colorpicker').val() );
+ });
+
+ updateColor( o.value );
+ }
+ return colorSupported ? $cell.find('input[type="hidden"]') : $('
');
}
- return colorSupported ? $cell.find('input[type="hidden"]') : $('
');
- }
-});
+ });
})(jQuery);
diff --git a/js/widgets/widget-filter-formatter-jui.js b/js/widgets/widget-filter-formatter-jui.js
index 00ee4612..6ba2a65c 100644
--- a/js/widgets/widget-filter-formatter-jui.js
+++ b/js/widgets/widget-filter-formatter-jui.js
@@ -10,755 +10,755 @@
/*jshint browser:true, jquery:true, unused:false */
/*global jQuery: false */
;(function($){
-"use strict";
+ 'use strict';
-var ts = $.tablesorter || {},
+ var ts = $.tablesorter || {},
-// compare option selector class name (jQuery selector)
-compareSelect = '.compare-select',
+ // compare option selector class name (jQuery selector)
+ compareSelect = '.compare-select',
-tsff = ts.filterFormatter = $.extend( {}, ts.filterFormatter, {
+ tsff = ts.filterFormatter = $.extend( {}, ts.filterFormatter, {
- addCompare: function($cell, indx, options){
- if (options.compare && $.isArray(options.compare) && options.compare.length > 1) {
- var opt = '',
- compareSelectClass = [ compareSelect.slice(1), ' ' + compareSelect.slice(1), '' ],
- txt = options.cellText ? '
' : '';
- $.each(options.compare, function(i, c){
- opt += '
';
- });
- $cell
- .wrapInner('
')
- .prepend( txt + '
' )
- .find('select')
- .append(opt);
- }
- },
-
- updateCompare : function($cell, $input, o) {
- var val = $input.val() || '',
- num = val.replace(/\s*?[><=]\s*?/g, ''),
- compare = val.match(/[><=]/g) || '';
- if (o.compare) {
- if ($.isArray(o.compare)){
- compare = (compare || []).join('') || o.compare[o.selected || 0];
- }
- $cell.find(compareSelect).val( compare );
- }
- return [ val, num ];
- },
-
- /**********************\
- jQuery UI Spinner
- \**********************/
- uiSpinner: function($cell, indx, spinnerDef) {
- var o = $.extend({
- // filter formatter options
- delayed : true,
- addToggle : true,
- exactMatch : true,
- value : 1,
- cellText : '',
- compare : '',
- // include ANY jQuery UI spinner options below
- min : 0,
- max : 100,
- step : 1,
- disabled : false
-
- }, spinnerDef ),
- c = $cell.closest('table')[0].config,
- // Add a hidden input to hold the range values
- $input = $('
')
- .appendTo($cell)
- // hidden filter update namespace trigger by filter widget
- .bind('change' + c.namespace + 'filter', function(){
- updateSpinner({ value: this.value, delayed: false });
- }),
- $shcell = [],
-
- // this function updates the hidden input and adds the current values to the header cell text
- updateSpinner = function(ui, notrigger) {
- var chkd = true, state,
- // ui is not undefined on create
- v = ui && ui.value && ts.formatFloat((ui.value + '').replace(/[><=]/g,'')) ||
- $cell.find('.spinner').val() || o.value,
- compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
- searchType = ui && typeof ui.delayed === 'boolean' ? ui.delayed : c.$table[0].hasInitialized ? o.delayed || '' : true;
- if (o.addToggle) {
- chkd = $cell.find('.toggle').is(':checked');
- }
- state = o.disabled || !chkd ? 'disable' : 'enable';
- $cell.find('.filter')
- // add equal to the beginning, so we filter exact numbers
- .val( chkd ? (compare ? compare : o.exactMatch ? '=' : '') + v : '' )
- .trigger( notrigger ? '' : 'search', searchType ).end()
- .find('.spinner').spinner(state).val(v);
- // update sticky header cell
- if ($shcell.length) {
- $shcell
- .find('.spinner').spinner(state).val(v).end()
- .find(compareSelect).val( compare );
- if (o.addToggle) {
- $shcell.find('.toggle')[0].checked = chkd;
- }
- }
- };
-
- // add callbacks; preserve added callbacks
- o.oldcreate = o.create;
- o.oldspin = o.spin;
- o.create = function(event, ui) {
- updateSpinner(); // ui is an empty object on create
- if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); }
- };
- o.spin = function(event, ui) {
- updateSpinner(ui);
- if (typeof o.oldspin === 'function') { o.oldspin(event, ui); }
- };
- if (o.addToggle) {
- $('
' +
- '
')
- .appendTo($cell)
- .find('.toggle')
- .bind('change', function(){
- updateSpinner();
+ addCompare: function($cell, indx, options){
+ if (options.compare && $.isArray(options.compare) && options.compare.length > 1) {
+ var opt = '',
+ compareSelectClass = [ compareSelect.slice(1), ' ' + compareSelect.slice(1), '' ],
+ txt = options.cellText ? '
' : '';
+ $.each(options.compare, function(i, c){
+ opt += '
';
});
- }
- // make sure we use parsed data
- $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
- // add a jQuery UI spinner!
- $('
')
- .val(o.value)
- .appendTo($cell)
- .spinner(o)
- .bind('change keyup', function(){
- updateSpinner();
- });
-
- // update spinner from hidden input, in case of saved filters
- c.$table.bind('filterFomatterUpdate', function(){
- var val = tsff.updateCompare($cell, $input, o)[0];
- $cell.find('.spinner').val( val );
- updateSpinner({ value: val }, true);
- ts.filter.formatterUpdated($cell, indx);
- });
-
- if (o.compare) {
- // add compare select
- tsff.addCompare($cell, indx, o);
- $cell.find(compareSelect).bind('change', function(){
- updateSpinner();
- });
- }
-
- // has sticky headers?
- c.$table.bind('stickyHeadersInit', function(){
- $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
- if (o.addToggle) {
- $('
' +
- '
')
- .appendTo($shcell)
- .find('.toggle')
- .bind('change', function(){
- $cell.find('.toggle')[0].checked = this.checked;
- updateSpinner();
- });
- }
- // add a jQuery UI spinner!
- $('
')
- .val(o.value)
- .appendTo($shcell)
- .spinner(o)
- .bind('change keyup', function(){
- $cell.find('.spinner').val( this.value );
- updateSpinner();
- });
-
- if (o.compare) {
- // add compare select
- tsff.addCompare($shcell, indx, o);
- $shcell.find(compareSelect).bind('change', function(){
- $cell.find(compareSelect).val( $(this).val() );
- updateSpinner();
- });
- }
-
- });
-
- // on reset
- c.$table.bind('filterReset', function(){
- if ($.isArray(o.compare)) {
- $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
- }
- // turn off the toggle checkbox
- if (o.addToggle) {
- $cell.find('.toggle')[0].checked = false;
- }
- $cell.find('.spinner').spinner('value', o.value);
- setTimeout(function(){
- updateSpinner();
- }, 0);
- });
-
- updateSpinner();
- return $input;
- },
-
- /**********************\
- jQuery UI Slider
- \**********************/
- uiSlider: function($cell, indx, sliderDef) {
- var o = $.extend({
- // filter formatter options
- delayed : true,
- valueToHeader : false,
- exactMatch : true,
- cellText : '',
- compare : '',
- allText : 'all',
- // include ANY jQuery UI spinner options below
- // except values, since this is a non-range setup
- value : 0,
- min : 0,
- max : 100,
- step : 1,
- range : "min"
- }, sliderDef ),
- c = $cell.closest('table')[0].config,
- // Add a hidden input to hold the range values
- $input = $('
')
- .appendTo($cell)
- // hidden filter update namespace trigger by filter widget
- .bind('change' + c.namespace + 'filter', function(){
- updateSlider({ value: this.value });
- }),
- $shcell = [],
-
- // this function updates the hidden input and adds the current values to the header cell text
- updateSlider = function(ui, notrigger) {
- // ui is not undefined on create
- var v = typeof ui !== "undefined" ? ts.formatFloat((ui.value + '').replace(/[><=]/g,'')) || o.value : o.value,
- val = o.compare ? v : v === o.min ? o.allText : v,
- compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
- result = compare + val,
- searchType = ui && typeof ui.delayed === 'boolean' ? ui.delayed : c.$table[0].hasInitialized ? o.delayed || '' : true;
- if (o.valueToHeader) {
- // add range indication to the header cell above!
- $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(' (' + result + ')');
- } else {
- // add values to the handle data-value attribute so the css tooltip will work properly
- $cell.find('.ui-slider-handle').addClass('value-popup').attr('data-value', result);
- }
- // update the hidden input;
- // ****** ADD AN EQUAL SIGN TO THE BEGINNING! <- this makes the slide exactly match the number ******
- // when the value is at the minimum, clear the hidden input so all rows will be seen
-
- $cell.find('.filter')
- .val( ( compare ? compare + v : v === o.min ? '' : (o.exactMatch ? '=' : '') + v ) )
- .trigger( notrigger ? '' : 'search', searchType ).end()
- .find('.slider').slider('value', v);
-
- // update sticky header cell
- if ($shcell.length) {
- $shcell
- .find(compareSelect).val( compare ).end()
- .find('.slider').slider('value', v);
- if (o.valueToHeader) {
- $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(' (' + result + ')');
- } else {
- $shcell.find('.ui-slider-handle').addClass('value-popup').attr('data-value', result);
- }
- }
-
- };
- $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
-
- // add span to header for value - only works if the line in the updateSlider() function is also un-commented out
- if (o.valueToHeader) {
- $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append('
');
- }
-
- // add callbacks; preserve added callbacks
- o.oldcreate = o.create;
- o.oldslide = o.slide;
- o.create = function(event, ui) {
- updateSlider(); // ui is an empty object on create
- if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); }
- };
- o.slide = function(event, ui) {
- updateSlider(ui);
- if (typeof o.oldslide === 'function') { o.oldslide(event, ui); }
- };
- // add a jQuery UI slider!
- $('
')
- .appendTo($cell)
- .slider(o);
-
- // update slider from hidden input, in case of saved filters
- c.$table.bind('filterFomatterUpdate', function(){
- var val = tsff.updateCompare($cell, $input, o)[0];
- $cell.find('.slider').slider('value', val );
- updateSlider({ value: val }, false);
- ts.filter.formatterUpdated($cell, indx);
- });
-
- if (o.compare) {
- // add compare select
- tsff.addCompare($cell, indx, o);
- $cell.find(compareSelect).bind('change', function(){
- updateSlider({ value: $cell.find('.slider').slider('value') });
- });
- }
-
- // on reset
- c.$table.bind('filterReset', function(){
- if ($.isArray(o.compare)) {
- $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
- }
- setTimeout(function(){
- updateSlider({ value: o.value });
- }, 0);
- });
-
- // has sticky headers?
- c.$table.bind('stickyHeadersInit', function(){
- $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
-
- // add a jQuery UI slider!
- $('
')
- .val(o.value)
- .appendTo($shcell)
- .slider(o)
- .bind('change keyup', function(){
- $cell.find('.slider').slider('value', this.value );
- updateSlider();
- });
-
- if (o.compare) {
- // add compare select
- tsff.addCompare($shcell, indx, o);
- $shcell.find(compareSelect).bind('change', function(){
- $cell.find(compareSelect).val( $(this).val() );
- updateSlider();
- });
- }
-
- });
-
- return $input;
- },
-
- /*************************\
- jQuery UI Range Slider (2 handles)
- \*************************/
- uiRange: function($cell, indx, rangeDef) {
- var o = $.extend({
- // filter formatter options
- delayed : true,
- valueToHeader : false,
- // include ANY jQuery UI spinner options below
- // except value, since this one is range specific)
- values : [0, 100],
- min : 0,
- max : 100,
- range : true
- }, rangeDef ),
- c = $cell.closest('table')[0].config,
- // Add a hidden input to hold the range values
- $input = $('
')
- .appendTo($cell)
- // hidden filter update namespace trigger by filter widget
- .bind('change' + c.namespace + 'filter', function(){
- getRange();
- }),
- $shcell = [],
-
- getRange = function(){
- var val = $input.val(),
- v = val.split(' - ');
- if (val === '') { v = [ o.min, o.max ]; }
- if (v && v[1]) {
- updateUiRange({ values: v, delay: false }, true);
+ $cell
+ .wrapInner('
')
+ .prepend( txt + '
' )
+ .find('select')
+ .append(opt);
}
},
- // this function updates the hidden input and adds the current values to the header cell text
- updateUiRange = function(ui, notrigger) {
- // ui.values are undefined for some reason on create
- var val = ui && ui.values || o.values,
- result = val[0] + ' - ' + val[1],
- // make range an empty string if entire range is covered so the filter row will hide (if set)
- range = val[0] === o.min && val[1] === o.max ? '' : result,
- searchType = ui && typeof ui.delayed === 'boolean' ? ui.delayed : c.$table[0].hasInitialized ? o.delayed || '': true;
- if (o.valueToHeader) {
- // add range indication to the header cell above (if not using the css method)!
- $cell.closest('thead').find('th[data-column=' + indx + ']').find('.currange').html(' (' + result + ')');
- } else {
- // add values to the handle data-value attribute so the css tooltip will work properly
- $cell.find('.ui-slider-handle')
- .addClass('value-popup')
- .eq(0).attr('data-value', val[0]).end() // adding value to data attribute
- .eq(1).attr('data-value', val[1]); // value popup shown via css
- }
- // update the hidden input
- $cell.find('.filter').val(range)
- .trigger(notrigger ? '' : 'search', searchType).end()
- .find('.range').slider('values', val);
- // update sticky header cell
- if ($shcell.length) {
- $shcell.find('.range').slider('values', val);
- if (o.valueToHeader) {
- $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.currange').html(' (' + result + ')');
- } else {
- $shcell.find('.ui-slider-handle')
- .addClass('value-popup')
- .eq(0).attr('data-value', val[0]).end() // adding value to data attribute
- .eq(1).attr('data-value', val[1]); // value popup shown via css
+ updateCompare : function($cell, $input, o) {
+ var val = $input.val() || '',
+ num = val.replace(/\s*?[><=]\s*?/g, ''),
+ compare = val.match(/[><=]/g) || '';
+ if (o.compare) {
+ if ($.isArray(o.compare)){
+ compare = (compare || []).join('') || o.compare[o.selected || 0];
}
+ $cell.find(compareSelect).val( compare );
}
+ return [ val, num ];
+ },
- };
- $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
+ /**********************\
+ jQuery UI Spinner
+ \**********************/
+ uiSpinner: function($cell, indx, spinnerDef) {
+ var o = $.extend({
+ // filter formatter options
+ delayed : true,
+ addToggle : true,
+ exactMatch : true,
+ value : 1,
+ cellText : '',
+ compare : '',
+ // include ANY jQuery UI spinner options below
+ min : 0,
+ max : 100,
+ step : 1,
+ disabled : false
- // add span to header for value - only works if the line in the updateUiRange() function is also un-commented out
- if (o.valueToHeader) {
- $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append('
');
- }
+ }, spinnerDef ),
+ c = $cell.closest('table')[0].config,
+ // Add a hidden input to hold the range values
+ $input = $('
')
+ .appendTo($cell)
+ // hidden filter update namespace trigger by filter widget
+ .bind('change' + c.namespace + 'filter', function(){
+ updateSpinner({ value: this.value, delayed: false });
+ }),
+ $shcell = [],
- // add callbacks; preserve added callbacks
- o.oldcreate = o.create;
- o.oldslide = o.slide;
- // add a jQuery UI range slider!
- o.create = function(event, ui) {
- updateUiRange(); // ui is an empty object on create
- if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); }
- };
- o.slide = function(event, ui) {
- updateUiRange(ui);
- if (typeof o.oldslide === 'function') { o.oldslide(event, ui); }
- };
- $('
')
- .appendTo($cell)
- .slider(o);
-
- // update slider from hidden input, in case of saved filters
- c.$table.bind('filterFomatterUpdate', function(){
- getRange();
- ts.filter.formatterUpdated($cell, indx);
- });
-
- // on reset
- c.$table.bind('filterReset', function(){
- $cell.find('.range').slider('values', o.values);
- setTimeout(function(){
- updateUiRange();
- }, 0);
- });
-
- // has sticky headers?
- c.$table.bind('stickyHeadersInit', function(){
- $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
-
- // add a jQuery UI slider!
- $('
')
- .val(o.value)
- .appendTo($shcell)
- .slider(o)
- .bind('change keyup', function(){
- $cell.find('.range').val( this.value );
- updateUiRange();
- });
-
- });
-
- // return the hidden input so the filter widget has a reference to it
- return $input;
- },
-
- /*************************\
- jQuery UI Datepicker compare (1 input)
- \*************************/
- uiDateCompare: function($cell, indx, defDate) {
- var o = $.extend({
- // filter formatter options
- cellText : '',
- compare : '',
- endOfDay : true,
- // include ANY jQuery UI spinner options below
-
- defaultDate : '',
-
- changeMonth : true,
- changeYear : true,
- numberOfMonths : 1
- }, defDate),
-
- $date,
- c = $cell.closest('table')[0].config,
- // make sure we're using parsed dates in the search
- $hdr = $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed'),
- // Add a hidden input to hold the range values
- $input = $('
')
- .appendTo($cell)
- // hidden filter update namespace trigger by filter widget
- .bind('change' + c.namespace + 'filter', function(){
- var v = this.value;
- if (v) {
- o.onClose(v);
+ // this function updates the hidden input and adds the current values to the header cell text
+ updateSpinner = function(ui, notrigger) {
+ var chkd = true, state,
+ // ui is not undefined on create
+ v = ui && ui.value && ts.formatFloat((ui.value + '').replace(/[><=]/g, '')) ||
+ $cell.find('.spinner').val() || o.value,
+ compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
+ searchType = ui && typeof ui.delayed === 'boolean' ? ui.delayed : c.$table[0].hasInitialized ? o.delayed || '' : true;
+ if (o.addToggle) {
+ chkd = $cell.find('.toggle').is(':checked');
}
- }),
- t, $shcell = [],
+ state = o.disabled || !chkd ? 'disable' : 'enable';
+ $cell.find('.filter')
+ // add equal to the beginning, so we filter exact numbers
+ .val( chkd ? (compare ? compare : o.exactMatch ? '=' : '') + v : '' )
+ .trigger( notrigger ? '' : 'search', searchType ).end()
+ .find('.spinner').spinner(state).val(v);
+ // update sticky header cell
+ if ($shcell.length) {
+ $shcell
+ .find('.spinner').spinner(state).val(v).end()
+ .find(compareSelect).val( compare );
+ if (o.addToggle) {
+ $shcell.find('.toggle')[0].checked = chkd;
+ }
+ }
+ };
- // this function updates the hidden input
- date1Compare = function(notrigger) {
- var date, query,
- getdate = $date.datepicker('getDate') || '',
- compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
- searchType = c.$table[0].hasInitialized ? o.delayed || '': true;
- $date.datepicker('setDate', (getdate === '' ? '' : getdate) || null);
- if (getdate === '') { notrigger = false; }
- date = $date.datepicker('getDate');
- query = date ? ( o.endOfDay && /<=/.test(compare) ? date.setHours(23, 59, 59) : date.getTime() ) || '' : '';
- if (date && o.endOfDay && compare === '=') {
- compare = '';
- query += ' - ' + date.setHours(23, 59, 59);
- notrigger = false;
+ // add callbacks; preserve added callbacks
+ o.oldcreate = o.create;
+ o.oldspin = o.spin;
+ o.create = function(event, ui) {
+ updateSpinner(); // ui is an empty object on create
+ if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); }
+ };
+ o.spin = function(event, ui) {
+ updateSpinner(ui);
+ if (typeof o.oldspin === 'function') { o.oldspin(event, ui); }
+ };
+ if (o.addToggle) {
+ $('
' +
+ '
')
+ .appendTo($cell)
+ .find('.toggle')
+ .bind('change', function(){
+ updateSpinner();
+ });
}
- $cell.find('.dateCompare')
- // add equal to the beginning, so we filter exact numbers
- .val(compare + query)
- .trigger( notrigger ? '' : 'search', searchType ).end();
- // update sticky header cell
- if ($shcell.length) {
- $shcell
- .find('.dateCompare').val(compare + query).end()
- .find(compareSelect).val(compare);
- }
- };
+ // make sure we use parsed data
+ $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
+ // add a jQuery UI spinner!
+ $('
')
+ .val(o.value)
+ .appendTo($cell)
+ .spinner(o)
+ .bind('change keyup', function(){
+ updateSpinner();
+ });
- // Add date range picker
- t = '
';
- $date = $(t).appendTo($cell);
-
- // add callbacks; preserve added callbacks
- o.oldonClose = o.onClose;
-
- o.onClose = function( selectedDate, ui ) {
- date1Compare();
- if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); }
- };
- $date.datepicker(o);
-
- // on reset
- c.$table.bind('filterReset', function(){
- if ($.isArray(o.compare)) {
- $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
- }
- $cell.add($shcell).find('.date').val(o.defaultDate).datepicker('setDate', o.defaultDate || null);
- setTimeout(function(){
- date1Compare();
- }, 0);
- });
-
- // update date compare from hidden input, in case of saved filters
- c.$table.bind('filterFomatterUpdate', function(){
- var num, v = $input.val();
- if (/\s+-\s+/.test(v)) {
- // date range found; assume an exact match on one day
- $cell.find(compareSelect).val('=');
- num = v.split(/\s+-\s+/)[0];
- $date.datepicker( 'setDate', num || null );
- } else {
- num = (tsff.updateCompare($cell, $input, o)[1]).toString() || '';
- // differeniate 1388556000000 from 1/1/2014 using \d{5} regex
- num = num !== '' ? /\d{5}/g.test(num) ? new Date(Number(num)) : num || '' : '';
- }
- $cell.add($shcell).find('.date').datepicker( 'setDate', num || null );
- setTimeout(function(){
- date1Compare(true);
+ // update spinner from hidden input, in case of saved filters
+ c.$table.bind('filterFomatterUpdate', function(){
+ var val = tsff.updateCompare($cell, $input, o)[0];
+ $cell.find('.spinner').val( val );
+ updateSpinner({ value: val }, true);
ts.filter.formatterUpdated($cell, indx);
- }, 0);
- });
-
- if (o.compare) {
- // add compare select
- tsff.addCompare($cell, indx, o);
- $cell.find(compareSelect).bind('change', function(){
- date1Compare();
});
- }
-
- // has sticky headers?
- c.$table.bind('stickyHeadersInit', function(){
- $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
-
- // add a jQuery datepicker!
- $shcell
- .append(t)
- .find('.date')
- .datepicker(o);
if (o.compare) {
// add compare select
- tsff.addCompare($shcell, indx, o);
- $shcell.find(compareSelect).bind('change', function(){
- $cell.find(compareSelect).val( $(this).val() );
+ tsff.addCompare($cell, indx, o);
+ $cell.find(compareSelect).bind('change', function(){
+ updateSpinner();
+ });
+ }
+
+ // has sticky headers?
+ c.$table.bind('stickyHeadersInit', function(){
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
+ if (o.addToggle) {
+ $('
' +
+ '
')
+ .appendTo($shcell)
+ .find('.toggle')
+ .bind('change', function(){
+ $cell.find('.toggle')[0].checked = this.checked;
+ updateSpinner();
+ });
+ }
+ // add a jQuery UI spinner!
+ $('
')
+ .val(o.value)
+ .appendTo($shcell)
+ .spinner(o)
+ .bind('change keyup', function(){
+ $cell.find('.spinner').val( this.value );
+ updateSpinner();
+ });
+
+ if (o.compare) {
+ // add compare select
+ tsff.addCompare($shcell, indx, o);
+ $shcell.find(compareSelect).bind('change', function(){
+ $cell.find(compareSelect).val( $(this).val() );
+ updateSpinner();
+ });
+ }
+
+ });
+
+ // on reset
+ c.$table.bind('filterReset', function(){
+ if ($.isArray(o.compare)) {
+ $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
+ }
+ // turn off the toggle checkbox
+ if (o.addToggle) {
+ $cell.find('.toggle')[0].checked = false;
+ }
+ $cell.find('.spinner').spinner('value', o.value);
+ setTimeout(function(){
+ updateSpinner();
+ }, 0);
+ });
+
+ updateSpinner();
+ return $input;
+ },
+
+ /**********************\
+ jQuery UI Slider
+ \**********************/
+ uiSlider: function($cell, indx, sliderDef) {
+ var o = $.extend({
+ // filter formatter options
+ delayed : true,
+ valueToHeader : false,
+ exactMatch : true,
+ cellText : '',
+ compare : '',
+ allText : 'all',
+ // include ANY jQuery UI spinner options below
+ // except values, since this is a non-range setup
+ value : 0,
+ min : 0,
+ max : 100,
+ step : 1,
+ range : 'min'
+ }, sliderDef ),
+ c = $cell.closest('table')[0].config,
+ // Add a hidden input to hold the range values
+ $input = $('
')
+ .appendTo($cell)
+ // hidden filter update namespace trigger by filter widget
+ .bind('change' + c.namespace + 'filter', function(){
+ updateSlider({ value: this.value });
+ }),
+ $shcell = [],
+
+ // this function updates the hidden input and adds the current values to the header cell text
+ updateSlider = function(ui, notrigger) {
+ // ui is not undefined on create
+ var v = typeof ui !== 'undefined' ? ts.formatFloat((ui.value + '').replace(/[><=]/g, '')) || o.value : o.value,
+ val = o.compare ? v : v === o.min ? o.allText : v,
+ compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
+ result = compare + val,
+ searchType = ui && typeof ui.delayed === 'boolean' ? ui.delayed : c.$table[0].hasInitialized ? o.delayed || '' : true;
+ if (o.valueToHeader) {
+ // add range indication to the header cell above!
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(' (' + result + ')');
+ } else {
+ // add values to the handle data-value attribute so the css tooltip will work properly
+ $cell.find('.ui-slider-handle').addClass('value-popup').attr('data-value', result);
+ }
+ // update the hidden input;
+ // ****** ADD AN EQUAL SIGN TO THE BEGINNING! <- this makes the slide exactly match the number ******
+ // when the value is at the minimum, clear the hidden input so all rows will be seen
+
+ $cell.find('.filter')
+ .val( ( compare ? compare + v : v === o.min ? '' : (o.exactMatch ? '=' : '') + v ) )
+ .trigger( notrigger ? '' : 'search', searchType ).end()
+ .find('.slider').slider('value', v);
+
+ // update sticky header cell
+ if ($shcell.length) {
+ $shcell
+ .find(compareSelect).val( compare ).end()
+ .find('.slider').slider('value', v);
+ if (o.valueToHeader) {
+ $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(' (' + result + ')');
+ } else {
+ $shcell.find('.ui-slider-handle').addClass('value-popup').attr('data-value', result);
+ }
+ }
+
+ };
+ $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
+
+ // add span to header for value - only works if the line in the updateSlider() function is also un-commented out
+ if (o.valueToHeader) {
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append('
');
+ }
+
+ // add callbacks; preserve added callbacks
+ o.oldcreate = o.create;
+ o.oldslide = o.slide;
+ o.create = function(event, ui) {
+ updateSlider(); // ui is an empty object on create
+ if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); }
+ };
+ o.slide = function(event, ui) {
+ updateSlider(ui);
+ if (typeof o.oldslide === 'function') { o.oldslide(event, ui); }
+ };
+ // add a jQuery UI slider!
+ $('
')
+ .appendTo($cell)
+ .slider(o);
+
+ // update slider from hidden input, in case of saved filters
+ c.$table.bind('filterFomatterUpdate', function(){
+ var val = tsff.updateCompare($cell, $input, o)[0];
+ $cell.find('.slider').slider('value', val );
+ updateSlider({ value: val }, false);
+ ts.filter.formatterUpdated($cell, indx);
+ });
+
+ if (o.compare) {
+ // add compare select
+ tsff.addCompare($cell, indx, o);
+ $cell.find(compareSelect).bind('change', function(){
+ updateSlider({ value: $cell.find('.slider').slider('value') });
+ });
+ }
+
+ // on reset
+ c.$table.bind('filterReset', function(){
+ if ($.isArray(o.compare)) {
+ $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
+ }
+ setTimeout(function(){
+ updateSlider({ value: o.value });
+ }, 0);
+ });
+
+ // has sticky headers?
+ c.$table.bind('stickyHeadersInit', function(){
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
+
+ // add a jQuery UI slider!
+ $('
')
+ .val(o.value)
+ .appendTo($shcell)
+ .slider(o)
+ .bind('change keyup', function(){
+ $cell.find('.slider').slider('value', this.value );
+ updateSlider();
+ });
+
+ if (o.compare) {
+ // add compare select
+ tsff.addCompare($shcell, indx, o);
+ $shcell.find(compareSelect).bind('change', function(){
+ $cell.find(compareSelect).val( $(this).val() );
+ updateSlider();
+ });
+ }
+
+ });
+
+ return $input;
+ },
+
+ /*************************\
+ jQuery UI Range Slider (2 handles)
+ \*************************/
+ uiRange: function($cell, indx, rangeDef) {
+ var o = $.extend({
+ // filter formatter options
+ delayed : true,
+ valueToHeader : false,
+ // include ANY jQuery UI spinner options below
+ // except value, since this one is range specific)
+ values : [ 0, 100 ],
+ min : 0,
+ max : 100,
+ range : true
+ }, rangeDef ),
+ c = $cell.closest('table')[0].config,
+ // Add a hidden input to hold the range values
+ $input = $('
')
+ .appendTo($cell)
+ // hidden filter update namespace trigger by filter widget
+ .bind('change' + c.namespace + 'filter', function(){
+ getRange();
+ }),
+ $shcell = [],
+
+ getRange = function(){
+ var val = $input.val(),
+ v = val.split(' - ');
+ if (val === '') { v = [ o.min, o.max ]; }
+ if (v && v[1]) {
+ updateUiRange({ values: v, delay: false }, true);
+ }
+ },
+
+ // this function updates the hidden input and adds the current values to the header cell text
+ updateUiRange = function(ui, notrigger) {
+ // ui.values are undefined for some reason on create
+ var val = ui && ui.values || o.values,
+ result = val[0] + ' - ' + val[1],
+ // make range an empty string if entire range is covered so the filter row will hide (if set)
+ range = val[0] === o.min && val[1] === o.max ? '' : result,
+ searchType = ui && typeof ui.delayed === 'boolean' ? ui.delayed : c.$table[0].hasInitialized ? o.delayed || '' : true;
+ if (o.valueToHeader) {
+ // add range indication to the header cell above (if not using the css method)!
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.currange').html(' (' + result + ')');
+ } else {
+ // add values to the handle data-value attribute so the css tooltip will work properly
+ $cell.find('.ui-slider-handle')
+ .addClass('value-popup')
+ .eq(0).attr('data-value', val[0]).end() // adding value to data attribute
+ .eq(1).attr('data-value', val[1]); // value popup shown via css
+ }
+ // update the hidden input
+ $cell.find('.filter').val(range)
+ .trigger(notrigger ? '' : 'search', searchType).end()
+ .find('.range').slider('values', val);
+ // update sticky header cell
+ if ($shcell.length) {
+ $shcell.find('.range').slider('values', val);
+ if (o.valueToHeader) {
+ $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.currange').html(' (' + result + ')');
+ } else {
+ $shcell.find('.ui-slider-handle')
+ .addClass('value-popup')
+ .eq(0).attr('data-value', val[0]).end() // adding value to data attribute
+ .eq(1).attr('data-value', val[1]); // value popup shown via css
+ }
+ }
+
+ };
+ $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
+
+ // add span to header for value - only works if the line in the updateUiRange() function is also un-commented out
+ if (o.valueToHeader) {
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append('
');
+ }
+
+ // add callbacks; preserve added callbacks
+ o.oldcreate = o.create;
+ o.oldslide = o.slide;
+ // add a jQuery UI range slider!
+ o.create = function(event, ui) {
+ updateUiRange(); // ui is an empty object on create
+ if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); }
+ };
+ o.slide = function(event, ui) {
+ updateUiRange(ui);
+ if (typeof o.oldslide === 'function') { o.oldslide(event, ui); }
+ };
+ $('
')
+ .appendTo($cell)
+ .slider(o);
+
+ // update slider from hidden input, in case of saved filters
+ c.$table.bind('filterFomatterUpdate', function(){
+ getRange();
+ ts.filter.formatterUpdated($cell, indx);
+ });
+
+ // on reset
+ c.$table.bind('filterReset', function(){
+ $cell.find('.range').slider('values', o.values);
+ setTimeout(function(){
+ updateUiRange();
+ }, 0);
+ });
+
+ // has sticky headers?
+ c.$table.bind('stickyHeadersInit', function(){
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
+
+ // add a jQuery UI slider!
+ $('
')
+ .val(o.value)
+ .appendTo($shcell)
+ .slider(o)
+ .bind('change keyup', function(){
+ $cell.find('.range').val( this.value );
+ updateUiRange();
+ });
+
+ });
+
+ // return the hidden input so the filter widget has a reference to it
+ return $input;
+ },
+
+ /*************************\
+ jQuery UI Datepicker compare (1 input)
+ \*************************/
+ uiDateCompare: function($cell, indx, defDate) {
+ var o = $.extend({
+ // filter formatter options
+ cellText : '',
+ compare : '',
+ endOfDay : true,
+ // include ANY jQuery UI spinner options below
+
+ defaultDate : '',
+
+ changeMonth : true,
+ changeYear : true,
+ numberOfMonths : 1
+ }, defDate),
+
+ $date,
+ c = $cell.closest('table')[0].config,
+ // make sure we're using parsed dates in the search
+ $hdr = $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed'),
+ // Add a hidden input to hold the range values
+ $input = $('
')
+ .appendTo($cell)
+ // hidden filter update namespace trigger by filter widget
+ .bind('change' + c.namespace + 'filter', function(){
+ var v = this.value;
+ if (v) {
+ o.onClose(v);
+ }
+ }),
+ t, $shcell = [],
+
+ // this function updates the hidden input
+ date1Compare = function(notrigger) {
+ var date, query,
+ getdate = $date.datepicker('getDate') || '',
+ compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
+ searchType = c.$table[0].hasInitialized ? o.delayed || '' : true;
+ $date.datepicker('setDate', (getdate === '' ? '' : getdate) || null);
+ if (getdate === '') { notrigger = false; }
+ date = $date.datepicker('getDate');
+ query = date ? ( o.endOfDay && /<=/.test(compare) ? date.setHours(23, 59, 59) : date.getTime() ) || '' : '';
+ if (date && o.endOfDay && compare === '=') {
+ compare = '';
+ query += ' - ' + date.setHours(23, 59, 59);
+ notrigger = false;
+ }
+ $cell.find('.dateCompare')
+ // add equal to the beginning, so we filter exact numbers
+ .val(compare + query)
+ .trigger( notrigger ? '' : 'search', searchType ).end();
+ // update sticky header cell
+ if ($shcell.length) {
+ $shcell
+ .find('.dateCompare').val(compare + query).end()
+ .find(compareSelect).val(compare);
+ }
+ };
+
+ // Add date range picker
+ t = '
';
+ $date = $(t).appendTo($cell);
+
+ // add callbacks; preserve added callbacks
+ o.oldonClose = o.onClose;
+
+ o.onClose = function( selectedDate, ui ) {
+ date1Compare();
+ if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); }
+ };
+ $date.datepicker(o);
+
+ // on reset
+ c.$table.bind('filterReset', function(){
+ if ($.isArray(o.compare)) {
+ $cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
+ }
+ $cell.add($shcell).find('.date').val(o.defaultDate).datepicker('setDate', o.defaultDate || null);
+ setTimeout(function(){
+ date1Compare();
+ }, 0);
+ });
+
+ // update date compare from hidden input, in case of saved filters
+ c.$table.bind('filterFomatterUpdate', function(){
+ var num, v = $input.val();
+ if (/\s+-\s+/.test(v)) {
+ // date range found; assume an exact match on one day
+ $cell.find(compareSelect).val('=');
+ num = v.split(/\s+-\s+/)[0];
+ $date.datepicker( 'setDate', num || null );
+ } else {
+ num = (tsff.updateCompare($cell, $input, o)[1]).toString() || '';
+ // differeniate 1388556000000 from 1/1/2014 using \d{5} regex
+ num = num !== '' ? /\d{5}/g.test(num) ? new Date(Number(num)) : num || '' : '';
+ }
+ $cell.add($shcell).find('.date').datepicker( 'setDate', num || null );
+ setTimeout(function(){
+ date1Compare(true);
+ ts.filter.formatterUpdated($cell, indx);
+ }, 0);
+ });
+
+ if (o.compare) {
+ // add compare select
+ tsff.addCompare($cell, indx, o);
+ $cell.find(compareSelect).bind('change', function(){
date1Compare();
});
}
- });
+ // has sticky headers?
+ c.$table.bind('stickyHeadersInit', function(){
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
- // return the hidden input so the filter widget has a reference to it
- return $input.val( o.defaultDate ? o.defaultDate : '' );
- },
+ // add a jQuery datepicker!
+ $shcell
+ .append(t)
+ .find('.date')
+ .datepicker(o);
- /*************************\
- jQuery UI Datepicker (2 inputs)
- \*************************/
- uiDatepicker: function($cell, indx, defDate) {
- var o = $.extend({
- // filter formatter options
- endOfDay : true,
- textFrom : 'from',
- textTo : 'to',
- from : '', // defaultDate "from" input
- to : '', // defaultDate "to" input
- // include ANY jQuery UI spinner options below
- changeMonth : true,
- changeYear : true,
- numberOfMonths : 1
- }, defDate),
- t, closeDate, $shcell = [],
- c = $cell.closest('table')[0].config,
- validDate = function(d){
- return d instanceof Date && isFinite(d);
- },
- // Add a hidden input to hold the range values
- $input = $('
')
- .appendTo($cell)
- // hidden filter update namespace trigger by filter widget
- .bind('change' + c.namespace + 'filter', function(){
- var v = this.value;
- if (v.match(' - ')) {
- v = v.split(' - ');
- $cell.find('.dateTo').val(v[1]);
- closeDate(v[0]);
- } else if (v.match('>=')) {
- closeDate( v.replace('>=', '') );
- } else if (v.match('<=')) {
- closeDate( v.replace('<=', '') );
+ if (o.compare) {
+ // add compare select
+ tsff.addCompare($shcell, indx, o);
+ $shcell.find(compareSelect).bind('change', function(){
+ $cell.find(compareSelect).val( $(this).val() );
+ date1Compare();
+ });
}
- }),
- // make sure we're using parsed dates in the search
- $hdr = $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
- // Add date range picker
- t = '
' +
- '
';
- $(t).appendTo($cell);
+ });
- // add callbacks; preserve added callbacks
- o.oldonClose = o.onClose;
+ // return the hidden input so the filter widget has a reference to it
+ return $input.val( o.defaultDate ? o.defaultDate : '' );
+ },
- closeDate = o.onClose = function( selectedDate, ui ) {
- var range,
- from = $cell.find('.dateFrom').datepicker('getDate'),
- to = $cell.find('.dateTo').datepicker('getDate');
- from = validDate(from) ? from.getTime() : '';
- to = validDate(to) ? ( o.endOfDay ? to.setHours(23, 59, 59) : to.getTime() ) || '' : '';
- range = from ? ( to ? from + ' - ' + to : '>=' + from ) : (to ? '<=' + to : '');
- $cell.add( $shcell )
- .find('.dateRange').val(range)
- .trigger('search');
- // date picker needs date objects
- from = from ? new Date(from) : '';
- to = to ? new Date(to) : '';
+ /*************************\
+ jQuery UI Datepicker (2 inputs)
+ \*************************/
+ uiDatepicker: function($cell, indx, defDate) {
+ var o = $.extend({
+ // filter formatter options
+ endOfDay : true,
+ textFrom : 'from',
+ textTo : 'to',
+ from : '', // defaultDate 'from' input
+ to : '', // defaultDate 'to' input
+ // include ANY jQuery UI spinner options below
+ changeMonth : true,
+ changeYear : true,
+ numberOfMonths : 1
+ }, defDate),
+ t, closeDate, $shcell = [],
+ c = $cell.closest('table')[0].config,
+ validDate = function(d){
+ return d instanceof Date && isFinite(d);
+ },
+ // Add a hidden input to hold the range values
+ $input = $('
')
+ .appendTo($cell)
+ // hidden filter update namespace trigger by filter widget
+ .bind('change' + c.namespace + 'filter', function(){
+ var v = this.value;
+ if (v.match(' - ')) {
+ v = v.split(' - ');
+ $cell.find('.dateTo').val(v[1]);
+ closeDate(v[0]);
+ } else if (v.match('>=')) {
+ closeDate( v.replace('>=', '') );
+ } else if (v.match('<=')) {
+ closeDate( v.replace('<=', '') );
+ }
+ }),
- if (/<=/.test(range)) {
+ // make sure we're using parsed dates in the search
+ $hdr = $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
+ // Add date range picker
+ t = '
' +
+ '
';
+ $(t).appendTo($cell);
+
+ // add callbacks; preserve added callbacks
+ o.oldonClose = o.onClose;
+
+ closeDate = o.onClose = function( selectedDate, ui ) {
+ var range,
+ from = $cell.find('.dateFrom').datepicker('getDate'),
+ to = $cell.find('.dateTo').datepicker('getDate');
+ from = validDate(from) ? from.getTime() : '';
+ to = validDate(to) ? ( o.endOfDay ? to.setHours(23, 59, 59) : to.getTime() ) || '' : '';
+ range = from ? ( to ? from + ' - ' + to : '>=' + from ) : (to ? '<=' + to : '');
$cell.add( $shcell )
- .find('.dateFrom').datepicker('option', 'maxDate', to || null ).end()
- .find('.dateTo').datepicker('option', 'minDate', null).datepicker('setDate', to || null);
- } else if (/>=/.test(range)) {
- $cell.add( $shcell )
- .find('.dateFrom').datepicker('option', 'maxDate', null).datepicker('setDate', from || null).end()
- .find('.dateTo').datepicker('option', 'minDate', from || null );
- } else {
- $cell.add( $shcell )
- .find('.dateFrom').datepicker('option', 'maxDate', null).datepicker('setDate', from || null ).end()
- .find('.dateTo').datepicker('option', 'minDate', null).datepicker('setDate', to || null);
- }
+ .find('.dateRange').val(range)
+ .trigger('search');
+ // date picker needs date objects
+ from = from ? new Date(from) : '';
+ to = to ? new Date(to) : '';
- if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); }
- };
+ if (/<=/.test(range)) {
+ $cell.add( $shcell )
+ .find('.dateFrom').datepicker('option', 'maxDate', to || null ).end()
+ .find('.dateTo').datepicker('option', 'minDate', null).datepicker('setDate', to || null);
+ } else if (/>=/.test(range)) {
+ $cell.add( $shcell )
+ .find('.dateFrom').datepicker('option', 'maxDate', null).datepicker('setDate', from || null).end()
+ .find('.dateTo').datepicker('option', 'minDate', from || null );
+ } else {
+ $cell.add( $shcell )
+ .find('.dateFrom').datepicker('option', 'maxDate', null).datepicker('setDate', from || null ).end()
+ .find('.dateTo').datepicker('option', 'minDate', null).datepicker('setDate', to || null);
+ }
- o.defaultDate = o.from || '';
- $cell.find('.dateFrom').datepicker(o);
- o.defaultDate = o.to || '+7d'; // set to date +7 days from today (if not defined)
- $cell.find('.dateTo').datepicker(o);
+ if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); }
+ };
- // update date compare from hidden input, in case of saved filters
- c.$table.bind('filterFomatterUpdate', function(){
- var val = $input.val() || '',
- from = '',
- to = '';
- // date range
- if (/\s+-\s+/.test(val)){
- val = val.split(/\s+-\s+/) || [];
- from = val[0] || '';
- to = val[1] || '';
- } else if (/>=/.test(val)) {
- // greater than date (to date empty)
- from = val.replace(/>=/, '') || '';
- } else if (/<=/.test(val)) {
- // less than date (from date empty)
- to = val.replace(/<=/, '') || '';
- }
-
- // differeniate 1388556000000 from 1/1/2014 using \d{5} regex
- from = from !== '' ? /\d{5}/g.test(from) ? new Date(Number(from)) : from || '' : '';
- to = to !== '' ? /\d{5}/g.test(to) ? new Date(Number(to)) : to || '' : '';
-
- $cell.add($shcell).find('.dateFrom').datepicker('setDate', from || null);
- $cell.add($shcell).find('.dateTo').datepicker('setDate', to || null);
- // give datepicker time to process
- setTimeout(function(){
- closeDate();
- ts.filter.formatterUpdated($cell, indx);
- }, 0);
- });
-
- // has sticky headers?
- c.$table.bind('stickyHeadersInit', function(){
- $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
- $shcell.append(t);
-
- // add a jQuery datepicker!
o.defaultDate = o.from || '';
- $shcell.find('.dateFrom').datepicker(o);
+ $cell.find('.dateFrom').datepicker(o);
+ o.defaultDate = o.to || '+7d'; // set to date +7 days from today (if not defined)
+ $cell.find('.dateTo').datepicker(o);
- o.defaultDate = o.to || '+7d';
- $shcell.find('.dateTo').datepicker(o);
+ // update date compare from hidden input, in case of saved filters
+ c.$table.bind('filterFomatterUpdate', function(){
+ var val = $input.val() || '',
+ from = '',
+ to = '';
+ // date range
+ if (/\s+-\s+/.test(val)){
+ val = val.split(/\s+-\s+/) || [];
+ from = val[0] || '';
+ to = val[1] || '';
+ } else if (/>=/.test(val)) {
+ // greater than date (to date empty)
+ from = val.replace(/>=/, '') || '';
+ } else if (/<=/.test(val)) {
+ // less than date (from date empty)
+ to = val.replace(/<=/, '') || '';
+ }
- });
+ // differeniate 1388556000000 from 1/1/2014 using \d{5} regex
+ from = from !== '' ? /\d{5}/g.test(from) ? new Date(Number(from)) : from || '' : '';
+ to = to !== '' ? /\d{5}/g.test(to) ? new Date(Number(to)) : to || '' : '';
- // on reset
- $cell.closest('table').bind('filterReset', function(){
- $cell.add($shcell).find('.dateFrom').val('').datepicker('setDate', o.from || null );
- $cell.add($shcell).find('.dateTo').val('').datepicker('setDate', o.to || null );
- setTimeout(function(){
- closeDate();
- }, 0);
- });
+ $cell.add($shcell).find('.dateFrom').datepicker('setDate', from || null);
+ $cell.add($shcell).find('.dateTo').datepicker('setDate', to || null);
+ // give datepicker time to process
+ setTimeout(function(){
+ closeDate();
+ ts.filter.formatterUpdated($cell, indx);
+ }, 0);
+ });
- // return the hidden input so the filter widget has a reference to it
- return $input.val( o.from ? ( o.to ? o.from + ' - ' + o.to : '>=' + o.from ) : (o.to ? '<=' + o.to : '') );
- }
+ // has sticky headers?
+ c.$table.bind('stickyHeadersInit', function(){
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
+ $shcell.append(t);
-});
+ // add a jQuery datepicker!
+ o.defaultDate = o.from || '';
+ $shcell.find('.dateFrom').datepicker(o);
+
+ o.defaultDate = o.to || '+7d';
+ $shcell.find('.dateTo').datepicker(o);
+
+ });
+
+ // on reset
+ $cell.closest('table').bind('filterReset', function(){
+ $cell.add($shcell).find('.dateFrom').val('').datepicker('setDate', o.from || null );
+ $cell.add($shcell).find('.dateTo').val('').datepicker('setDate', o.to || null );
+ setTimeout(function(){
+ closeDate();
+ }, 0);
+ });
+
+ // return the hidden input so the filter widget has a reference to it
+ return $input.val( o.from ? ( o.to ? o.from + ' - ' + o.to : '>=' + o.from ) : (o.to ? '<=' + o.to : '') );
+ }
+
+ });
})(jQuery);
diff --git a/js/widgets/widget-filter-formatter-select2.js b/js/widgets/widget-filter-formatter-select2.js
index ec5d0d31..8139a58c 100644
--- a/js/widgets/widget-filter-formatter-select2.js
+++ b/js/widgets/widget-filter-formatter-select2.js
@@ -4,146 +4,146 @@
/*jshint browser:true, jquery:true, unused:false */
/*global jQuery: false */
;(function($){
-"use strict";
+ 'use strict';
-var ts = $.tablesorter || {};
-ts.filterFormatter = ts.filterFormatter || {};
+ var ts = $.tablesorter || {};
+ ts.filterFormatter = ts.filterFormatter || {};
-/************************\
- Select2 Filter Formatter
-\************************/
-ts.filterFormatter.select2 = function($cell, indx, select2Def) {
- var o = $.extend({
- // select2 filter formatter options
- cellText : '', // Text (wrapped in a label element)
- match : true, // adds "filter-match" to header
- value : '',
- // include ANY select2 options below
- multiple : true,
- width : '100%'
+ /************************\
+ Select2 Filter Formatter
+ \************************/
+ ts.filterFormatter.select2 = function($cell, indx, select2Def) {
+ var o = $.extend({
+ // select2 filter formatter options
+ cellText : '', // Text (wrapped in a label element)
+ match : true, // adds 'filter-match' to header
+ value : '',
+ // include ANY select2 options below
+ multiple : true,
+ width : '100%'
- }, select2Def ),
- arry, data,
- c = $cell.closest('table')[0].config,
- wo = c.widgetOptions,
- // Add a hidden input to hold the range values
- $input = $('
')
- .appendTo($cell)
- // hidden filter update namespace trigger by filter widget
- .bind('change' + c.namespace + 'filter', function(){
- var val = this.value;
- val = val.replace(/[/()$^]/g, '').split('|');
- $cell.find('.select2').select2('val', val);
- updateSelect2();
- }),
- $header = c.$headerIndexed[indx],
- onlyAvail = $header.hasClass(wo.filter_onlyAvail),
- $shcell = [],
- matchPrefix = o.match ? '' : '^',
- matchSuffix = o.match ? '' : '$',
+ }, select2Def ),
+ arry, data,
+ c = $cell.closest('table')[0].config,
+ wo = c.widgetOptions,
+ // Add a hidden input to hold the range values
+ $input = $('
')
+ .appendTo($cell)
+ // hidden filter update namespace trigger by filter widget
+ .bind('change' + c.namespace + 'filter', function(){
+ var val = this.value;
+ val = val.replace(/[/()$^]/g, '').split('|');
+ $cell.find('.select2').select2('val', val);
+ updateSelect2();
+ }),
+ $header = c.$headerIndexed[indx],
+ onlyAvail = $header.hasClass(wo.filter_onlyAvail),
+ $shcell = [],
+ matchPrefix = o.match ? '' : '^',
+ matchSuffix = o.match ? '' : '$',
- // this function updates the hidden input and adds the current values to the header cell text
- updateSelect2 = function() {
- var arry = false,
- v = $cell.find('.select2').select2('val') || o.value || '';
- // convert array to string
- if ($.isArray(v)) {
- arry = true;
- v = v.join('\u0000');
- }
- // escape special regex characters (http://stackoverflow.com/a/9310752/145346)
- v = v.replace(/[-[\]{}()*+?.,/\\^$|#\s]/g, '\\$&');
- // convert string back into an array
- if (arry) {
- v = v.split('\u0000');
- }
- $input
- // add regex, so we filter exact numbers
- .val( $.isArray(v) && v.length && v.join('') !== '' ? '/(' + matchPrefix + (v || []).join(matchSuffix + '|' + matchPrefix) + matchSuffix + ')/' : '' )
- .trigger('search').end()
- .find('.select2').select2('val', v);
- // update sticky header cell
- if ($shcell.length) {
- $shcell.find('.select2').select2('val', v);
- }
- },
+ // this function updates the hidden input and adds the current values to the header cell text
+ updateSelect2 = function() {
+ var arry = false,
+ v = $cell.find('.select2').select2('val') || o.value || '';
+ // convert array to string
+ if ($.isArray(v)) {
+ arry = true;
+ v = v.join('\u0000');
+ }
+ // escape special regex characters (http://stackoverflow.com/a/9310752/145346)
+ v = v.replace(/[-[\]{}()*+?.,/\\^$|#\s]/g, '\\$&');
+ // convert string back into an array
+ if (arry) {
+ v = v.split('\u0000');
+ }
+ $input
+ // add regex, so we filter exact numbers
+ .val( $.isArray(v) && v.length && v.join('') !== '' ? '/(' + matchPrefix + (v || []).join(matchSuffix + '|' + matchPrefix) + matchSuffix + ')/' : '' )
+ .trigger('search').end()
+ .find('.select2').select2('val', v);
+ // update sticky header cell
+ if ($shcell.length) {
+ $shcell.find('.select2').select2('val', v);
+ }
+ },
- // get options from table cell content or filter_selectSource (v2.16)
- updateOptions = function(){
- data = [];
- arry = ts.filter.getOptionSource(c.$table[0], indx, onlyAvail) || [];
- // build select2 data option
- $.each(arry, function(i,v){
- data.push({id: v, text: v});
- });
- o.data = data;
- };
-
- // get filter-match class from option
- $header.toggleClass('filter-match', o.match);
- if (o.cellText) {
- $cell.prepend('
');
- }
-
- // don't add default in table options if either ajax or
- // data options are already defined
- if (!(o.ajax && !$.isEmptyObject(o.ajax)) && !o.data) {
- updateOptions();
- if (onlyAvail) {
- c.$table.bind('filterEnd', function(){
- updateOptions();
- $cell.add($shcell).find('.select2').select2(o);
+ // get options from table cell content or filter_selectSource (v2.16)
+ updateOptions = function(){
+ data = [];
+ arry = ts.filter.getOptionSource(c.$table[0], indx, onlyAvail) || [];
+ // build select2 data option
+ $.each(arry, function(i, v){
+ data.push({id: v, text: v});
});
+ o.data = data;
+ };
+
+ // get filter-match class from option
+ $header.toggleClass('filter-match', o.match);
+ if (o.cellText) {
+ $cell.prepend('
');
}
- }
- // add a select2 hidden input!
- $('
')
- .val(o.value)
- .appendTo($cell)
- .select2(o)
- .bind('change', function(){
- updateSelect2();
- });
+ // don't add default in table options if either ajax or
+ // data options are already defined
+ if (!(o.ajax && !$.isEmptyObject(o.ajax)) && !o.data) {
+ updateOptions();
+ if (onlyAvail) {
+ c.$table.bind('filterEnd', function(){
+ updateOptions();
+ $cell.add($shcell).find('.select2').select2(o);
+ });
+ }
+ }
- // update select2 from filter hidden input, in case of saved filters
- c.$table.bind('filterFomatterUpdate', function(){
- // value = '/(^x$|^y$)/' => 'x,y'
- var val = c.$table.data('lastSearch')[indx] || '';
- val = val.replace(/^\/\(\^?/,'').replace(/\$\|\^/g, '|').replace(/\$?\)\/$/g,'').split('|');
- $cell.find('.select2').select2('val', val);
- updateSelect2();
- ts.filter.formatterUpdated($cell, indx);
- });
-
- // has sticky headers?
- c.$table.bind('stickyHeadersInit', function(){
- $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
- // add a select2!
- $('
')
+ // add a select2 hidden input!
+ $('
')
.val(o.value)
- .appendTo($shcell)
+ .appendTo($cell)
.select2(o)
.bind('change', function(){
- $cell.find('.select2').select2('val', $shcell.find('.select2').select2('val') );
updateSelect2();
});
- if (o.cellText) {
- $shcell.prepend('
');
- }
- });
-
- // on reset
- c.$table.bind('filterReset', function(){
- $cell.find('.select2').select2('val', o.value || '');
- setTimeout(function(){
+ // update select2 from filter hidden input, in case of saved filters
+ c.$table.bind('filterFomatterUpdate', function(){
+ // value = '/(^x$|^y$)/' => 'x,y'
+ var val = c.$table.data('lastSearch')[indx] || '';
+ val = val.replace(/^\/\(\^?/, '').replace(/\$\|\^/g, '|').replace(/\$?\)\/$/g, '').split('|');
+ $cell.find('.select2').select2('val', val);
updateSelect2();
- }, 0);
- });
+ ts.filter.formatterUpdated($cell, indx);
+ });
- updateSelect2();
- return $input;
-};
+ // has sticky headers?
+ c.$table.bind('stickyHeadersInit', function(){
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
+ // add a select2!
+ $('
')
+ .val(o.value)
+ .appendTo($shcell)
+ .select2(o)
+ .bind('change', function(){
+ $cell.find('.select2').select2('val', $shcell.find('.select2').select2('val') );
+ updateSelect2();
+ });
+ if (o.cellText) {
+ $shcell.prepend('
');
+ }
+
+ });
+
+ // on reset
+ c.$table.bind('filterReset', function(){
+ $cell.find('.select2').select2('val', o.value || '');
+ setTimeout(function(){
+ updateSelect2();
+ }, 0);
+ });
+
+ updateSelect2();
+ return $input;
+ };
})(jQuery);
diff --git a/js/widgets/widget-filter-type-insideRange.js b/js/widgets/widget-filter-type-insideRange.js
index 0bdd37b5..bb39f92f 100644
--- a/js/widgets/widget-filter-type-insideRange.js
+++ b/js/widgets/widget-filter-type-insideRange.js
@@ -1,6 +1,6 @@
/*! Widget: filter, insideRange filter type - updated 2/23/2015 (v2.21.0) */
;(function($){
-'use strict';
+ 'use strict';
// Add insideRange filter type
// ============================
diff --git a/js/widgets/widget-filter.js b/js/widgets/widget-filter.js
index 3436e4c7..ced1de3a 100644
--- a/js/widgets/widget-filter.js
+++ b/js/widgets/widget-filter.js
@@ -3,92 +3,92 @@
* by Rob Garrison
*/
;( function ( $ ) {
-'use strict';
-var ts = $.tablesorter || {},
+ 'use strict';
+ var ts = $.tablesorter || {},
tscss = ts.css;
-$.extend( tscss, {
- filterRow : 'tablesorter-filter-row',
- filter : 'tablesorter-filter',
- filterDisabled : 'disabled',
- filterRowHide : 'hideme'
-});
+ $.extend( tscss, {
+ filterRow : 'tablesorter-filter-row',
+ filter : 'tablesorter-filter',
+ filterDisabled : 'disabled',
+ filterRowHide : 'hideme'
+ });
-ts.addWidget({
- id: 'filter',
- priority: 50,
- options : {
- filter_childRows : false, // if true, filter includes child row content in the search
- filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped
- filter_columnFilters : true, // if true, a filter will be added to the top of each table column
- filter_columnAnyMatch: true, // if true, allows using '#:{query}' in AnyMatch searches ( column:query )
- filter_cellFilter : '', // css class name added to the filter cell ( string or array )
- filter_cssFilter : '', // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added )
- filter_defaultFilter : {}, // add a default column filter type '~{query}' to make fuzzy searches default; '{q1} AND {q2}' to make all searches use a logical AND.
- filter_excludeFilter : {}, // filters to exclude, per column
- filter_external : '', // jQuery selector string ( or jQuery object ) of external filters
- filter_filteredRow : 'filtered', // class added to filtered rows; needed by pager plugin
- filter_formatter : null, // add custom filter elements to the filter row
- filter_functions : null, // add custom filter functions using this option
- filter_hideEmpty : true, // hide filter row when table is empty
- filter_hideFilters : false, // collapse filter row when mouse leaves the area
- filter_ignoreCase : true, // if true, make all searches case-insensitive
- filter_liveSearch : true, // if true, search column content while the user types ( with a delay )
- filter_onlyAvail : 'filter-onlyAvail', // a header with a select dropdown & this class name will only show available ( visible ) options within the drop down
- filter_placeholder : { search : '', select : '' }, // default placeholder text ( overridden by any header 'data-placeholder' setting )
- filter_reset : null, // jQuery selector string of an element used to reset the filters
- filter_saveFilters : false, // Use the $.tablesorter.storage utility to save the most recent filters
- filter_searchDelay : 300, // typing delay in milliseconds before starting a search
- filter_searchFiltered: true, // allow searching through already filtered rows in special circumstances; will speed up searching in large tables if true
- filter_selectSource : null, // include a function to return an array of values to be added to the column filter select
- filter_startsWith : false, // if true, filter start from the beginning of the cell contents
- filter_useParsedData : false, // filter all data using parsed content
- filter_serversideFiltering : false, // if true, server-side filtering should be performed because client-side filtering will be disabled, but the ui and events will still be used.
- filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value
- filter_selectSourceSeparator : '|' // filter_selectSource array text left of the separator is added to the option value, right into the option text
- },
- format: function( table, c, wo ) {
- if ( !c.$table.hasClass( 'hasFilters' ) ) {
- ts.filter.init( table, c, wo );
+ ts.addWidget({
+ id: 'filter',
+ priority: 50,
+ options : {
+ filter_childRows : false, // if true, filter includes child row content in the search
+ filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped
+ filter_columnFilters : true, // if true, a filter will be added to the top of each table column
+ filter_columnAnyMatch: true, // if true, allows using '#:{query}' in AnyMatch searches ( column:query )
+ filter_cellFilter : '', // css class name added to the filter cell ( string or array )
+ filter_cssFilter : '', // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added )
+ filter_defaultFilter : {}, // add a default column filter type '~{query}' to make fuzzy searches default; '{q1} AND {q2}' to make all searches use a logical AND.
+ filter_excludeFilter : {}, // filters to exclude, per column
+ filter_external : '', // jQuery selector string ( or jQuery object ) of external filters
+ filter_filteredRow : 'filtered', // class added to filtered rows; needed by pager plugin
+ filter_formatter : null, // add custom filter elements to the filter row
+ filter_functions : null, // add custom filter functions using this option
+ filter_hideEmpty : true, // hide filter row when table is empty
+ filter_hideFilters : false, // collapse filter row when mouse leaves the area
+ filter_ignoreCase : true, // if true, make all searches case-insensitive
+ filter_liveSearch : true, // if true, search column content while the user types ( with a delay )
+ filter_onlyAvail : 'filter-onlyAvail', // a header with a select dropdown & this class name will only show available ( visible ) options within the drop down
+ filter_placeholder : { search : '', select : '' }, // default placeholder text ( overridden by any header 'data-placeholder' setting )
+ filter_reset : null, // jQuery selector string of an element used to reset the filters
+ filter_saveFilters : false, // Use the $.tablesorter.storage utility to save the most recent filters
+ filter_searchDelay : 300, // typing delay in milliseconds before starting a search
+ filter_searchFiltered: true, // allow searching through already filtered rows in special circumstances; will speed up searching in large tables if true
+ filter_selectSource : null, // include a function to return an array of values to be added to the column filter select
+ filter_startsWith : false, // if true, filter start from the beginning of the cell contents
+ filter_useParsedData : false, // filter all data using parsed content
+ filter_serversideFiltering : false, // if true, must perform server-side filtering b/c client-side filtering is disabled, but the ui and events will still be used.
+ filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value
+ filter_selectSourceSeparator : '|' // filter_selectSource array text left of the separator is added to the option value, right into the option text
+ },
+ format: function( table, c, wo ) {
+ if ( !c.$table.hasClass( 'hasFilters' ) ) {
+ ts.filter.init( table, c, wo );
+ }
+ },
+ remove: function( table, c, wo, refreshing ) {
+ var tbodyIndex, $tbody,
+ $table = c.$table,
+ $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( events.replace( /\s+/g, ' ' ) )
+ // remove the filter row even if refreshing, because the column might have been moved
+ .find( '.' + tscss.filterRow ).remove();
+ if ( refreshing ) { return; }
+ for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+ $tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
+ $tbody.children().removeClass( wo.filter_filteredRow ).show();
+ ts.processTbody( table, $tbody, false ); // restore tbody
+ }
+ if ( wo.filter_reset ) {
+ $( document ).undelegate( wo.filter_reset, 'click.tsfilter' );
+ }
}
- },
- remove: function( table, c, wo, refreshing ) {
- var tbodyIndex, $tbody,
- $table = c.$table,
- $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( events.replace( /\s+/g, ' ' ) )
- // remove the filter row even if refreshing, because the column might have been moved
- .find( '.' + tscss.filterRow ).remove();
- if ( refreshing ) { return; }
- for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
- $tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
- $tbody.children().removeClass( wo.filter_filteredRow ).show();
- ts.processTbody( table, $tbody, false ); // restore tbody
- }
- if ( wo.filter_reset ) {
- $( document ).undelegate( wo.filter_reset, 'click.tsfilter' );
- }
- }
-});
+ });
-ts.filter = {
+ ts.filter = {
- // regex used in filter 'check' functions - not for general use and not documented
- regex: {
- regex : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/, // regex to test for regex
- child : /tablesorter-childRow/, // child row class name; this gets updated in the script
- filtered : /filtered/, // filtered (hidden) row class name; updated in the script
- type : /undefined|number/, // check type
- exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==')
- nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser)
- operators : /[<>=]/g, // replace operators
- query : '(q|query)' // replace filter queries
- },
+ // regex used in filter 'check' functions - not for general use and not documented
+ regex: {
+ regex : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/, // regex to test for regex
+ child : /tablesorter-childRow/, // child row class name; this gets updated in the script
+ filtered : /filtered/, // filtered (hidden) row class name; updated in the script
+ type : /undefined|number/, // check type
+ exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==')
+ nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser)
+ operators : /[<>=]/g, // replace operators
+ query : '(q|query)' // replace filter queries
+ },
// function( c, data ) { }
// c = table.config
// data.$row = jQuery object of the row currently being processed
@@ -102,1507 +102,1507 @@ ts.filter = {
// data.cacheArray = An array of parsed content from each table cell in the row being processed
// data.index = column index; table = table element ( DOM )
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
- types: {
- or : function( c, data, vars ) {
- if ( /\|/.test( data.iFilter ) || ts.filter.regex.orSplit.test( data.filter ) ) {
- var indx, filterMatched, txt, query, regex,
- // duplicate data but split filter
- data2 = $.extend( {}, data ),
- index = data.index,
- parsed = data.parsed[ index ],
- filter = data.filter.split( ts.filter.regex.orSplit ),
- iFilter = data.iFilter.split( ts.filter.regex.orSplit ),
- len = filter.length;
- for ( indx = 0; indx < len; indx++ ) {
- data2.nestedFilters = true;
- data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
- data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
- query = '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
- regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
- // filterMatched = data2.filter === '' && indx > 0 ? true
- // look for an exact match with the 'or' unless the 'filter-match' class is found
- filterMatched = regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars );
- if ( filterMatched ) {
- return filterMatched;
+ types: {
+ or : function( c, data, vars ) {
+ if ( /\|/.test( data.iFilter ) || ts.filter.regex.orSplit.test( data.filter ) ) {
+ var indx, filterMatched, txt, query, regex,
+ // duplicate data but split filter
+ data2 = $.extend( {}, data ),
+ index = data.index,
+ parsed = data.parsed[ index ],
+ filter = data.filter.split( ts.filter.regex.orSplit ),
+ iFilter = data.iFilter.split( ts.filter.regex.orSplit ),
+ len = filter.length;
+ for ( indx = 0; indx < len; indx++ ) {
+ data2.nestedFilters = true;
+ data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
+ data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
+ query = '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
+ regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
+ // filterMatched = data2.filter === '' && indx > 0 ? true
+ // look for an exact match with the 'or' unless the 'filter-match' class is found
+ filterMatched = regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars );
+ if ( filterMatched ) {
+ return filterMatched;
+ }
}
+ // may be null from processing types
+ return filterMatched || false;
}
- // may be null from processing types
- return filterMatched || false;
- }
- return null;
- },
- // Look for an AND or && operator ( logical and )
- and : function( c, data, vars ) {
- if ( ts.filter.regex.andTest.test( data.filter ) ) {
- var indx, filterMatched, result, txt, query, regex,
- // duplicate data but split filter
- data2 = $.extend( {}, data ),
- index = data.index,
- parsed = data.parsed[ index ],
- filter = data.filter.split( ts.filter.regex.andSplit ),
- iFilter = data.iFilter.split( ts.filter.regex.andSplit ),
- len = filter.length;
- for ( indx = 0; indx < len; indx++ ) {
- data2.nestedFilters = true;
- data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
- data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
- query = ( '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
- // replace wild cards since /(a*)/i will match anything
- .replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
- regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
- // look for an exact match with the 'and' unless the 'filter-match' class is found
- result = ( regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars ) );
- if ( indx === 0 ) {
- filterMatched = result;
+ return null;
+ },
+ // Look for an AND or && operator ( logical and )
+ and : function( c, data, vars ) {
+ if ( ts.filter.regex.andTest.test( data.filter ) ) {
+ var indx, filterMatched, result, txt, query, regex,
+ // duplicate data but split filter
+ data2 = $.extend( {}, data ),
+ index = data.index,
+ parsed = data.parsed[ index ],
+ filter = data.filter.split( ts.filter.regex.andSplit ),
+ iFilter = data.iFilter.split( ts.filter.regex.andSplit ),
+ len = filter.length;
+ for ( indx = 0; indx < len; indx++ ) {
+ data2.nestedFilters = true;
+ data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
+ data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
+ query = ( '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
+ // replace wild cards since /(a*)/i will match anything
+ .replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
+ regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
+ // look for an exact match with the 'and' unless the 'filter-match' class is found
+ result = ( regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars ) );
+ if ( indx === 0 ) {
+ filterMatched = result;
+ } else {
+ filterMatched = filterMatched && result;
+ }
+ }
+ // may be null from processing types
+ return filterMatched || false;
+ }
+ return null;
+ },
+ // Look for regex
+ regex: function( c, data ) {
+ if ( ts.filter.regex.regex.test( data.filter ) ) {
+ var matches,
+ // cache regex per column for optimal speed
+ regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
+ isRegex = regex instanceof RegExp;
+ try {
+ if ( !isRegex ) {
+ // force case insensitive search if ignoreCase option set?
+ // if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; }
+ data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] );
+ }
+ matches = regex.test( data.exact );
+ } catch ( error ) {
+ matches = false;
+ }
+ return matches;
+ }
+ return null;
+ },
+ // Look for operators >, >=, < or <=
+ operators: function( c, data ) {
+ // ignore empty strings... because '' < 10 is true
+ if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) {
+ var cachedValue, result, txt,
+ table = c.table,
+ index = data.index,
+ parsed = data.parsed[index],
+ query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ),
+ parser = c.parsers[index],
+ savedSearch = query;
+ // parse filter value in case we're comparing numbers ( dates )
+ if ( parsed || parser.type === 'numeric' ) {
+ txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) );
+ result = ts.filter.parseFilter( c, txt, index, true );
+ query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
+ }
+ // iExact may be numeric - see issue #149;
+ // check if cached is defined, because sometimes j goes out of range? ( numeric columns )
+ if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) &&
+ typeof data.cache !== 'undefined' ) {
+ cachedValue = data.cache;
} else {
- filterMatched = filterMatched && result;
+ txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
+ cachedValue = ts.formatFloat( txt, table );
+ }
+ if ( />/.test( data.iFilter ) ) {
+ result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
+ } else if ( /= 0 );
}
}
- // may be null from processing types
- return filterMatched || false;
- }
- return null;
- },
- // Look for regex
- regex: function( c, data ) {
- if ( ts.filter.regex.regex.test( data.filter ) ) {
- var matches,
- // cache regex per column for optimal speed
- regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
- isRegex = regex instanceof RegExp;
- try {
- if ( !isRegex ) {
- // force case insensitive search if ignoreCase option set?
- // if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; }
- data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] );
- }
- matches = regex.test( data.exact );
- } catch ( error ) {
- matches = false;
+ return null;
+ },
+ // Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
+ exact: function( c, data ) {
+ /*jshint eqeqeq:false */
+ if ( ts.filter.regex.exact.test( data.iFilter ) ) {
+ var txt = data.iFilter.replace( ts.filter.regex.exact, '' ),
+ filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
+ return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
}
- return matches;
- }
- return null;
- },
- // Look for operators >, >=, < or <=
- operators: function( c, data ) {
- // ignore empty strings... because '' < 10 is true
- if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) {
- var cachedValue, result, txt,
- table = c.table,
- index = data.index,
- parsed = data.parsed[index],
- query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ),
- parser = c.parsers[index],
- savedSearch = query;
- // parse filter value in case we're comparing numbers ( dates )
- if ( parsed || parser.type === 'numeric' ) {
- txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) );
- result = ts.filter.parseFilter( c, txt, index, true );
- query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
- }
- // iExact may be numeric - see issue #149;
- // check if cached is defined, because sometimes j goes out of range? ( numeric columns )
- if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) &&
- typeof data.cache !== 'undefined' ) {
- cachedValue = data.cache;
- } else {
- txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
- cachedValue = ts.formatFloat( txt, table );
- }
- if ( />/.test( data.iFilter ) ) {
- result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
- } else if ( /= 0 );
- }
- }
- return null;
- },
- // Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
- exact: function( c, data ) {
- /*jshint eqeqeq:false */
- if ( ts.filter.regex.exact.test( data.iFilter ) ) {
- var txt = data.iFilter.replace( ts.filter.regex.exact, '' ),
- filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
- return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
- }
- return null;
- },
- // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
- range : function( c, data ) {
- if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
- var result, tmp, range1, range2,
- table = c.table,
- index = data.index,
- parsed = data.parsed[index],
- // make sure the dash is for a range and not indicating a negative number
- query = data.iFilter.split( ts.filter.regex.toSplit );
+ return null;
+ },
+ // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
+ range : function( c, data ) {
+ if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
+ var result, tmp, range1, range2,
+ table = c.table,
+ index = data.index,
+ parsed = data.parsed[index],
+ // make sure the dash is for a range and not indicating a negative number
+ query = data.iFilter.split( ts.filter.regex.toSplit );
- tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || '';
- range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
- tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || '';
- range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
- // parse filter value in case we're comparing numbers ( dates )
- if ( parsed || c.parsers[index].type === 'numeric' ) {
- result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
- range1 = ( result !== '' && !isNaN( result ) ) ? result : range1;
- result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index );
- range2 = ( result !== '' && !isNaN( result ) ) ? result : range2;
- }
- if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
- result = data.cache;
- } else {
- tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
- result = ts.formatFloat( tmp, table );
- }
- if ( range1 > range2 ) {
- tmp = range1; range1 = range2; range2 = tmp; // swap
- }
- return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' );
- }
- return null;
- },
- // Look for wild card: ? = single, * = multiple, or | = logical OR
- wild : function( c, data ) {
- if ( /[\?\*\|]/.test( data.iFilter ) ) {
- var index = data.index,
- parsed = data.parsed[ index ],
- query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
- // look for an exact match with the 'or' unless the 'filter-match' class is found
- if ( !/\?\*/.test( query ) && data.nestedFilters ) {
- query = data.isMatch ? query : '^(' + query + ')$';
- }
- // parsing the filter may not work properly when using wildcards =/
- return new RegExp(
- query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
- c.widgetOptions.filter_ignoreCase ? 'i' : ''
- )
- .test( data.exact );
- }
- return null;
- },
- // fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
- fuzzy: function( c, data ) {
- if ( /^~/.test( data.iFilter ) ) {
- var indx,
- patternIndx = 0,
- len = data.iExact.length,
- txt = data.iFilter.slice( 1 ),
- pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
- for ( indx = 0; indx < len; indx++ ) {
- if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
- patternIndx += 1;
+ tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || '';
+ range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
+ tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || '';
+ range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
+ // parse filter value in case we're comparing numbers ( dates )
+ if ( parsed || c.parsers[index].type === 'numeric' ) {
+ result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
+ range1 = ( result !== '' && !isNaN( result ) ) ? result : range1;
+ result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index );
+ range2 = ( result !== '' && !isNaN( result ) ) ? result : range2;
}
+ if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
+ result = data.cache;
+ } else {
+ tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
+ result = ts.formatFloat( tmp, table );
+ }
+ if ( range1 > range2 ) {
+ tmp = range1; range1 = range2; range2 = tmp; // swap
+ }
+ return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' );
}
- if ( patternIndx === pattern.length ) {
- return true;
+ return null;
+ },
+ // Look for wild card: ? = single, * = multiple, or | = logical OR
+ wild : function( c, data ) {
+ if ( /[\?\*\|]/.test( data.iFilter ) ) {
+ var index = data.index,
+ parsed = data.parsed[ index ],
+ query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
+ // look for an exact match with the 'or' unless the 'filter-match' class is found
+ if ( !/\?\*/.test( query ) && data.nestedFilters ) {
+ query = data.isMatch ? query : '^(' + query + ')$';
+ }
+ // parsing the filter may not work properly when using wildcards =/
+ return new RegExp(
+ query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
+ c.widgetOptions.filter_ignoreCase ? 'i' : ''
+ )
+ .test( data.exact );
+ }
+ return null;
+ },
+ // fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
+ fuzzy: function( c, data ) {
+ if ( /^~/.test( data.iFilter ) ) {
+ var indx,
+ patternIndx = 0,
+ len = data.iExact.length,
+ txt = data.iFilter.slice( 1 ),
+ pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
+ for ( indx = 0; indx < len; indx++ ) {
+ if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
+ patternIndx += 1;
+ }
+ }
+ if ( patternIndx === pattern.length ) {
+ return true;
+ }
+ return false;
+ }
+ return null;
+ }
+ },
+ init: function( table, c, wo ) {
+ // filter language options
+ ts.language = $.extend( true, {}, {
+ to : 'to',
+ or : 'or',
+ and : 'and'
+ }, ts.language );
+
+ var options, string, txt, $header, column, filters, val, fxn, noSelect,
+ regex = ts.filter.regex;
+ c.$table.addClass( 'hasFilters' );
+
+ // define timers so using clearTimeout won't cause an undefined error
+ wo.searchTimer = null;
+ wo.filter_initTimer = null;
+ wo.filter_formatterCount = 0;
+ wo.filter_formatterInit = [];
+ wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
+ wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
+
+ val = '\\{' + ts.filter.regex.query + '\\}';
+ $.extend( regex, {
+ child : new RegExp( c.cssChildRow ),
+ filtered : new RegExp( wo.filter_filteredRow ),
+ alreadyFiltered : new RegExp( '(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i' ),
+ toTest : new RegExp( '\\s+(-|' + ts.language.to + ')\\s+', 'i' ),
+ toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)', 'gi' ),
+ andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
+ andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
+ orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
+ iQuery : new RegExp( val, 'i' ),
+ igQuery : new RegExp( val, 'ig' )
+ });
+
+ // don't build filter row if columnFilters is false or all columns are set to 'filter-false'
+ // see issue #156
+ val = c.$headers.filter( '.filter-false, .parser-false' ).length;
+ if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
+ // build filter row
+ ts.filter.buildRow( table, c, wo );
+ }
+
+ txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
+ .split( ' ' ).join( c.namespace + 'filter ' );
+ c.$table.bind( 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( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
+ if ( !/(search|filter)/.test( event.type ) ) {
+ event.stopPropagation();
+ ts.filter.buildDefault( table, true );
+ }
+ if ( event.type === 'filterReset' ) {
+ c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
+ ts.filter.searching( table, [] );
+ } else if ( event.type === 'filterEnd' ) {
+ ts.filter.buildDefault( table, true );
+ } else {
+ // send false argument to force a new search; otherwise if the filter hasn't changed,
+ // it will return
+ filter = event.type === 'search' ? filter :
+ event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : '';
+ if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) {
+ // force a new search since content has changed
+ c.lastCombinedFilter = null;
+ c.lastSearch = [];
+ }
+ // pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
+ // input ensures all inputs are updated when a search is triggered on the table
+ // $( 'table' ).trigger( 'search', [...] );
+ ts.filter.searching( table, filter, true );
}
return false;
- }
- return null;
- }
- },
- init: function( table, c, wo ) {
- // filter language options
- ts.language = $.extend( true, {}, {
- to : 'to',
- or : 'or',
- and : 'and'
- }, ts.language );
+ });
- var options, string, txt, $header, column, filters, val, fxn, noSelect,
- regex = ts.filter.regex;
- c.$table.addClass( 'hasFilters' );
-
- // define timers so using clearTimeout won't cause an undefined error
- wo.searchTimer = null;
- wo.filter_initTimer = null;
- wo.filter_formatterCount = 0;
- wo.filter_formatterInit = [];
- wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
- wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
-
- val = '\\{' + ts.filter.regex.query + '\\}';
- $.extend( regex, {
- child : new RegExp( c.cssChildRow ),
- filtered : new RegExp( wo.filter_filteredRow ),
- alreadyFiltered : new RegExp( '(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i' ),
- toTest : new RegExp( '\\s+(-|' + ts.language.to + ')\\s+', 'i' ),
- toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
- andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
- andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
- orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
- iQuery : new RegExp( val, 'i' ),
- igQuery : new RegExp( val, 'ig' )
- });
-
- // don't build filter row if columnFilters is false or all columns are set to 'filter-false'
- // see issue #156
- val = c.$headers.filter( '.filter-false, .parser-false' ).length;
- if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
- // build filter row
- ts.filter.buildRow( table, c, wo );
- }
-
- txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
- .split( ' ' ).join( c.namespace + 'filter ' );
- c.$table.bind( 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( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
- if ( !/(search|filter)/.test( event.type ) ) {
- event.stopPropagation();
- ts.filter.buildDefault( table, true );
- }
- if ( event.type === 'filterReset' ) {
- c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
- ts.filter.searching( table, [] );
- } else if ( event.type === 'filterEnd' ) {
- ts.filter.buildDefault( table, true );
- } else {
- // send false argument to force a new search; otherwise if the filter hasn't changed,
- // it will return
- filter = event.type === 'search' ? filter :
- event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : '';
- if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) {
- // force a new search since content has changed
- c.lastCombinedFilter = null;
- c.lastSearch = [];
- }
- // pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
- // input ensures all inputs are updated when a search is triggered on the table
- // $( 'table' ).trigger( 'search', [...] );
- ts.filter.searching( table, filter, true );
- }
- return false;
- });
-
- // reset button/link
- if ( wo.filter_reset ) {
- if ( wo.filter_reset instanceof $ ) {
- // reset contains a jQuery object, bind to it
- wo.filter_reset.click( function() {
- c.$table.trigger( 'filterReset' );
- });
- } else if ( $( wo.filter_reset ).length ) {
- // reset is a jQuery selector, use event delegation
- $( document )
- .undelegate( wo.filter_reset, 'click.tsfilter' )
- .delegate( wo.filter_reset, 'click.tsfilter', function() {
- // trigger a reset event, so other functions ( filter_formatter ) know when to reset
+ // reset button/link
+ if ( wo.filter_reset ) {
+ if ( wo.filter_reset instanceof $ ) {
+ // reset contains a jQuery object, bind to it
+ wo.filter_reset.click( function() {
c.$table.trigger( 'filterReset' );
});
+ } else if ( $( wo.filter_reset ).length ) {
+ // reset is a jQuery selector, use event delegation
+ $( document )
+ .undelegate( wo.filter_reset, 'click.tsfilter' )
+ .delegate( wo.filter_reset, 'click.tsfilter', function() {
+ // trigger a reset event, so other functions ( filter_formatter ) know when to reset
+ c.$table.trigger( 'filterReset' );
+ });
+ }
}
- }
- if ( wo.filter_functions ) {
- for ( column = 0; column < c.columns; column++ ) {
- fxn = ts.getColumnData( table, wo.filter_functions, column );
- if ( fxn ) {
- // remove 'filter-select' from header otherwise the options added here are replaced with
- // all options
- $header = c.$headerIndexed[ column ].removeClass( 'filter-select' );
- // don't build select if 'filter-false' or 'parser-false' set
- noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
- options = '';
- if ( fxn === true && noSelect ) {
- ts.filter.buildSelect( table, column );
- } else if ( typeof fxn === 'object' && noSelect ) {
- // add custom drop down list
- for ( string in fxn ) {
- if ( typeof string === 'string' ) {
- options += options === '' ?
- '
' : '';
- val = string;
- txt = string;
- if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
- val = string.split( wo.filter_selectSourceSeparator );
- txt = val[1];
- val = val[0];
+ if ( wo.filter_functions ) {
+ for ( column = 0; column < c.columns; column++ ) {
+ fxn = ts.getColumnData( table, wo.filter_functions, column );
+ if ( fxn ) {
+ // remove 'filter-select' from header otherwise the options added here are replaced with
+ // all options
+ $header = c.$headerIndexed[ column ].removeClass( 'filter-select' );
+ // don't build select if 'filter-false' or 'parser-false' set
+ noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
+ options = '';
+ if ( fxn === true && noSelect ) {
+ ts.filter.buildSelect( table, column );
+ } else if ( typeof fxn === 'object' && noSelect ) {
+ // add custom drop down list
+ for ( string in fxn ) {
+ if ( typeof string === 'string' ) {
+ options += options === '' ?
+ '
' : '';
+ val = string;
+ txt = string;
+ if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
+ val = string.split( wo.filter_selectSourceSeparator );
+ txt = val[1];
+ val = val[0];
+ }
+ options += '
';
}
- options += '
';
+ }
+ c.$table
+ .find( 'thead' )
+ .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
+ .append( options );
+ txt = wo.filter_selectSource;
+ fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column );
+ if ( fxn ) {
+ // updating so the extra options are appended
+ ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
}
}
+ }
+ }
+ }
+ // not really updating, but if the column has both the 'filter-select' class &
+ // filter_functions set to true, it would append the same options twice.
+ ts.filter.buildDefault( table, true );
+
+ ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
+ if ( wo.filter_external ) {
+ ts.filter.bindSearch( table, wo.filter_external );
+ }
+
+ if ( wo.filter_hideFilters ) {
+ ts.filter.hideFilters( table, c );
+ }
+
+ // show processing icon
+ if ( c.showProcessing ) {
+ txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
+ c.$table
+ .unbind( txt.replace( /\s+/g, ' ' ) )
+ .bind( txt, function( event, columns ) {
+ // only add processing to certain columns to all columns
+ $header = ( columns ) ?
c.$table
- .find( 'thead' )
- .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
- .append( options );
- txt = wo.filter_selectSource;
- fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column );
- if ( fxn ) {
- // updating so the extra options are appended
- ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
- }
- }
- }
- }
- }
- // not really updating, but if the column has both the 'filter-select' class &
- // filter_functions set to true, it would append the same options twice.
- ts.filter.buildDefault( table, true );
-
- ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
- if ( wo.filter_external ) {
- ts.filter.bindSearch( table, wo.filter_external );
- }
-
- if ( wo.filter_hideFilters ) {
- ts.filter.hideFilters( table, c );
- }
-
- // show processing icon
- if ( c.showProcessing ) {
- txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
- c.$table
- .unbind( txt.replace( /\s+/g, ' ' ) )
- .bind( txt, function( event, columns ) {
- // only add processing to certain columns to all columns
- $header = ( columns ) ?
- c.$table
- .find( '.' + tscss.header )
- .filter( '[data-column]' )
- .filter( function() {
- return columns[ $( this ).data( 'column' ) ] !== '';
- }) : '';
- ts.isProcessing( table, event.type === 'filterStart', columns ? $header : '' );
- });
- }
-
- // set filtered rows count ( intially unfiltered )
- c.filteredRows = c.totalRows;
-
- // add default values
- txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
- c.$table
- .unbind( txt.replace( /\s+/g, ' ' ) )
- .bind( txt, function() {
- // redefine 'wo' as it does not update properly inside this callback
- var wo = this.config.widgetOptions;
- filters = ts.filter.setDefaults( table, c, wo ) || [];
- if ( filters.length ) {
- // prevent delayInit from triggering a cache build if filters are empty
- if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
- ts.setFilters( table, filters, true );
- }
- }
- c.$table.trigger( 'filterFomatterUpdate' );
- // trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
- setTimeout( function() {
- if ( !wo.filter_initialized ) {
- ts.filter.filterInitComplete( c );
- }
- }, 100 );
- });
- // if filter widget is added after pager has initialized; then set filter init flag
- if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
- c.$table.trigger( 'filterFomatterUpdate' );
- setTimeout( function() {
- ts.filter.filterInitComplete( c );
- }, 100 );
- }
- },
- // $cell parameter, but not the config, is passed to the filter_formatters,
- // so we have to work with it instead
- formatterUpdated: function( $cell, column ) {
- var wo = $cell.closest( 'table' )[0].config.widgetOptions;
- if ( !wo.filter_initialized ) {
- // add updates by column since this function
- // may be called numerous times before initialization
- wo.filter_formatterInit[ column ] = 1;
- }
- },
- filterInitComplete: function( c ) {
- var indx, len,
- wo = c.widgetOptions,
- count = 0,
- completed = function() {
- wo.filter_initialized = true;
- c.$table.trigger( 'filterInit', c );
- ts.filter.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
- };
- if ( $.isEmptyObject( wo.filter_formatter ) ) {
- completed();
- } else {
- len = wo.filter_formatterInit.length;
- for ( indx = 0; indx < len; indx++ ) {
- if ( wo.filter_formatterInit[ indx ] === 1 ) {
- count++;
- }
- }
- clearTimeout( wo.filter_initTimer );
- if ( !wo.filter_initialized && count === wo.filter_formatterCount ) {
- // filter widget initialized
- completed();
- } else if ( !wo.filter_initialized ) {
- // fall back in case a filter_formatter doesn't call
- // $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off
- wo.filter_initTimer = setTimeout( function() {
- completed();
- }, 500 );
- }
- }
- },
- setDefaults: function( table, c, wo ) {
- var isArray, saved, indx, col, $filters,
- // get current ( default ) filters
- filters = ts.getFilters( table ) || [];
- if ( wo.filter_saveFilters && ts.storage ) {
- saved = ts.storage( table, 'tablesorter-filters' ) || [];
- isArray = $.isArray( saved );
- // make sure we're not just getting an empty array
- if ( !( isArray && saved.join( '' ) === '' || !isArray ) ) {
- filters = saved;
- }
- }
- // if no filters saved, then check default settings
- if ( filters.join( '' ) === '' ) {
- // allow adding default setting to external filters
- $filters = c.$headers.add( wo.filter_$externalFilters )
- .filter( '[' + wo.filter_defaultAttrib + ']' );
- for ( indx = 0; indx <= c.columns; indx++ ) {
- // include data-column='all' external filters
- col = indx === c.columns ? 'all' : indx;
- filters[indx] = $filters
- .filter( '[data-column="' + col + '"]' )
- .attr( wo.filter_defaultAttrib ) || filters[indx] || '';
- }
- }
- c.$table.data( 'lastSearch', filters );
- return filters;
- },
- parseFilter: function( c, filter, column, parsed ) {
- return parsed ? c.parsers[column].format( filter, c.table, [], column ) : filter;
- },
- buildRow: function( table, c, wo ) {
- var col, column, $header, buildSelect, disabled, name, ffxn, tmp,
- // c.columns defined in computeThIndexes()
- cellFilter = wo.filter_cellFilter,
- columns = c.columns,
- arry = $.isArray( cellFilter ),
- buildFilter = '
';
- for ( column = 0; column < columns; column++ ) {
- buildFilter += ' | ';
- }
- c.$filters = $( buildFilter += '
' )
- .appendTo( c.$table.children( 'thead' ).eq( 0 ) )
- .find( 'td' );
- // build each filter input
- for ( column = 0; column < columns; column++ ) {
- disabled = false;
- // assuming last cell of a column is the main column
- $header = c.$headerIndexed[ column ];
- ffxn = ts.getColumnData( table, wo.filter_functions, column );
- buildSelect = ( wo.filter_functions && ffxn && typeof ffxn !== 'function' ) ||
- $header.hasClass( 'filter-select' );
- // get data from jQuery data, metadata, headers option or header class name
- col = ts.getColumnData( table, c.headers, column );
- disabled = ts.getData( $header[0], col, 'filter' ) === 'false' ||
- ts.getData( $header[0], col, 'parser' ) === 'false';
-
- if ( buildSelect ) {
- buildFilter = $( '