jquery-tablesorter 1.16.5 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/jquery-tablesorter/version.rb +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter/addons/pager/jquery.tablesorter.pager.js +38 -27
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.combined.js +1104 -839
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +167 -123
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets.js +938 -717
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date.js +5 -5
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-globalize.js +46 -0
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-input-select.js +96 -72
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-named-numbers.js +6 -5
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-network.js +26 -17
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-columns.js +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-editable.js +95 -42
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-filter.js +921 -700
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-grouping.js +5 -3
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-math.js +22 -20
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-output.js +7 -5
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-pager.js +40 -29
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-resizable.js +6 -6
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-saveSort.js +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-scroller.js +53 -31
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-stickyHeaders.js +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-storage.js +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-uitheme.js +1 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.black-ice.css +2 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.blue.css +2 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.bootstrap.css +2 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.bootstrap_2.css +8 -6
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.dark.css +2 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.default.css +1 -1
- metadata +3 -2
@@ -1,13 +1,13 @@
|
|
1
|
-
/*! Widget: filter - updated
|
1
|
+
/*! Widget: filter - updated 5/17/2015 (v2.22.0) *//*
|
2
2
|
* Requires tablesorter v2.8+ and jQuery 1.7+
|
3
3
|
* by Rob Garrison
|
4
4
|
*/
|
5
|
-
;(function ($) {
|
5
|
+
;( function ( $ ) {
|
6
6
|
'use strict';
|
7
|
-
var ts = $.tablesorter
|
7
|
+
var ts = $.tablesorter || {},
|
8
8
|
tscss = ts.css;
|
9
9
|
|
10
|
-
$.extend(tscss, {
|
10
|
+
$.extend( tscss, {
|
11
11
|
filterRow : 'tablesorter-filter-row',
|
12
12
|
filter : 'tablesorter-filter',
|
13
13
|
filterDisabled : 'disabled',
|
@@ -15,26 +15,27 @@ $.extend(tscss, {
|
|
15
15
|
});
|
16
16
|
|
17
17
|
ts.addWidget({
|
18
|
-
id:
|
18
|
+
id: 'filter',
|
19
19
|
priority: 50,
|
20
20
|
options : {
|
21
21
|
filter_childRows : false, // if true, filter includes child row content in the search
|
22
|
+
filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped
|
22
23
|
filter_columnFilters : true, // if true, a filter will be added to the top of each table column
|
23
|
-
filter_columnAnyMatch: true, // if true, allows using
|
24
|
-
filter_cellFilter : '', // css class name added to the filter cell (string or array)
|
25
|
-
filter_cssFilter : '', // css class name added to the filter row & each input in the row (tablesorter-filter is ALWAYS added)
|
26
|
-
filter_defaultFilter : {}, // add a default column filter type
|
24
|
+
filter_columnAnyMatch: true, // if true, allows using '#:{query}' in AnyMatch searches ( column:query )
|
25
|
+
filter_cellFilter : '', // css class name added to the filter cell ( string or array )
|
26
|
+
filter_cssFilter : '', // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added )
|
27
|
+
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.
|
27
28
|
filter_excludeFilter : {}, // filters to exclude, per column
|
28
|
-
filter_external : '', // jQuery selector string (or jQuery object) of external filters
|
29
|
+
filter_external : '', // jQuery selector string ( or jQuery object ) of external filters
|
29
30
|
filter_filteredRow : 'filtered', // class added to filtered rows; needed by pager plugin
|
30
31
|
filter_formatter : null, // add custom filter elements to the filter row
|
31
32
|
filter_functions : null, // add custom filter functions using this option
|
32
33
|
filter_hideEmpty : true, // hide filter row when table is empty
|
33
34
|
filter_hideFilters : false, // collapse filter row when mouse leaves the area
|
34
35
|
filter_ignoreCase : true, // if true, make all searches case-insensitive
|
35
|
-
filter_liveSearch : true, // if true, search column content while the user types (with a delay)
|
36
|
-
filter_onlyAvail : 'filter-onlyAvail', // a header with a select dropdown & this class name will only show available (visible) options within the drop down
|
37
|
-
filter_placeholder : { search : '', select : '' }, // default placeholder text (overridden by any header
|
36
|
+
filter_liveSearch : true, // if true, search column content while the user types ( with a delay )
|
37
|
+
filter_onlyAvail : 'filter-onlyAvail', // a header with a select dropdown & this class name will only show available ( visible ) options within the drop down
|
38
|
+
filter_placeholder : { search : '', select : '' }, // default placeholder text ( overridden by any header 'data-placeholder' setting )
|
38
39
|
filter_reset : null, // jQuery selector string of an element used to reset the filters
|
39
40
|
filter_saveFilters : false, // Use the $.tablesorter.storage utility to save the most recent filters
|
40
41
|
filter_searchDelay : 300, // typing delay in milliseconds before starting a search
|
@@ -46,37 +47,38 @@ ts.addWidget({
|
|
46
47
|
filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value
|
47
48
|
filter_selectSourceSeparator : '|' // filter_selectSource array text left of the separator is added to the option value, right into the option text
|
48
49
|
},
|
49
|
-
format: function(table, c, wo) {
|
50
|
-
if (!c.$table.hasClass('hasFilters')) {
|
51
|
-
ts.filter.init(table, c, wo);
|
50
|
+
format: function( table, c, wo ) {
|
51
|
+
if ( !c.$table.hasClass( 'hasFilters' ) ) {
|
52
|
+
ts.filter.init( table, c, wo );
|
52
53
|
}
|
53
54
|
},
|
54
|
-
remove: function(table, c, wo, refreshing) {
|
55
|
+
remove: function( table, c, wo, refreshing ) {
|
55
56
|
var tbodyIndex, $tbody,
|
56
57
|
$table = c.$table,
|
57
58
|
$tbodies = c.$tbodies,
|
58
|
-
events = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
|
59
|
+
events = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
|
60
|
+
.split( ' ' ).join( c.namespace + 'filter ' );
|
59
61
|
$table
|
60
|
-
.removeClass('hasFilters')
|
62
|
+
.removeClass( 'hasFilters' )
|
61
63
|
// add .tsfilter namespace to all BUT search
|
62
|
-
.unbind( events.replace(/\s+/g, ' ') )
|
64
|
+
.unbind( events.replace( /\s+/g, ' ' ) )
|
63
65
|
// remove the filter row even if refreshing, because the column might have been moved
|
64
|
-
.find('.' + tscss.filterRow).remove();
|
65
|
-
if (refreshing) { return; }
|
66
|
-
for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
|
67
|
-
$tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody
|
68
|
-
$tbody.children().removeClass(wo.filter_filteredRow).show();
|
69
|
-
ts.processTbody(table, $tbody, false); // restore tbody
|
66
|
+
.find( '.' + tscss.filterRow ).remove();
|
67
|
+
if ( refreshing ) { return; }
|
68
|
+
for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
|
69
|
+
$tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
|
70
|
+
$tbody.children().removeClass( wo.filter_filteredRow ).show();
|
71
|
+
ts.processTbody( table, $tbody, false ); // restore tbody
|
70
72
|
}
|
71
|
-
if (wo.filter_reset) {
|
72
|
-
$(document).undelegate(wo.filter_reset, 'click.tsfilter');
|
73
|
+
if ( wo.filter_reset ) {
|
74
|
+
$( document ).undelegate( wo.filter_reset, 'click.tsfilter' );
|
73
75
|
}
|
74
76
|
}
|
75
77
|
});
|
76
78
|
|
77
79
|
ts.filter = {
|
78
80
|
|
79
|
-
// regex used in filter
|
81
|
+
// regex used in filter 'check' functions - not for general use and not documented
|
80
82
|
regex: {
|
81
83
|
regex : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/, // regex to test for regex
|
82
84
|
child : /tablesorter-childRow/, // child row class name; this gets updated in the script
|
@@ -89,22 +91,33 @@ ts.filter = {
|
|
89
91
|
},
|
90
92
|
// function( c, data ) { }
|
91
93
|
// c = table.config
|
92
|
-
// data
|
93
|
-
// data
|
94
|
-
// data.
|
95
|
-
// data.
|
96
|
-
// data.
|
97
|
-
// data.
|
98
|
-
// data.
|
94
|
+
// data.$row = jQuery object of the row currently being processed
|
95
|
+
// data.$cells = jQuery object of all cells within the current row
|
96
|
+
// data.filters = array of filters for all columns ( some may be undefined )
|
97
|
+
// data.filter = filter for the current column
|
98
|
+
// data.iFilter = same as data.filter, except lowercase ( if wo.filter_ignoreCase is true )
|
99
|
+
// data.exact = table cell text ( or parsed data if column parser enabled )
|
100
|
+
// data.iExact = same as data.exact, except lowercase ( if wo.filter_ignoreCase is true )
|
101
|
+
// data.cache = table cell text from cache, so it has been parsed ( & in all lower case if c.ignoreCase is true )
|
102
|
+
// data.cacheArray = An array of parsed content from each table cell in the row being processed
|
103
|
+
// data.index = column index; table = table element ( DOM )
|
104
|
+
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
|
99
105
|
types: {
|
100
106
|
// Look for regex
|
101
107
|
regex: function( c, data ) {
|
102
|
-
if ( ts.filter.regex.regex.test(data.
|
108
|
+
if ( ts.filter.regex.regex.test( data.filter ) ) {
|
103
109
|
var matches,
|
104
|
-
regex
|
110
|
+
// cache regex per column for optimal speed
|
111
|
+
regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
|
112
|
+
isRegex = regex instanceof RegExp;
|
105
113
|
try {
|
106
|
-
|
107
|
-
|
114
|
+
if ( !isRegex ) {
|
115
|
+
// force case insensitive search if ignoreCase option set?
|
116
|
+
// if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; }
|
117
|
+
data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] );
|
118
|
+
}
|
119
|
+
matches = regex.test( data.exact );
|
120
|
+
} catch ( error ) {
|
108
121
|
matches = false;
|
109
122
|
}
|
110
123
|
return matches;
|
@@ -113,46 +126,56 @@ ts.filter = {
|
|
113
126
|
},
|
114
127
|
// Look for operators >, >=, < or <=
|
115
128
|
operators: function( c, data ) {
|
116
|
-
|
117
|
-
|
129
|
+
// ignore empty strings... because '' < 10 is true
|
130
|
+
if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) {
|
131
|
+
var cachedValue, result, txt,
|
118
132
|
table = c.table,
|
119
133
|
index = data.index,
|
120
134
|
parsed = data.parsed[index],
|
121
|
-
query = ts.formatFloat( data.iFilter.replace(ts.filter.regex.operators, ''), table ),
|
135
|
+
query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ),
|
122
136
|
parser = c.parsers[index],
|
123
137
|
savedSearch = query;
|
124
|
-
// parse filter value in case we're comparing numbers (dates)
|
125
|
-
if (parsed || parser.type === 'numeric') {
|
126
|
-
|
127
|
-
|
138
|
+
// parse filter value in case we're comparing numbers ( dates )
|
139
|
+
if ( parsed || parser.type === 'numeric' ) {
|
140
|
+
txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) );
|
141
|
+
result = ts.filter.parseFilter( c, txt, index, true );
|
142
|
+
query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
|
128
143
|
}
|
129
|
-
|
130
144
|
// iExact may be numeric - see issue #149;
|
131
|
-
// check if cached is defined, because sometimes j goes out of range? (numeric columns)
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
145
|
+
// check if cached is defined, because sometimes j goes out of range? ( numeric columns )
|
146
|
+
if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) &&
|
147
|
+
typeof data.cache !== 'undefined' ) {
|
148
|
+
cachedValue = data.cache;
|
149
|
+
} else {
|
150
|
+
txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
|
151
|
+
cachedValue = ts.formatFloat( txt, table );
|
152
|
+
}
|
153
|
+
if ( />/.test( data.iFilter ) ) {
|
154
|
+
result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
|
155
|
+
} else if ( /</.test( data.iFilter ) ) {
|
156
|
+
result = /<=/.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
|
157
|
+
}
|
138
158
|
// keep showing all rows if nothing follows the operator
|
139
|
-
if ( !result && savedSearch === '' ) {
|
159
|
+
if ( !result && savedSearch === '' ) {
|
160
|
+
result = true;
|
161
|
+
}
|
140
162
|
return result;
|
141
163
|
}
|
142
164
|
return null;
|
143
165
|
},
|
144
166
|
// Look for a not match
|
145
167
|
notMatch: function( c, data ) {
|
146
|
-
if ( /^\!/.test(data.iFilter) ) {
|
168
|
+
if ( /^\!/.test( data.iFilter ) ) {
|
147
169
|
var indx,
|
148
|
-
|
149
|
-
|
170
|
+
txt = data.iFilter.replace( '!', '' ),
|
171
|
+
filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
|
172
|
+
if ( ts.filter.regex.exact.test( filter ) ) {
|
150
173
|
// look for exact not matches - see #628
|
151
|
-
filter = filter.replace(ts.filter.regex.exact, '');
|
152
|
-
return filter === '' ? true : $.trim(filter) !== data.iExact;
|
174
|
+
filter = filter.replace( ts.filter.regex.exact, '' );
|
175
|
+
return filter === '' ? true : $.trim( filter ) !== data.iExact;
|
153
176
|
} else {
|
154
|
-
indx = data.iExact.search( $.trim(filter) );
|
155
|
-
return filter === '' ? true : !(c.widgetOptions.filter_startsWith ? indx === 0 : indx >= 0);
|
177
|
+
indx = data.iExact.search( $.trim( filter ) );
|
178
|
+
return filter === '' ? true : !( c.widgetOptions.filter_startsWith ? indx === 0 : indx >= 0 );
|
156
179
|
}
|
157
180
|
}
|
158
181
|
return null;
|
@@ -160,84 +183,101 @@ ts.filter = {
|
|
160
183
|
// Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
|
161
184
|
exact: function( c, data ) {
|
162
185
|
/*jshint eqeqeq:false */
|
163
|
-
if (ts.filter.regex.exact.test(data.iFilter)) {
|
164
|
-
var
|
165
|
-
|
186
|
+
if ( ts.filter.regex.exact.test( data.iFilter ) ) {
|
187
|
+
var txt = data.iFilter.replace( ts.filter.regex.exact, '' ),
|
188
|
+
filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
|
189
|
+
return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
|
166
190
|
}
|
167
191
|
return null;
|
168
192
|
},
|
169
|
-
// Look for an AND or && operator (logical and)
|
193
|
+
// Look for an AND or && operator ( logical and )
|
170
194
|
and : function( c, data ) {
|
171
|
-
if ( ts.filter.regex.andTest.test(data.filter) ) {
|
195
|
+
if ( ts.filter.regex.andTest.test( data.filter ) ) {
|
172
196
|
var index = data.index,
|
173
197
|
parsed = data.parsed[index],
|
174
198
|
query = data.iFilter.split( ts.filter.regex.andSplit ),
|
175
|
-
result = data.iExact.search( $.trim( ts.filter.parseFilter(c, query[0], index, parsed) ) ) >= 0,
|
199
|
+
result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0,
|
176
200
|
indx = query.length - 1;
|
177
|
-
while (result && indx) {
|
178
|
-
result = result &&
|
201
|
+
while ( result && indx ) {
|
202
|
+
result = result &&
|
203
|
+
data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0;
|
179
204
|
indx--;
|
180
205
|
}
|
181
206
|
return result;
|
182
207
|
}
|
183
208
|
return null;
|
184
209
|
},
|
185
|
-
// Look for a range (using
|
210
|
+
// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
|
186
211
|
range : function( c, data ) {
|
187
|
-
if ( ts.filter.regex.toTest.test(data.iFilter) ) {
|
188
|
-
var result, tmp,
|
212
|
+
if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
|
213
|
+
var result, tmp, range1, range2,
|
189
214
|
table = c.table,
|
190
215
|
index = data.index,
|
191
216
|
parsed = data.parsed[index],
|
192
217
|
// make sure the dash is for a range and not indicating a negative number
|
193
|
-
query = data.iFilter.split( ts.filter.regex.toSplit )
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
218
|
+
query = data.iFilter.split( ts.filter.regex.toSplit );
|
219
|
+
|
220
|
+
tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || '';
|
221
|
+
range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
|
222
|
+
tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || '';
|
223
|
+
range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
|
224
|
+
// parse filter value in case we're comparing numbers ( dates )
|
225
|
+
if ( parsed || c.parsers[index].type === 'numeric' ) {
|
226
|
+
result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
|
227
|
+
range1 = ( result !== '' && !isNaN( result ) ) ? result : range1;
|
228
|
+
result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index );
|
229
|
+
range2 = ( result !== '' && !isNaN( result ) ) ? result : range2;
|
230
|
+
}
|
231
|
+
if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
|
232
|
+
result = data.cache;
|
233
|
+
} else {
|
234
|
+
tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
|
235
|
+
result = ts.formatFloat( tmp, table );
|
236
|
+
}
|
237
|
+
if ( range1 > range2 ) {
|
238
|
+
tmp = range1; range1 = range2; range2 = tmp; // swap
|
202
239
|
}
|
203
|
-
result
|
204
|
-
isNaN(data.iExact) ? ts.formatFloat( data.iExact.replace(ts.filter.regex.nondigit, ''), table) :
|
205
|
-
ts.formatFloat( data.iExact, table );
|
206
|
-
if (range1 > range2) { tmp = range1; range1 = range2; range2 = tmp; } // swap
|
207
|
-
return (result >= range1 && result <= range2) || (range1 === '' || range2 === '');
|
240
|
+
return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' );
|
208
241
|
}
|
209
242
|
return null;
|
210
243
|
},
|
211
244
|
// Look for wild card: ? = single, * = multiple, or | = logical OR
|
212
245
|
wild : function( c, data ) {
|
213
|
-
if ( /[\?\*\|]/.test(data.iFilter) || ts.filter.regex.orReplace.test(data.filter) ) {
|
246
|
+
if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) {
|
214
247
|
var index = data.index,
|
215
|
-
parsed = data.parsed[index],
|
216
|
-
|
217
|
-
|
218
|
-
|
248
|
+
parsed = data.parsed[ index ],
|
249
|
+
txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ),
|
250
|
+
query = ts.filter.parseFilter( c, txt, index, parsed ) || '';
|
251
|
+
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
252
|
+
if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) {
|
219
253
|
// show all results while using filter match. Fixes #727
|
220
|
-
if (query[ query.length - 1 ] === '|') {
|
221
|
-
|
254
|
+
if ( query[ query.length - 1 ] === '|' ) {
|
255
|
+
query += '*';
|
256
|
+
}
|
257
|
+
query = data.anyMatch && $.isArray( data.rowArray ) ?
|
258
|
+
'(' + query + ')' :
|
259
|
+
'^(' + query + ')$';
|
222
260
|
}
|
223
261
|
// parsing the filter may not work properly when using wildcards =/
|
224
|
-
return new RegExp( query.replace(/\?/g, '\\S{1}').replace(/\*/g, '\\S*') )
|
262
|
+
return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) )
|
263
|
+
.test( data.iExact );
|
225
264
|
}
|
226
265
|
return null;
|
227
266
|
},
|
228
|
-
// fuzzy text search; modified from https://github.com/mattyork/fuzzy (MIT license)
|
267
|
+
// fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
|
229
268
|
fuzzy: function( c, data ) {
|
230
|
-
if ( /^~/.test(data.iFilter) ) {
|
269
|
+
if ( /^~/.test( data.iFilter ) ) {
|
231
270
|
var indx,
|
232
271
|
patternIndx = 0,
|
233
272
|
len = data.iExact.length,
|
234
|
-
|
235
|
-
|
236
|
-
|
273
|
+
txt = data.iFilter.slice( 1 ),
|
274
|
+
pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
|
275
|
+
for ( indx = 0; indx < len; indx++ ) {
|
276
|
+
if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
|
237
277
|
patternIndx += 1;
|
238
278
|
}
|
239
279
|
}
|
240
|
-
if (patternIndx === pattern.length) {
|
280
|
+
if ( patternIndx === pattern.length ) {
|
241
281
|
return true;
|
242
282
|
}
|
243
283
|
return false;
|
@@ -245,17 +285,17 @@ ts.filter = {
|
|
245
285
|
return null;
|
246
286
|
}
|
247
287
|
},
|
248
|
-
init: function(table, c, wo) {
|
288
|
+
init: function( table, c, wo ) {
|
249
289
|
// filter language options
|
250
|
-
ts.language = $.extend(true, {}, {
|
290
|
+
ts.language = $.extend( true, {}, {
|
251
291
|
to : 'to',
|
252
292
|
or : 'or',
|
253
293
|
and : 'and'
|
254
|
-
}, ts.language);
|
294
|
+
}, ts.language );
|
255
295
|
|
256
296
|
var options, string, txt, $header, column, filters, val, fxn, noSelect,
|
257
297
|
regex = ts.filter.regex;
|
258
|
-
c.$table.addClass('hasFilters');
|
298
|
+
c.$table.addClass( 'hasFilters' );
|
259
299
|
|
260
300
|
// define timers so using clearTimeout won't cause an undefined error
|
261
301
|
wo.searchTimer = null;
|
@@ -265,512 +305,566 @@ ts.filter = {
|
|
265
305
|
wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
|
266
306
|
wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
|
267
307
|
|
268
|
-
|
308
|
+
val = '\\{' + ts.filter.regex.query + '\\}';
|
269
309
|
$.extend( regex, {
|
270
|
-
child : new RegExp(c.cssChildRow),
|
271
|
-
filtered : new RegExp(wo.filter_filteredRow),
|
272
|
-
alreadyFiltered : new RegExp('(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i'),
|
273
|
-
toTest : new RegExp('\\s+(-|' + ts.language.to + ')\\s+', 'i'),
|
274
|
-
toSplit : new RegExp('(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi'),
|
275
|
-
andTest : new RegExp('\\s+(' + ts.language.and + '|&&)\\s+', 'i'),
|
276
|
-
andSplit : new RegExp('(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi'),
|
277
|
-
orReplace : new RegExp('\\s+(' + ts.language.or + ')\\s+', 'gi'),
|
278
|
-
iQuery : new RegExp(
|
279
|
-
igQuery : new RegExp(
|
310
|
+
child : new RegExp( c.cssChildRow ),
|
311
|
+
filtered : new RegExp( wo.filter_filteredRow ),
|
312
|
+
alreadyFiltered : new RegExp( '(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i' ),
|
313
|
+
toTest : new RegExp( '\\s+(-|' + ts.language.to + ')\\s+', 'i' ),
|
314
|
+
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
|
315
|
+
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
|
316
|
+
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
|
317
|
+
orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ),
|
318
|
+
iQuery : new RegExp( val, 'i' ),
|
319
|
+
igQuery : new RegExp( val, 'ig' )
|
280
320
|
});
|
281
321
|
|
282
|
-
// don't build filter row if columnFilters is false or all columns are set to
|
283
|
-
|
322
|
+
// don't build filter row if columnFilters is false or all columns are set to 'filter-false'
|
323
|
+
// see issue #156
|
324
|
+
val = c.$headers.filter( '.filter-false, .parser-false' ).length;
|
325
|
+
if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
|
284
326
|
// build filter row
|
285
|
-
ts.filter.buildRow(table, c, wo);
|
327
|
+
ts.filter.buildRow( table, c, wo );
|
286
328
|
}
|
287
329
|
|
288
|
-
txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
330
|
+
txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
|
331
|
+
.split( ' ' ).join( c.namespace + 'filter ' );
|
332
|
+
c.$table.bind( txt, function( event, filter ) {
|
333
|
+
val = wo.filter_hideEmpty &&
|
334
|
+
$.isEmptyObject( c.cache ) &&
|
335
|
+
!( c.delayInit && event.type === 'appendCache' );
|
336
|
+
// hide filter row using the 'filtered' class name
|
337
|
+
c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
|
338
|
+
if ( !/(search|filter)/.test( event.type ) ) {
|
294
339
|
event.stopPropagation();
|
295
|
-
ts.filter.buildDefault(table, true);
|
340
|
+
ts.filter.buildDefault( table, true );
|
296
341
|
}
|
297
|
-
if (event.type === 'filterReset') {
|
298
|
-
c.$table.find('.' + tscss.filter).add(wo.filter_$externalFilters).val('');
|
299
|
-
ts.filter.searching(table, []);
|
300
|
-
} else if (event.type === 'filterEnd') {
|
301
|
-
ts.filter.buildDefault(table, true);
|
342
|
+
if ( event.type === 'filterReset' ) {
|
343
|
+
c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
|
344
|
+
ts.filter.searching( table, [] );
|
345
|
+
} else if ( event.type === 'filterEnd' ) {
|
346
|
+
ts.filter.buildDefault( table, true );
|
302
347
|
} else {
|
303
|
-
// send false argument to force a new search; otherwise if the filter hasn't changed,
|
304
|
-
|
305
|
-
|
348
|
+
// send false argument to force a new search; otherwise if the filter hasn't changed,
|
349
|
+
// it will return
|
350
|
+
filter = event.type === 'search' ? filter :
|
351
|
+
event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : '';
|
352
|
+
if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) {
|
306
353
|
// force a new search since content has changed
|
307
354
|
c.lastCombinedFilter = null;
|
308
355
|
c.lastSearch = [];
|
309
356
|
}
|
310
|
-
// pass true (skipFirst) to prevent the tablesorter.setFilters function from skipping the first
|
311
|
-
// ensures all inputs are updated when a search is triggered on the table
|
312
|
-
|
357
|
+
// pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
|
358
|
+
// input ensures all inputs are updated when a search is triggered on the table
|
359
|
+
// $( 'table' ).trigger( 'search', [...] );
|
360
|
+
ts.filter.searching( table, filter, true );
|
313
361
|
}
|
314
362
|
return false;
|
315
363
|
});
|
316
364
|
|
317
365
|
// reset button/link
|
318
|
-
if (wo.filter_reset) {
|
319
|
-
if (wo.filter_reset instanceof $) {
|
366
|
+
if ( wo.filter_reset ) {
|
367
|
+
if ( wo.filter_reset instanceof $ ) {
|
320
368
|
// reset contains a jQuery object, bind to it
|
321
|
-
wo.filter_reset.click(function(){
|
322
|
-
c.$table.trigger('filterReset');
|
369
|
+
wo.filter_reset.click( function() {
|
370
|
+
c.$table.trigger( 'filterReset' );
|
323
371
|
});
|
324
|
-
} else if ($(wo.filter_reset).length) {
|
372
|
+
} else if ( $( wo.filter_reset ).length ) {
|
325
373
|
// reset is a jQuery selector, use event delegation
|
326
|
-
$(document)
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
374
|
+
$( document )
|
375
|
+
.undelegate( wo.filter_reset, 'click.tsfilter' )
|
376
|
+
.delegate( wo.filter_reset, 'click.tsfilter', function() {
|
377
|
+
// trigger a reset event, so other functions ( filter_formatter ) know when to reset
|
378
|
+
c.$table.trigger( 'filterReset' );
|
379
|
+
});
|
332
380
|
}
|
333
381
|
}
|
334
|
-
if (wo.filter_functions) {
|
335
|
-
for (column = 0; column < c.columns; column++) {
|
382
|
+
if ( wo.filter_functions ) {
|
383
|
+
for ( column = 0; column < c.columns; column++ ) {
|
336
384
|
fxn = ts.getColumnData( table, wo.filter_functions, column );
|
337
|
-
if (fxn) {
|
338
|
-
// remove
|
339
|
-
|
340
|
-
|
341
|
-
|
385
|
+
if ( fxn ) {
|
386
|
+
// remove 'filter-select' from header otherwise the options added here are replaced with
|
387
|
+
// all options
|
388
|
+
$header = c.$headerIndexed[ column ].removeClass( 'filter-select' );
|
389
|
+
// don't build select if 'filter-false' or 'parser-false' set
|
390
|
+
noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
|
342
391
|
options = '';
|
343
392
|
if ( fxn === true && noSelect ) {
|
344
|
-
ts.filter.buildSelect(table, column);
|
393
|
+
ts.filter.buildSelect( table, column );
|
345
394
|
} else if ( typeof fxn === 'object' && noSelect ) {
|
346
395
|
// add custom drop down list
|
347
|
-
for (string in fxn) {
|
348
|
-
if (typeof string === 'string') {
|
396
|
+
for ( string in fxn ) {
|
397
|
+
if ( typeof string === 'string' ) {
|
349
398
|
options += options === '' ?
|
350
|
-
'<option value="">' +
|
399
|
+
'<option value="">' +
|
400
|
+
( $header.data( 'placeholder' ) ||
|
401
|
+
$header.attr( 'data-placeholder' ) ||
|
402
|
+
wo.filter_placeholder.select ||
|
403
|
+
''
|
404
|
+
) +
|
405
|
+
'</option>' : '';
|
351
406
|
val = string;
|
352
407
|
txt = string;
|
353
|
-
if (string.indexOf(wo.filter_selectSourceSeparator) >= 0) {
|
354
|
-
val = string.split(wo.filter_selectSourceSeparator);
|
408
|
+
if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
|
409
|
+
val = string.split( wo.filter_selectSourceSeparator );
|
355
410
|
txt = val[1];
|
356
411
|
val = val[0];
|
357
412
|
}
|
358
|
-
options += '<option ' +
|
413
|
+
options += '<option ' +
|
414
|
+
( txt === val ? '' : 'data-function-name="' + string + '" ' ) +
|
415
|
+
'value="' + val + '">' + txt + '</option>';
|
359
416
|
}
|
360
417
|
}
|
361
|
-
c.$table
|
418
|
+
c.$table
|
419
|
+
.find( 'thead' )
|
420
|
+
.find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
|
421
|
+
.append( options );
|
362
422
|
txt = wo.filter_selectSource;
|
363
|
-
fxn = $.isFunction(txt) ? true : ts.getColumnData( table, txt, column );
|
364
|
-
if (fxn) {
|
423
|
+
fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column );
|
424
|
+
if ( fxn ) {
|
365
425
|
// updating so the extra options are appended
|
366
|
-
ts.filter.buildSelect(c.table, column, '', true, $header.hasClass(wo.filter_onlyAvail));
|
426
|
+
ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
|
367
427
|
}
|
368
428
|
}
|
369
429
|
}
|
370
430
|
}
|
371
431
|
}
|
372
|
-
// not really updating, but if the column has both the
|
373
|
-
// it would append the same options twice.
|
374
|
-
ts.filter.buildDefault(table, true);
|
432
|
+
// not really updating, but if the column has both the 'filter-select' class &
|
433
|
+
// filter_functions set to true, it would append the same options twice.
|
434
|
+
ts.filter.buildDefault( table, true );
|
375
435
|
|
376
|
-
ts.filter.bindSearch( table, c.$table.find('.' + tscss.filter), true );
|
377
|
-
if (wo.filter_external) {
|
436
|
+
ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
|
437
|
+
if ( wo.filter_external ) {
|
378
438
|
ts.filter.bindSearch( table, wo.filter_external );
|
379
439
|
}
|
380
440
|
|
381
|
-
if (wo.filter_hideFilters) {
|
382
|
-
ts.filter.hideFilters(table, c);
|
441
|
+
if ( wo.filter_hideFilters ) {
|
442
|
+
ts.filter.hideFilters( table, c );
|
383
443
|
}
|
384
444
|
|
385
445
|
// show processing icon
|
386
|
-
if (c.showProcessing) {
|
446
|
+
if ( c.showProcessing ) {
|
447
|
+
txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
|
387
448
|
c.$table
|
388
|
-
.unbind(
|
389
|
-
.bind(
|
449
|
+
.unbind( txt.replace( /\s+/g, ' ' ) )
|
450
|
+
.bind( txt, function( event, columns ) {
|
390
451
|
// only add processing to certain columns to all columns
|
391
|
-
$header = (columns) ?
|
392
|
-
|
393
|
-
|
394
|
-
|
452
|
+
$header = ( columns ) ?
|
453
|
+
c.$table
|
454
|
+
.find( '.' + tscss.header )
|
455
|
+
.filter( '[data-column]' )
|
456
|
+
.filter( function() {
|
457
|
+
return columns[ $( this ).data( 'column' ) ] !== '';
|
458
|
+
}) : '';
|
459
|
+
ts.isProcessing( table, event.type === 'filterStart', columns ? $header : '' );
|
395
460
|
});
|
396
461
|
}
|
397
462
|
|
398
|
-
// set filtered rows count (intially unfiltered)
|
463
|
+
// set filtered rows count ( intially unfiltered )
|
399
464
|
c.filteredRows = c.totalRows;
|
400
465
|
|
401
466
|
// add default values
|
467
|
+
txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
|
402
468
|
c.$table
|
403
|
-
.unbind(
|
404
|
-
.bind(
|
405
|
-
// redefine
|
469
|
+
.unbind( txt.replace( /\s+/g, ' ' ) )
|
470
|
+
.bind( txt, function() {
|
471
|
+
// redefine 'wo' as it does not update properly inside this callback
|
406
472
|
var wo = this.config.widgetOptions;
|
407
|
-
filters = ts.filter.setDefaults(table, c, wo) || [];
|
408
|
-
if (filters.length) {
|
473
|
+
filters = ts.filter.setDefaults( table, c, wo ) || [];
|
474
|
+
if ( filters.length ) {
|
409
475
|
// prevent delayInit from triggering a cache build if filters are empty
|
410
|
-
if ( !(c.delayInit && filters.join('') === '') ) {
|
411
|
-
ts.setFilters(table, filters, true);
|
476
|
+
if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
|
477
|
+
ts.setFilters( table, filters, true );
|
412
478
|
}
|
413
479
|
}
|
414
|
-
c.$table.trigger('filterFomatterUpdate');
|
480
|
+
c.$table.trigger( 'filterFomatterUpdate' );
|
415
481
|
// trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
|
416
|
-
setTimeout(function(){
|
417
|
-
if (!wo.filter_initialized) {
|
418
|
-
ts.filter.filterInitComplete(c);
|
482
|
+
setTimeout( function() {
|
483
|
+
if ( !wo.filter_initialized ) {
|
484
|
+
ts.filter.filterInitComplete( c );
|
419
485
|
}
|
420
|
-
}, 100);
|
486
|
+
}, 100 );
|
421
487
|
});
|
422
488
|
// if filter widget is added after pager has initialized; then set filter init flag
|
423
|
-
if (c.pager && c.pager.initialized && !wo.filter_initialized) {
|
424
|
-
c.$table.trigger('filterFomatterUpdate');
|
425
|
-
setTimeout(function(){
|
426
|
-
ts.filter.filterInitComplete(c);
|
427
|
-
}, 100);
|
489
|
+
if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
|
490
|
+
c.$table.trigger( 'filterFomatterUpdate' );
|
491
|
+
setTimeout( function() {
|
492
|
+
ts.filter.filterInitComplete( c );
|
493
|
+
}, 100 );
|
428
494
|
}
|
429
495
|
},
|
430
|
-
// $cell parameter, but not the config, is passed to the
|
431
|
-
//
|
432
|
-
formatterUpdated: function($cell, column) {
|
433
|
-
var wo = $cell.closest('table')[0].config.widgetOptions;
|
434
|
-
if (!wo.filter_initialized) {
|
496
|
+
// $cell parameter, but not the config, is passed to the filter_formatters,
|
497
|
+
// so we have to work with it instead
|
498
|
+
formatterUpdated: function( $cell, column ) {
|
499
|
+
var wo = $cell.closest( 'table' )[0].config.widgetOptions;
|
500
|
+
if ( !wo.filter_initialized ) {
|
435
501
|
// add updates by column since this function
|
436
502
|
// may be called numerous times before initialization
|
437
|
-
wo.filter_formatterInit[column] = 1;
|
503
|
+
wo.filter_formatterInit[ column ] = 1;
|
438
504
|
}
|
439
505
|
},
|
440
|
-
filterInitComplete: function(c){
|
506
|
+
filterInitComplete: function( c ) {
|
441
507
|
var indx, len,
|
442
508
|
wo = c.widgetOptions,
|
443
509
|
count = 0,
|
444
|
-
completed = function(){
|
510
|
+
completed = function() {
|
445
511
|
wo.filter_initialized = true;
|
446
|
-
c.$table.trigger('filterInit', c);
|
447
|
-
ts.filter.findRows(c.table, c.$table.data('lastSearch') || []);
|
512
|
+
c.$table.trigger( 'filterInit', c );
|
513
|
+
ts.filter.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
|
448
514
|
};
|
449
515
|
if ( $.isEmptyObject( wo.filter_formatter ) ) {
|
450
516
|
completed();
|
451
517
|
} else {
|
452
518
|
len = wo.filter_formatterInit.length;
|
453
|
-
for (indx = 0; indx < len; indx++) {
|
454
|
-
if (wo.filter_formatterInit[indx] === 1) {
|
519
|
+
for ( indx = 0; indx < len; indx++ ) {
|
520
|
+
if ( wo.filter_formatterInit[ indx ] === 1 ) {
|
455
521
|
count++;
|
456
522
|
}
|
457
523
|
}
|
458
|
-
clearTimeout(wo.filter_initTimer);
|
459
|
-
if (!wo.filter_initialized && count === wo.filter_formatterCount) {
|
524
|
+
clearTimeout( wo.filter_initTimer );
|
525
|
+
if ( !wo.filter_initialized && count === wo.filter_formatterCount ) {
|
460
526
|
// filter widget initialized
|
461
527
|
completed();
|
462
|
-
} else if (!wo.filter_initialized) {
|
528
|
+
} else if ( !wo.filter_initialized ) {
|
463
529
|
// fall back in case a filter_formatter doesn't call
|
464
|
-
// $.tablesorter.filter.formatterUpdated($cell, column), and the count is off
|
465
|
-
wo.filter_initTimer = setTimeout(function(){
|
530
|
+
// $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off
|
531
|
+
wo.filter_initTimer = setTimeout( function() {
|
466
532
|
completed();
|
467
|
-
}, 500);
|
533
|
+
}, 500 );
|
468
534
|
}
|
469
535
|
}
|
470
536
|
},
|
471
537
|
|
472
|
-
setDefaults: function(table, c, wo) {
|
538
|
+
setDefaults: function( table, c, wo ) {
|
473
539
|
var isArray, saved, indx, col, $filters,
|
474
|
-
// get current (default) filters
|
475
|
-
filters = ts.getFilters(table) || [];
|
476
|
-
if (wo.filter_saveFilters && ts.storage) {
|
540
|
+
// get current ( default ) filters
|
541
|
+
filters = ts.getFilters( table ) || [];
|
542
|
+
if ( wo.filter_saveFilters && ts.storage ) {
|
477
543
|
saved = ts.storage( table, 'tablesorter-filters' ) || [];
|
478
|
-
isArray = $.isArray(saved);
|
544
|
+
isArray = $.isArray( saved );
|
479
545
|
// make sure we're not just getting an empty array
|
480
|
-
if ( !(isArray && saved.join('') === '' || !isArray) ) {
|
546
|
+
if ( !( isArray && saved.join( '' ) === '' || !isArray ) ) {
|
547
|
+
filters = saved;
|
548
|
+
}
|
481
549
|
}
|
482
550
|
// if no filters saved, then check default settings
|
483
|
-
if (filters.join('') === '') {
|
551
|
+
if ( filters.join( '' ) === '' ) {
|
484
552
|
// allow adding default setting to external filters
|
485
|
-
$filters = c.$headers.add( wo.filter_$externalFilters )
|
486
|
-
|
487
|
-
|
553
|
+
$filters = c.$headers.add( wo.filter_$externalFilters )
|
554
|
+
.filter( '[' + wo.filter_defaultAttrib + ']' );
|
555
|
+
for ( indx = 0; indx <= c.columns; indx++ ) {
|
556
|
+
// include data-column='all' external filters
|
488
557
|
col = indx === c.columns ? 'all' : indx;
|
489
|
-
filters[indx] = $filters
|
558
|
+
filters[indx] = $filters
|
559
|
+
.filter( '[data-column="' + col + '"]' )
|
560
|
+
.attr( wo.filter_defaultAttrib ) || filters[indx] || '';
|
490
561
|
}
|
491
562
|
}
|
492
|
-
c.$table.data('lastSearch', filters);
|
563
|
+
c.$table.data( 'lastSearch', filters );
|
493
564
|
return filters;
|
494
565
|
},
|
495
|
-
parseFilter: function(c, filter, column, parsed
|
496
|
-
return
|
497
|
-
c.parsers[column].format( filter, c.table, [], column ) :
|
498
|
-
filter;
|
566
|
+
parseFilter: function( c, filter, column, parsed ) {
|
567
|
+
return parsed ? c.parsers[column].format( filter, c.table, [], column ) : filter;
|
499
568
|
},
|
500
|
-
buildRow: function(table, c, wo) {
|
501
|
-
var col, column, $header, buildSelect, disabled, name, ffxn,
|
569
|
+
buildRow: function( table, c, wo ) {
|
570
|
+
var col, column, $header, buildSelect, disabled, name, ffxn, tmp,
|
502
571
|
// c.columns defined in computeThIndexes()
|
572
|
+
cellFilter = wo.filter_cellFilter,
|
503
573
|
columns = c.columns,
|
504
|
-
arry = $.isArray(
|
574
|
+
arry = $.isArray( cellFilter ),
|
505
575
|
buildFilter = '<tr role="row" class="' + tscss.filterRow + ' ' + c.cssIgnoreRow + '">';
|
506
|
-
for (column = 0; column < columns; column++) {
|
507
|
-
|
508
|
-
|
576
|
+
for ( column = 0; column < columns; column++ ) {
|
577
|
+
buildFilter += '<td';
|
578
|
+
if ( arry ) {
|
579
|
+
buildFilter += ( cellFilter[ column ] ? ' class="' + cellFilter[ column ] + '"' : '' );
|
509
580
|
} else {
|
510
|
-
buildFilter +=
|
581
|
+
buildFilter += ( cellFilter !== '' ? ' class="' + cellFilter + '"' : '' );
|
511
582
|
}
|
583
|
+
buildFilter += '></td>';
|
512
584
|
}
|
513
|
-
c.$filters = $(buildFilter += '</tr>'
|
585
|
+
c.$filters = $( buildFilter += '</tr>' )
|
586
|
+
.appendTo( c.$table.children( 'thead' ).eq( 0 ) )
|
587
|
+
.find( 'td' );
|
514
588
|
// build each filter input
|
515
|
-
for (column = 0; column < columns; column++) {
|
589
|
+
for ( column = 0; column < columns; column++ ) {
|
516
590
|
disabled = false;
|
517
591
|
// assuming last cell of a column is the main column
|
518
|
-
$header = c.$headerIndexed[column];
|
592
|
+
$header = c.$headerIndexed[ column ];
|
519
593
|
ffxn = ts.getColumnData( table, wo.filter_functions, column );
|
520
|
-
buildSelect = (wo.filter_functions && ffxn && typeof ffxn !==
|
521
|
-
$header.hasClass('filter-select');
|
594
|
+
buildSelect = ( wo.filter_functions && ffxn && typeof ffxn !== 'function' ) ||
|
595
|
+
$header.hasClass( 'filter-select' );
|
522
596
|
// get data from jQuery data, metadata, headers option or header class name
|
523
597
|
col = ts.getColumnData( table, c.headers, column );
|
524
|
-
disabled = ts.getData($header[0], col, 'filter') === 'false' ||
|
598
|
+
disabled = ts.getData( $header[0], col, 'filter' ) === 'false' ||
|
599
|
+
ts.getData( $header[0], col, 'parser' ) === 'false';
|
525
600
|
|
526
|
-
if (buildSelect) {
|
527
|
-
buildFilter = $('<select>').appendTo( c.$filters.eq(column) );
|
601
|
+
if ( buildSelect ) {
|
602
|
+
buildFilter = $( '<select>' ).appendTo( c.$filters.eq( column ) );
|
528
603
|
} else {
|
529
604
|
ffxn = ts.getColumnData( table, wo.filter_formatter, column );
|
530
|
-
if (ffxn) {
|
605
|
+
if ( ffxn ) {
|
531
606
|
wo.filter_formatterCount++;
|
532
|
-
buildFilter = ffxn( c.$filters.eq(column), column );
|
607
|
+
buildFilter = ffxn( c.$filters.eq( column ), column );
|
533
608
|
// no element returned, so lets go find it
|
534
|
-
if (buildFilter && buildFilter.length === 0) {
|
535
|
-
buildFilter = c.$filters.eq(column).children('input');
|
609
|
+
if ( buildFilter && buildFilter.length === 0 ) {
|
610
|
+
buildFilter = c.$filters.eq( column ).children( 'input' );
|
536
611
|
}
|
537
612
|
// element not in DOM, so lets attach it
|
538
|
-
if ( buildFilter && (buildFilter.parent().length === 0 ||
|
539
|
-
(buildFilter.parent().length && buildFilter.parent()[0] !== c.$filters[column])) ) {
|
540
|
-
c.$filters.eq(column).append(buildFilter);
|
613
|
+
if ( buildFilter && ( buildFilter.parent().length === 0 ||
|
614
|
+
( buildFilter.parent().length && buildFilter.parent()[0] !== c.$filters[column] ) ) ) {
|
615
|
+
c.$filters.eq( column ).append( buildFilter );
|
541
616
|
}
|
542
617
|
} else {
|
543
|
-
buildFilter = $('<input type="search">').appendTo( c.$filters.eq(column) );
|
618
|
+
buildFilter = $( '<input type="search">' ).appendTo( c.$filters.eq( column ) );
|
544
619
|
}
|
545
|
-
if (buildFilter) {
|
546
|
-
|
620
|
+
if ( buildFilter ) {
|
621
|
+
tmp = $header.data( 'placeholder' ) ||
|
622
|
+
$header.attr( 'data-placeholder' ) ||
|
623
|
+
wo.filter_placeholder.search || '';
|
624
|
+
buildFilter.attr( 'placeholder', tmp );
|
547
625
|
}
|
548
626
|
}
|
549
|
-
if (buildFilter) {
|
627
|
+
if ( buildFilter ) {
|
550
628
|
// add filter class name
|
551
|
-
name = ( $.isArray(wo.filter_cssFilter) ?
|
552
|
-
(typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '') :
|
629
|
+
name = ( $.isArray( wo.filter_cssFilter ) ?
|
630
|
+
( typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '' ) :
|
553
631
|
wo.filter_cssFilter ) || '';
|
554
|
-
buildFilter.addClass( tscss.filter + ' ' + name ).attr('data-column', column);
|
555
|
-
if (disabled) {
|
556
|
-
buildFilter.attr('placeholder', '').addClass(tscss.filterDisabled)[0].disabled = true;
|
632
|
+
buildFilter.addClass( tscss.filter + ' ' + name ).attr( 'data-column', column );
|
633
|
+
if ( disabled ) {
|
634
|
+
buildFilter.attr( 'placeholder', '' ).addClass( tscss.filterDisabled )[0].disabled = true;
|
557
635
|
}
|
558
636
|
}
|
559
637
|
}
|
560
638
|
},
|
561
|
-
bindSearch: function(table, $el, internal) {
|
562
|
-
table = $(table)[0];
|
563
|
-
$el = $($el); // allow passing a selector string
|
564
|
-
if (!$el.length) { return; }
|
565
|
-
var
|
639
|
+
bindSearch: function( table, $el, internal ) {
|
640
|
+
table = $( table )[0];
|
641
|
+
$el = $( $el ); // allow passing a selector string
|
642
|
+
if ( !$el.length ) { return; }
|
643
|
+
var tmp,
|
644
|
+
c = table.config,
|
566
645
|
wo = c.widgetOptions,
|
646
|
+
namespace = c.namespace + 'filter',
|
567
647
|
$ext = wo.filter_$externalFilters;
|
568
|
-
if (internal !== true) {
|
648
|
+
if ( internal !== true ) {
|
569
649
|
// save anyMatch element
|
570
|
-
|
571
|
-
|
650
|
+
tmp = wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector;
|
651
|
+
wo.filter_$anyMatch = $el.filter( tmp );
|
652
|
+
if ( $ext && $ext.length ) {
|
572
653
|
wo.filter_$externalFilters = wo.filter_$externalFilters.add( $el );
|
573
654
|
} else {
|
574
655
|
wo.filter_$externalFilters = $el;
|
575
656
|
}
|
576
|
-
// update values (external filters added after table initialization)
|
577
|
-
ts.setFilters(table, c.$table.data('lastSearch') || [], internal === false);
|
657
|
+
// update values ( external filters added after table initialization )
|
658
|
+
ts.setFilters( table, c.$table.data( 'lastSearch' ) || [], internal === false );
|
578
659
|
}
|
660
|
+
// unbind events
|
661
|
+
tmp = ( 'keypress keyup search change '.split( ' ' ).join( namespace + ' ' ) );
|
579
662
|
$el
|
580
|
-
// use data attribute instead of jQuery data since the head is cloned without including
|
581
|
-
|
582
|
-
.
|
663
|
+
// use data attribute instead of jQuery data since the head is cloned without including
|
664
|
+
// the data/binding
|
665
|
+
.attr( 'data-lastSearchTime', new Date().getTime() )
|
666
|
+
.unbind( tmp.replace( /\s+/g, ' ' ) )
|
583
667
|
// include change for select - fixes #473
|
584
|
-
.bind('keyup' +
|
585
|
-
$(this).attr('data-lastSearchTime', new Date().getTime());
|
668
|
+
.bind( 'keyup' + namespace, function( event ) {
|
669
|
+
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
|
586
670
|
// emulate what webkit does.... escape clears the filter
|
587
|
-
if (event.which === 27) {
|
671
|
+
if ( event.which === 27 ) {
|
588
672
|
this.value = '';
|
589
673
|
// live search
|
590
674
|
} else if ( wo.filter_liveSearch === false ) {
|
591
675
|
return;
|
592
|
-
// don't return if the search value is empty (all rows need to be revealed)
|
676
|
+
// don't return if the search value is empty ( all rows need to be revealed )
|
593
677
|
} else if ( this.value !== '' && (
|
594
678
|
// liveSearch can contain a min value length; ignore arrow and meta keys, but allow backspace
|
595
679
|
( typeof wo.filter_liveSearch === 'number' && this.value.length < wo.filter_liveSearch ) ||
|
596
680
|
// let return & backspace continue on, but ignore arrows & non-valid characters
|
597
|
-
( event.which !== 13 && event.which !== 8 &&
|
681
|
+
( event.which !== 13 && event.which !== 8 &&
|
682
|
+
( event.which < 32 || ( event.which >= 37 && event.which <= 40 ) ) ) ) ) {
|
598
683
|
return;
|
599
684
|
}
|
600
685
|
// change event = no delay; last true flag tells getFilters to skip newest timed input
|
601
686
|
ts.filter.searching( table, true, true );
|
602
687
|
})
|
603
|
-
.bind( 'search change keypress '.split(' ').join(
|
604
|
-
var column = $(this).data('column');
|
605
|
-
// don't allow
|
606
|
-
if (event.which === 13 || event.type === 'search' ||
|
688
|
+
.bind( 'search change keypress '.split( ' ' ).join( namespace + ' ' ), function( event ) {
|
689
|
+
var column = $( this ).data( 'column' );
|
690
|
+
// don't allow 'change' event to process if the input value is the same - fixes #685
|
691
|
+
if ( event.which === 13 || event.type === 'search' ||
|
692
|
+
event.type === 'change' && this.value !== c.lastSearch[column] ) {
|
607
693
|
event.preventDefault();
|
608
694
|
// init search with no delay
|
609
|
-
$(this).attr('data-lastSearchTime', new Date().getTime());
|
695
|
+
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
|
610
696
|
ts.filter.searching( table, false, true );
|
611
697
|
}
|
612
698
|
});
|
613
699
|
},
|
614
|
-
searching: function(table, filter, skipFirst) {
|
700
|
+
searching: function( table, filter, skipFirst ) {
|
615
701
|
var wo = table.config.widgetOptions;
|
616
|
-
clearTimeout(wo.searchTimer);
|
617
|
-
if (typeof filter === 'undefined' || filter === true) {
|
702
|
+
clearTimeout( wo.searchTimer );
|
703
|
+
if ( typeof filter === 'undefined' || filter === true ) {
|
618
704
|
// delay filtering
|
619
|
-
wo.searchTimer = setTimeout(function() {
|
620
|
-
ts.filter.checkFilters(table, filter, skipFirst );
|
621
|
-
}, wo.filter_liveSearch ? wo.filter_searchDelay : 10);
|
705
|
+
wo.searchTimer = setTimeout( function() {
|
706
|
+
ts.filter.checkFilters( table, filter, skipFirst );
|
707
|
+
}, wo.filter_liveSearch ? wo.filter_searchDelay : 10 );
|
622
708
|
} else {
|
623
709
|
// skip delay
|
624
|
-
ts.filter.checkFilters(table, filter, skipFirst);
|
710
|
+
ts.filter.checkFilters( table, filter, skipFirst );
|
625
711
|
}
|
626
712
|
},
|
627
|
-
checkFilters: function(table, filter, skipFirst) {
|
713
|
+
checkFilters: function( table, filter, skipFirst ) {
|
628
714
|
var c = table.config,
|
629
715
|
wo = c.widgetOptions,
|
630
|
-
filterArray = $.isArray(filter),
|
631
|
-
filters = (filterArray) ? filter : ts.getFilters(table, true),
|
632
|
-
combinedFilters = (filters || []).join(''); // combined filter values
|
716
|
+
filterArray = $.isArray( filter ),
|
717
|
+
filters = ( filterArray ) ? filter : ts.getFilters( table, true ),
|
718
|
+
combinedFilters = ( filters || [] ).join( '' ); // combined filter values
|
633
719
|
// prevent errors if delay init is set
|
634
|
-
if ($.isEmptyObject(c.cache)) {
|
635
|
-
// update cache if delayInit set & pager has initialized (after user initiates a search)
|
636
|
-
if (c.delayInit && c.pager && c.pager.initialized) {
|
637
|
-
c.$table.trigger('updateCache', [function(){
|
638
|
-
ts.filter.checkFilters(table, false, skipFirst);
|
639
|
-
}] );
|
720
|
+
if ( $.isEmptyObject( c.cache ) ) {
|
721
|
+
// update cache if delayInit set & pager has initialized ( after user initiates a search )
|
722
|
+
if ( c.delayInit && c.pager && c.pager.initialized ) {
|
723
|
+
c.$table.trigger( 'updateCache', [ function() {
|
724
|
+
ts.filter.checkFilters( table, false, skipFirst );
|
725
|
+
} ] );
|
640
726
|
}
|
641
727
|
return;
|
642
728
|
}
|
643
729
|
// add filter array back into inputs
|
644
|
-
if (filterArray) {
|
730
|
+
if ( filterArray ) {
|
645
731
|
ts.setFilters( table, filters, false, skipFirst !== true );
|
646
|
-
if (!wo.filter_initialized) { c.lastCombinedFilter = ''; }
|
732
|
+
if ( !wo.filter_initialized ) { c.lastCombinedFilter = ''; }
|
647
733
|
}
|
648
|
-
if (wo.filter_hideFilters) {
|
734
|
+
if ( wo.filter_hideFilters ) {
|
649
735
|
// show/hide filter row as needed
|
650
|
-
c.$table
|
736
|
+
c.$table
|
737
|
+
.find( '.' + tscss.filterRow )
|
738
|
+
.trigger( combinedFilters === '' ? 'mouseleave' : 'mouseenter' );
|
651
739
|
}
|
652
740
|
// return if the last search is the same; but filter === false when updating the search
|
653
741
|
// see example-widget-filter.html filter toggle buttons
|
654
|
-
if (c.lastCombinedFilter === combinedFilters && filter !== false) {
|
742
|
+
if ( c.lastCombinedFilter === combinedFilters && filter !== false ) {
|
655
743
|
return;
|
656
|
-
} else if (filter === false) {
|
744
|
+
} else if ( filter === false ) {
|
657
745
|
// force filter refresh
|
658
746
|
c.lastCombinedFilter = null;
|
659
747
|
c.lastSearch = [];
|
660
748
|
}
|
661
|
-
if (wo.filter_initialized) {
|
662
|
-
|
749
|
+
if ( wo.filter_initialized ) {
|
750
|
+
c.$table.trigger( 'filterStart', [filters] );
|
751
|
+
}
|
752
|
+
if ( c.showProcessing ) {
|
663
753
|
// give it time for the processing icon to kick in
|
664
|
-
setTimeout(function() {
|
665
|
-
ts.filter.findRows(table, filters, combinedFilters);
|
754
|
+
setTimeout( function() {
|
755
|
+
ts.filter.findRows( table, filters, combinedFilters );
|
666
756
|
return false;
|
667
|
-
}, 30);
|
757
|
+
}, 30 );
|
668
758
|
} else {
|
669
|
-
ts.filter.findRows(table, filters, combinedFilters);
|
759
|
+
ts.filter.findRows( table, filters, combinedFilters );
|
670
760
|
return false;
|
671
761
|
}
|
672
762
|
},
|
673
|
-
hideFilters: function(table, c) {
|
763
|
+
hideFilters: function( table, c ) {
|
674
764
|
var $filterRow, $filterRow2, timer;
|
675
|
-
$(table)
|
676
|
-
.find('.' + tscss.filterRow)
|
677
|
-
.addClass(tscss.filterRowHide)
|
678
|
-
.bind('mouseenter mouseleave', function(e) {
|
765
|
+
$( table )
|
766
|
+
.find( '.' + tscss.filterRow )
|
767
|
+
.addClass( tscss.filterRowHide )
|
768
|
+
.bind( 'mouseenter mouseleave', function( e ) {
|
679
769
|
// save event object - http://bugs.jquery.com/ticket/12140
|
680
770
|
var event = e;
|
681
|
-
$filterRow = $(this);
|
682
|
-
clearTimeout(timer);
|
683
|
-
timer = setTimeout(function() {
|
684
|
-
if ( /enter|over/.test(event.type) ) {
|
685
|
-
$filterRow.removeClass(tscss.filterRowHide);
|
771
|
+
$filterRow = $( this );
|
772
|
+
clearTimeout( timer );
|
773
|
+
timer = setTimeout( function() {
|
774
|
+
if ( /enter|over/.test( event.type ) ) {
|
775
|
+
$filterRow.removeClass( tscss.filterRowHide );
|
686
776
|
} else {
|
687
777
|
// don't hide if input has focus
|
688
|
-
// $(':focus') needs jQuery 1.6+
|
689
|
-
if ( $(document.activeElement).closest('tr')[0] !== $filterRow[0] ) {
|
778
|
+
// $( ':focus' ) needs jQuery 1.6+
|
779
|
+
if ( $( document.activeElement ).closest( 'tr' )[0] !== $filterRow[0] ) {
|
690
780
|
// don't hide row if any filter has a value
|
691
|
-
if (c.lastCombinedFilter === '') {
|
692
|
-
$filterRow.addClass(tscss.filterRowHide);
|
781
|
+
if ( c.lastCombinedFilter === '' ) {
|
782
|
+
$filterRow.addClass( tscss.filterRowHide );
|
693
783
|
}
|
694
784
|
}
|
695
785
|
}
|
696
|
-
}, 200);
|
786
|
+
}, 200 );
|
697
787
|
})
|
698
|
-
.find('input, select').bind('focus blur', function(e) {
|
699
|
-
$filterRow2 = $(this).closest('tr');
|
700
|
-
clearTimeout(timer);
|
788
|
+
.find( 'input, select' ).bind( 'focus blur', function( e ) {
|
789
|
+
$filterRow2 = $( this ).closest( 'tr' );
|
790
|
+
clearTimeout( timer );
|
701
791
|
var event = e;
|
702
|
-
timer = setTimeout(function() {
|
792
|
+
timer = setTimeout( function() {
|
703
793
|
// don't hide row if any filter has a value
|
704
|
-
if (ts.getFilters(c.$table).join('') === '') {
|
705
|
-
$filterRow2
|
794
|
+
if ( ts.getFilters( c.$table ).join( '' ) === '' ) {
|
795
|
+
$filterRow2.toggleClass( tscss.filterRowHide, event.type === 'focus' );
|
706
796
|
}
|
707
|
-
}, 200);
|
797
|
+
}, 200 );
|
708
798
|
});
|
709
799
|
},
|
710
|
-
defaultFilter: function(filter, mask){
|
711
|
-
if (filter === '') { return filter; }
|
800
|
+
defaultFilter: function( filter, mask ) {
|
801
|
+
if ( filter === '' ) { return filter; }
|
712
802
|
var regex = ts.filter.regex.iQuery,
|
713
803
|
maskLen = mask.match( ts.filter.regex.igQuery ).length,
|
714
|
-
query = maskLen > 1 ? $.trim(filter).split(/\s/) : [ $.trim(filter) ],
|
804
|
+
query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
|
715
805
|
len = query.length - 1,
|
716
806
|
indx = 0,
|
717
807
|
val = mask;
|
718
808
|
if ( len < 1 && maskLen > 1 ) {
|
719
|
-
// only one
|
809
|
+
// only one 'word' in query but mask has >1 slots
|
720
810
|
query[1] = query[0];
|
721
811
|
}
|
722
812
|
// replace all {query} with query words...
|
723
|
-
// if query =
|
724
|
-
// if query =
|
725
|
-
while (regex.test(val)) {
|
726
|
-
val = val.replace(regex, query[indx++] || '');
|
727
|
-
if (regex.test(val) && indx < len && (query[indx] || '') !== '') {
|
728
|
-
val = mask.replace(regex, val);
|
813
|
+
// if query = 'Bob', then convert mask from '!{query}' to '!Bob'
|
814
|
+
// if query = 'Bob Joe Frank', then convert mask '{q} OR {q}' to 'Bob OR Joe OR Frank'
|
815
|
+
while ( regex.test( val ) ) {
|
816
|
+
val = val.replace( regex, query[indx++] || '' );
|
817
|
+
if ( regex.test( val ) && indx < len && ( query[indx] || '' ) !== '' ) {
|
818
|
+
val = mask.replace( regex, val );
|
729
819
|
}
|
730
820
|
}
|
731
821
|
return val;
|
732
822
|
},
|
733
823
|
getLatestSearch: function( $input ) {
|
734
|
-
if ($input) {
|
735
|
-
return $input.sort(function(a, b) {
|
736
|
-
return $(b).attr('data-lastSearchTime') - $(a).attr('data-lastSearchTime');
|
824
|
+
if ( $input ) {
|
825
|
+
return $input.sort( function( a, b ) {
|
826
|
+
return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' );
|
737
827
|
});
|
738
828
|
}
|
739
829
|
return $();
|
740
830
|
},
|
741
831
|
multipleColumns: function( c, $input ) {
|
742
|
-
// look for multiple columns
|
832
|
+
// look for multiple columns '1-3,4-6,8' in data-column
|
743
833
|
var temp, ranges, range, start, end, singles, i, indx, len,
|
744
834
|
wo = c.widgetOptions,
|
745
|
-
// only target
|
746
|
-
// & don't target
|
747
|
-
targets = wo.filter_initialized || !$input.filter(wo.filter_anyColumnSelector).length,
|
835
|
+
// only target 'all' column inputs on initialization
|
836
|
+
// & don't target 'all' column inputs if they don't exist
|
837
|
+
targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
|
748
838
|
columns = [],
|
749
|
-
val = $.trim( ts.filter.getLatestSearch( $input ).attr('data-column') || '' );
|
839
|
+
val = $.trim( ts.filter.getLatestSearch( $input ).attr( 'data-column' ) || '' );
|
750
840
|
// process column range
|
751
841
|
if ( targets && /-/.test( val ) ) {
|
752
842
|
ranges = val.match( /(\d+)\s*-\s*(\d+)/g );
|
753
843
|
len = ranges.length;
|
754
|
-
for (indx = 0; indx < len; indx++) {
|
844
|
+
for ( indx = 0; indx < len; indx++ ) {
|
755
845
|
range = ranges[indx].split( /\s*-\s*/ );
|
756
846
|
start = parseInt( range[0], 10 ) || 0;
|
757
847
|
end = parseInt( range[1], 10 ) || ( c.columns - 1 );
|
758
|
-
if ( start > end ) {
|
759
|
-
|
848
|
+
if ( start > end ) {
|
849
|
+
temp = start; start = end; end = temp; // swap
|
850
|
+
}
|
851
|
+
if ( end >= c.columns ) {
|
852
|
+
end = c.columns - 1;
|
853
|
+
}
|
760
854
|
for ( ; start <= end; start++ ) {
|
761
|
-
columns.push(start);
|
855
|
+
columns.push( start );
|
762
856
|
}
|
763
857
|
// remove processed range from val
|
764
|
-
val = val.replace( ranges[indx], '' );
|
858
|
+
val = val.replace( ranges[ indx ], '' );
|
765
859
|
}
|
766
860
|
}
|
767
861
|
// process single columns
|
768
862
|
if ( targets && /,/.test( val ) ) {
|
769
863
|
singles = val.split( /\s*,\s*/ );
|
770
864
|
len = singles.length;
|
771
|
-
for (i = 0; i < len; i++) {
|
772
|
-
if (singles[i] !== '') {
|
773
|
-
indx = parseInt( singles[i], 10 );
|
865
|
+
for ( i = 0; i < len; i++ ) {
|
866
|
+
if ( singles[ i ] !== '' ) {
|
867
|
+
indx = parseInt( singles[ i ], 10 );
|
774
868
|
if ( indx < c.columns ) {
|
775
869
|
columns.push( indx );
|
776
870
|
}
|
@@ -778,382 +872,472 @@ ts.filter = {
|
|
778
872
|
}
|
779
873
|
}
|
780
874
|
// return all columns
|
781
|
-
if (!columns.length) {
|
875
|
+
if ( !columns.length ) {
|
782
876
|
for ( indx = 0; indx < c.columns; indx++ ) {
|
783
877
|
columns.push( indx );
|
784
878
|
}
|
785
879
|
}
|
786
880
|
return columns;
|
787
881
|
},
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
882
|
+
processRow: function( c, data, vars ) {
|
883
|
+
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch,
|
884
|
+
fxn, ffxn, txt,
|
885
|
+
regex = ts.filter.regex,
|
886
|
+
wo = c.widgetOptions,
|
887
|
+
showRow = true;
|
888
|
+
data.$cells = data.$row.children();
|
889
|
+
|
890
|
+
if ( data.anyMatchFlag ) {
|
891
|
+
// look for multiple columns '1-3,4-6,8'
|
892
|
+
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
|
893
|
+
data.anyMatch = true;
|
894
|
+
data.rowArray = data.$cells.map( function( i ) {
|
895
|
+
if ( $.inArray( i, columnIndex ) > -1 ) {
|
896
|
+
if ( data.parsed[ i ] ) {
|
897
|
+
txt = data.cacheArray[ i ];
|
898
|
+
} else {
|
899
|
+
txt = data.rawArray[ i ];
|
900
|
+
txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
|
901
|
+
if ( c.sortLocaleCompare ) {
|
902
|
+
txt = ts.replaceAccents( txt );
|
903
|
+
}
|
904
|
+
}
|
905
|
+
return txt;
|
906
|
+
}
|
907
|
+
}).get();
|
908
|
+
data.filter = data.anyMatchFilter;
|
909
|
+
data.iFilter = data.iAnyMatchFilter;
|
910
|
+
data.exact = data.rowArray.join( ' ' );
|
911
|
+
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
|
912
|
+
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
|
913
|
+
filterMatched = null;
|
914
|
+
matches = null;
|
915
|
+
for ( ffxn in ts.filter.types ) {
|
916
|
+
if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
|
917
|
+
matches = ts.filter.types[ffxn]( c, data );
|
918
|
+
if ( matches !== null ) {
|
919
|
+
filterMatched = matches;
|
920
|
+
}
|
921
|
+
}
|
922
|
+
}
|
923
|
+
if ( filterMatched !== null ) {
|
924
|
+
showRow = filterMatched;
|
925
|
+
} else {
|
926
|
+
if ( wo.filter_startsWith ) {
|
927
|
+
showRow = false;
|
928
|
+
columnIndex = c.columns;
|
929
|
+
while ( !showRow && columnIndex > 0 ) {
|
930
|
+
columnIndex--;
|
931
|
+
showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0;
|
932
|
+
}
|
933
|
+
} else {
|
934
|
+
showRow = ( data.iExact + data.childRowText ).indexOf( data.iFilter ) >= 0;
|
935
|
+
}
|
936
|
+
}
|
937
|
+
data.anyMatch = false;
|
938
|
+
// no other filters to process
|
939
|
+
if ( data.filters.join( '' ) === data.filter ) {
|
940
|
+
return showRow;
|
941
|
+
}
|
942
|
+
}
|
943
|
+
|
944
|
+
for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
|
945
|
+
data.filter = data.filters[ columnIndex ];
|
946
|
+
data.index = columnIndex;
|
947
|
+
|
948
|
+
// filter types to exclude, per column
|
949
|
+
excludeMatch = vars.excludeFilter[ columnIndex ];
|
950
|
+
|
951
|
+
// ignore if filter is empty or disabled
|
952
|
+
if ( data.filter ) {
|
953
|
+
data.cache = data.cacheArray[ columnIndex ];
|
954
|
+
// check if column data should be from the cell or from parsed data
|
955
|
+
if ( wo.filter_useParsedData || data.parsed[ columnIndex ] ) {
|
956
|
+
data.exact = data.cache;
|
957
|
+
} else {
|
958
|
+
result = data.rawArray[ columnIndex ] || '';
|
959
|
+
data.exact = c.sortLocaleCompare ? ts.replaceAccents( result ) : result; // issue #405
|
960
|
+
}
|
961
|
+
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
|
962
|
+
data.exact.toLowerCase() : data.exact;
|
963
|
+
result = showRow; // if showRow is true, show that row
|
964
|
+
|
965
|
+
// in case select filter option has a different value vs text 'a - z|A through Z'
|
966
|
+
ffxn = wo.filter_columnFilters ?
|
967
|
+
c.$filters.add( c.$externalFilters )
|
968
|
+
.filter( '[data-column="'+ columnIndex + '"]' )
|
969
|
+
.find( 'select option:selected' )
|
970
|
+
.attr( 'data-function-name' ) || '' : '';
|
971
|
+
// replace accents - see #357
|
972
|
+
if ( c.sortLocaleCompare ) {
|
973
|
+
data.filter = ts.replaceAccents( data.filter );
|
974
|
+
}
|
975
|
+
|
976
|
+
val = true;
|
977
|
+
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
|
978
|
+
data.filter = ts.filter.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
|
979
|
+
// val is used to indicate that a filter select is using a default filter;
|
980
|
+
// so we override the exact & partial matches
|
981
|
+
val = false;
|
982
|
+
}
|
983
|
+
// data.iFilter = case insensitive ( if wo.filter_ignoreCase is true ),
|
984
|
+
// data.filter = case sensitive
|
985
|
+
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
|
986
|
+
fxn = vars.functions[ columnIndex ];
|
987
|
+
$cell = c.$headerIndexed[ columnIndex ];
|
988
|
+
hasSelect = $cell.hasClass( 'filter-select' );
|
989
|
+
filterMatched = null;
|
990
|
+
if ( fxn || ( hasSelect && val ) ) {
|
991
|
+
if ( fxn === true || hasSelect ) {
|
992
|
+
// default selector uses exact match unless 'filter-match' class is found
|
993
|
+
filterMatched = $cell.hasClass( 'filter-match' ) ?
|
994
|
+
data.iExact.search( data.iFilter ) >= 0 :
|
995
|
+
data.filter === data.exact;
|
996
|
+
} else if ( typeof fxn === 'function' ) {
|
997
|
+
// filter callback( exact cell content, parser normalized content,
|
998
|
+
// filter input value, column index, jQuery row object )
|
999
|
+
filterMatched = fxn( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
|
1000
|
+
} else if ( typeof fxn[ ffxn || data.filter ] === 'function' ) {
|
1001
|
+
// selector option function
|
1002
|
+
txt = ffxn || data.filter;
|
1003
|
+
filterMatched =
|
1004
|
+
fxn[ txt ]( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
|
1005
|
+
}
|
1006
|
+
}
|
1007
|
+
if ( filterMatched === null ) {
|
1008
|
+
// cycle through the different filters
|
1009
|
+
// filters return a boolean or null if nothing matches
|
1010
|
+
matches = null;
|
1011
|
+
for ( ffxn in ts.filter.types ) {
|
1012
|
+
if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) {
|
1013
|
+
matches = ts.filter.types[ ffxn ]( c, data );
|
1014
|
+
if ( matches !== null ) {
|
1015
|
+
filterMatched = matches;
|
1016
|
+
}
|
1017
|
+
}
|
1018
|
+
}
|
1019
|
+
if ( filterMatched !== null ) {
|
1020
|
+
result = filterMatched;
|
1021
|
+
// Look for match, and add child row data for matching
|
1022
|
+
} else {
|
1023
|
+
txt = ( data.iExact + data.childRowText )
|
1024
|
+
.indexOf( ts.filter.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
|
1025
|
+
result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
|
1026
|
+
}
|
1027
|
+
} else {
|
1028
|
+
result = filterMatched;
|
1029
|
+
}
|
1030
|
+
showRow = ( result ) ? showRow : false;
|
1031
|
+
}
|
1032
|
+
}
|
1033
|
+
return showRow;
|
1034
|
+
},
|
1035
|
+
findRows: function( table, filters, combinedFilters ) {
|
1036
|
+
if ( table.config.lastCombinedFilter === combinedFilters ||
|
1037
|
+
!table.config.widgetOptions.filter_initialized ) {
|
1038
|
+
return;
|
1039
|
+
}
|
1040
|
+
var len, norm_rows, rowData, $rows, rowIndex, tbodyIndex, $tbody, columnIndex,
|
1041
|
+
isChild, childRow, lastSearch, showRow, time, val, indx,
|
1042
|
+
notFiltered, searchFiltered, query, injected, res, id, txt,
|
1043
|
+
storedFilters = $.extend( [], filters ),
|
794
1044
|
regex = ts.filter.regex,
|
795
1045
|
c = table.config,
|
796
1046
|
wo = c.widgetOptions,
|
797
1047
|
// data object passed to filters; anyMatch is a flag for the filters
|
798
|
-
data = {
|
799
|
-
|
800
|
-
|
1048
|
+
data = {
|
1049
|
+
anyMatch: false,
|
1050
|
+
filters: filters,
|
1051
|
+
// regex filter type cache
|
1052
|
+
filter_regexCache : [],
|
1053
|
+
},
|
1054
|
+
vars = {
|
1055
|
+
// anyMatch really screws up with these types of filters
|
1056
|
+
noAnyMatch: [ 'range', 'notMatch', 'operators' ],
|
1057
|
+
// cache filter variables that use ts.getColumnData in the main loop
|
1058
|
+
functions : [],
|
1059
|
+
excludeFilter : [],
|
1060
|
+
defaultColFilter : [],
|
1061
|
+
defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || ''
|
1062
|
+
};
|
801
1063
|
|
802
1064
|
// parse columns after formatter, in case the class is added at that point
|
803
|
-
data.parsed = c.$headers.map(function(columnIndex) {
|
804
|
-
return c.parsers && c.parsers[columnIndex] &&
|
805
|
-
//
|
806
|
-
|
807
|
-
|
1065
|
+
data.parsed = c.$headers.map( function( columnIndex ) {
|
1066
|
+
return c.parsers && c.parsers[ columnIndex ] &&
|
1067
|
+
// force parsing if parser type is numeric
|
1068
|
+
( c.parsers[ columnIndex ].parsed || c.parsers[ columnIndex ].type === 'numeric' ) ||
|
1069
|
+
// getData won't return 'parsed' if other 'filter-' class names exist
|
1070
|
+
// ( e.g. <th class="filter-select filter-parsed"> )
|
1071
|
+
ts.getData && ts.getData( c.$headerIndexed[ columnIndex ],
|
1072
|
+
ts.getColumnData( table, c.headers, columnIndex ), 'filter' ) === 'parsed' ||
|
1073
|
+
$( this ).hasClass( 'filter-parsed' );
|
808
1074
|
}).get();
|
809
1075
|
|
810
|
-
// cache filter variables that use ts.getColumnData in the main loop
|
811
|
-
wo.filter_indexed = {
|
812
|
-
functions : [],
|
813
|
-
excludeFilter : [],
|
814
|
-
defaultColFilter : [],
|
815
|
-
defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || ''
|
816
|
-
};
|
817
1076
|
for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
|
818
|
-
|
819
|
-
|
820
|
-
|
1077
|
+
vars.functions[ columnIndex ] =
|
1078
|
+
ts.getColumnData( table, wo.filter_functions, columnIndex );
|
1079
|
+
vars.defaultColFilter[ columnIndex ] =
|
1080
|
+
ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || '';
|
1081
|
+
vars.excludeFilter[ columnIndex ] =
|
1082
|
+
( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split( /\s+/ );
|
821
1083
|
}
|
822
1084
|
|
823
|
-
if (c.debug) {
|
824
|
-
ts.log('Filter: Starting filter widget search', filters);
|
1085
|
+
if ( c.debug ) {
|
1086
|
+
ts.log( 'Filter: Starting filter widget search', filters );
|
825
1087
|
time = new Date();
|
826
1088
|
}
|
827
1089
|
// filtered rows count
|
828
1090
|
c.filteredRows = 0;
|
829
1091
|
c.totalRows = 0;
|
830
1092
|
// combindedFilters are undefined on init
|
831
|
-
combinedFilters = (
|
1093
|
+
combinedFilters = ( storedFilters || [] ).join( '' );
|
832
1094
|
|
833
|
-
for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
|
834
|
-
$tbody = ts.processTbody(table, c.$tbodies.eq(tbodyIndex), true);
|
835
|
-
// skip child rows & widget added (removable) rows - fixes #448 thanks to @hempel!
|
836
|
-
// $rows = $tbody.children('tr').not(c.selectorRemove);
|
1095
|
+
for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
|
1096
|
+
$tbody = ts.processTbody( table, c.$tbodies.eq( tbodyIndex ), true );
|
1097
|
+
// skip child rows & widget added ( removable ) rows - fixes #448 thanks to @hempel!
|
1098
|
+
// $rows = $tbody.children( 'tr' ).not( c.selectorRemove );
|
837
1099
|
columnIndex = c.columns;
|
838
1100
|
// convert stored rows into a jQuery object
|
839
|
-
norm_rows = c.cache[tbodyIndex].normalized;
|
840
|
-
$rows = $( $.map(norm_rows, function(
|
1101
|
+
norm_rows = c.cache[ tbodyIndex ].normalized;
|
1102
|
+
$rows = $( $.map( norm_rows, function( el ) {
|
1103
|
+
return el[ columnIndex ].$row.get();
|
1104
|
+
}) );
|
841
1105
|
|
842
|
-
if (combinedFilters === '' || wo.filter_serversideFiltering) {
|
843
|
-
$rows
|
1106
|
+
if ( combinedFilters === '' || wo.filter_serversideFiltering ) {
|
1107
|
+
$rows
|
1108
|
+
.removeClass( wo.filter_filteredRow )
|
1109
|
+
.not( '.' + c.cssChildRow )
|
1110
|
+
.css( 'display', '' );
|
844
1111
|
} else {
|
845
1112
|
// filter out child rows
|
846
|
-
$rows = $rows.not('.' + c.cssChildRow);
|
1113
|
+
$rows = $rows.not( '.' + c.cssChildRow );
|
847
1114
|
len = $rows.length;
|
848
1115
|
|
849
|
-
if ( (wo.filter_$anyMatch && wo.filter_$anyMatch.length) ||
|
1116
|
+
if ( ( wo.filter_$anyMatch && wo.filter_$anyMatch.length ) ||
|
1117
|
+
typeof filters[c.columns] !== 'undefined' ) {
|
850
1118
|
data.anyMatchFlag = true;
|
851
|
-
data.anyMatchFilter =
|
852
|
-
|
1119
|
+
data.anyMatchFilter = '' + (
|
1120
|
+
filters[ c.columns ] ||
|
1121
|
+
wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() ||
|
1122
|
+
''
|
1123
|
+
);
|
1124
|
+
if ( wo.filter_columnAnyMatch ) {
|
853
1125
|
// specific columns search
|
854
|
-
query = data.anyMatchFilter.split(
|
1126
|
+
query = data.anyMatchFilter.split( regex.andSplit );
|
855
1127
|
injected = false;
|
856
|
-
for (indx = 0; indx < query.length; indx++) {
|
857
|
-
res = query[indx].split(':');
|
1128
|
+
for ( indx = 0; indx < query.length; indx++ ) {
|
1129
|
+
res = query[ indx ].split( ':' );
|
858
1130
|
if ( res.length > 1 ) {
|
859
1131
|
// make the column a one-based index ( non-developers start counting from one :P )
|
860
1132
|
id = parseInt( res[0], 10 ) - 1;
|
861
1133
|
if ( id >= 0 && id < c.columns ) { // if id is an integer
|
862
|
-
filters[id] = res[1];
|
863
|
-
query.splice(indx, 1);
|
1134
|
+
filters[ id ] = res[1];
|
1135
|
+
query.splice( indx, 1 );
|
864
1136
|
indx--;
|
865
1137
|
injected = true;
|
866
1138
|
}
|
867
1139
|
}
|
868
1140
|
}
|
869
|
-
if (injected) {
|
870
|
-
data.anyMatchFilter = query.join(' && ');
|
1141
|
+
if ( injected ) {
|
1142
|
+
data.anyMatchFilter = query.join( ' && ' );
|
871
1143
|
}
|
872
1144
|
}
|
873
1145
|
}
|
874
1146
|
|
875
1147
|
// optimize searching only through already filtered rows - see #313
|
876
1148
|
searchFiltered = wo.filter_searchFiltered;
|
877
|
-
lastSearch = c.lastSearch || c.$table.data('lastSearch') || [];
|
878
|
-
if (searchFiltered) {
|
879
|
-
// cycle through all filters; include last (columnIndex + 1 = match any column). Fixes #669
|
880
|
-
for (indx = 0; indx < columnIndex + 1; indx++) {
|
1149
|
+
lastSearch = c.lastSearch || c.$table.data( 'lastSearch' ) || [];
|
1150
|
+
if ( searchFiltered ) {
|
1151
|
+
// cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669
|
1152
|
+
for ( indx = 0; indx < columnIndex + 1; indx++ ) {
|
881
1153
|
val = filters[indx] || '';
|
882
1154
|
// break out of loop if we've already determined not to search filtered rows
|
883
|
-
if (!searchFiltered) { indx = columnIndex; }
|
1155
|
+
if ( !searchFiltered ) { indx = columnIndex; }
|
884
1156
|
// search already filtered rows if...
|
885
1157
|
searchFiltered = searchFiltered && lastSearch.length &&
|
886
1158
|
// there are no changes from beginning of filter
|
887
|
-
val.indexOf(lastSearch[indx] || '') === 0 &&
|
888
|
-
// if there is NOT a logical
|
889
|
-
!regex.alreadyFiltered.test(val) &&
|
890
|
-
// if we are not doing exact matches, using
|
891
|
-
!/[=\"\|!]/.test(val) &&
|
892
|
-
// don't search only filtered if the value is negative
|
893
|
-
|
894
|
-
|
895
|
-
|
1159
|
+
val.indexOf( lastSearch[indx] || '' ) === 0 &&
|
1160
|
+
// if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
|
1161
|
+
!regex.alreadyFiltered.test( val ) &&
|
1162
|
+
// if we are not doing exact matches, using '|' ( logical or ) or not '!'
|
1163
|
+
!/[=\"\|!]/.test( val ) &&
|
1164
|
+
// don't search only filtered if the value is negative
|
1165
|
+
// ( '> -10' => '> -100' will ignore hidden rows )
|
1166
|
+
!( /(>=?\s*-\d)/.test( val ) || /(<=?\s*\d)/.test( val ) ) &&
|
1167
|
+
// if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
|
1168
|
+
!( val !== '' && c.$filters && c.$filters.eq( indx ).find( 'select' ).length &&
|
1169
|
+
!c.$headerIndexed[indx].hasClass( 'filter-match' ) );
|
896
1170
|
}
|
897
1171
|
}
|
898
|
-
notFiltered = $rows.not('.' + wo.filter_filteredRow).length;
|
1172
|
+
notFiltered = $rows.not( '.' + wo.filter_filteredRow ).length;
|
899
1173
|
// can't search when all rows are hidden - this happens when looking for exact matches
|
900
|
-
if (searchFiltered && notFiltered === 0) { searchFiltered = false; }
|
901
|
-
if (c.debug) {
|
902
|
-
ts.log( 'Filter: Searching through ' +
|
1174
|
+
if ( searchFiltered && notFiltered === 0 ) { searchFiltered = false; }
|
1175
|
+
if ( c.debug ) {
|
1176
|
+
ts.log( 'Filter: Searching through ' +
|
1177
|
+
( searchFiltered && notFiltered < len ? notFiltered : 'all' ) + ' rows' );
|
903
1178
|
}
|
904
|
-
if (data.anyMatchFlag) {
|
905
|
-
if (c.sortLocaleCompare) {
|
1179
|
+
if ( data.anyMatchFlag ) {
|
1180
|
+
if ( c.sortLocaleCompare ) {
|
906
1181
|
// replace accents
|
907
|
-
data.anyMatchFilter = ts.replaceAccents(data.anyMatchFilter);
|
1182
|
+
data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
|
908
1183
|
}
|
909
|
-
if ( wo.filter_defaultFilter && regex.iQuery.test(
|
910
|
-
data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter,
|
1184
|
+
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) {
|
1185
|
+
data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
|
911
1186
|
// clear search filtered flag because default filters are not saved to the last search
|
912
1187
|
searchFiltered = false;
|
913
1188
|
}
|
914
1189
|
// make iAnyMatchFilter lowercase unless both filter widget & core ignoreCase options are true
|
915
1190
|
// when c.ignoreCase is true, the cache contains all lower case data
|
916
|
-
data.iAnyMatchFilter = !(wo.filter_ignoreCase && c.ignoreCase) ?
|
1191
|
+
data.iAnyMatchFilter = !( wo.filter_ignoreCase && c.ignoreCase ) ?
|
1192
|
+
data.anyMatchFilter :
|
1193
|
+
data.anyMatchFilter.toLowerCase();
|
917
1194
|
}
|
918
1195
|
|
919
1196
|
// loop through the rows
|
920
|
-
for (rowIndex = 0; rowIndex < len; rowIndex++) {
|
1197
|
+
for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
|
921
1198
|
|
922
|
-
|
923
|
-
|
924
|
-
|
1199
|
+
txt = $rows[ rowIndex ].className;
|
1200
|
+
// the first row can never be a child row
|
1201
|
+
isChild = rowIndex && regex.child.test( txt );
|
925
1202
|
// skip child rows & already filtered rows
|
926
|
-
if (
|
927
|
-
|
928
|
-
// *** nextAll/nextUntil not supported by Zepto! ***
|
929
|
-
childRow = $rows.eq(rowIndex).nextUntil('tr:not(.' + c.cssChildRow + ')');
|
930
|
-
// so, if "table.config.widgetOptions.filter_childRows" is true and there is
|
931
|
-
// a match anywhere in the child row, then it will make the row visible
|
932
|
-
// checked here so the option can be changed dynamically
|
933
|
-
data.childRowText = (childRow.length && wo.filter_childRows) ? childRow.text() : '';
|
934
|
-
data.childRowText = wo.filter_ignoreCase ? data.childRowText.toLocaleLowerCase() : data.childRowText;
|
935
|
-
$cells = $rows.eq(rowIndex).children();
|
936
|
-
if (data.anyMatchFlag) {
|
937
|
-
// look for multiple columns "1-3,4-6,8"
|
938
|
-
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
|
939
|
-
data.anyMatch = true;
|
940
|
-
data.rowArray = $cells.map(function(i){
|
941
|
-
if ( $.inArray(i, columnIndex) > -1 ) {
|
942
|
-
var txt;
|
943
|
-
if (data.parsed[i]) {
|
944
|
-
txt = data.cacheArray[i];
|
945
|
-
} else {
|
946
|
-
txt = this ? this.getAttribute( c.textAttribute ) || this.textContent || $(this).text() : '';
|
947
|
-
txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
|
948
|
-
if (c.sortLocaleCompare) {
|
949
|
-
txt = ts.replaceAccents(txt);
|
950
|
-
}
|
951
|
-
}
|
952
|
-
return txt;
|
953
|
-
}
|
954
|
-
}).get();
|
955
|
-
data.filter = data.anyMatchFilter;
|
956
|
-
data.iFilter = data.iAnyMatchFilter;
|
957
|
-
data.exact = data.rowArray.join(' ');
|
958
|
-
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
|
959
|
-
data.cache = data.cacheArray.slice(0,-1).join(' ');
|
960
|
-
filterMatched = null;
|
961
|
-
$.each(ts.filter.types, function(type, typeFunction) {
|
962
|
-
if ($.inArray(type, noAnyMatch) < 0) {
|
963
|
-
matches = typeFunction( c, data );
|
964
|
-
if (matches !== null) {
|
965
|
-
filterMatched = matches;
|
966
|
-
return false;
|
967
|
-
}
|
968
|
-
}
|
969
|
-
});
|
970
|
-
if (filterMatched !== null) {
|
971
|
-
showRow = filterMatched;
|
972
|
-
} else {
|
973
|
-
if (wo.filter_startsWith) {
|
974
|
-
showRow = false;
|
975
|
-
columnIndex = c.columns;
|
976
|
-
while (!showRow && columnIndex > 0) {
|
977
|
-
columnIndex--;
|
978
|
-
showRow = showRow || data.rowArray[columnIndex].indexOf(data.iFilter) === 0;
|
979
|
-
}
|
980
|
-
} else {
|
981
|
-
showRow = (data.iExact + data.childRowText).indexOf(data.iFilter) >= 0;
|
982
|
-
}
|
983
|
-
}
|
984
|
-
data.anyMatch = false;
|
1203
|
+
if ( isChild || ( searchFiltered && regex.filtered.test( txt ) ) ) {
|
1204
|
+
continue;
|
985
1205
|
}
|
986
1206
|
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
excludeMatch = wo.filter_indexed.excludeFilter[ columnIndex ];
|
1207
|
+
data.$row = $rows.eq( rowIndex );
|
1208
|
+
data.cacheArray = norm_rows[ rowIndex ];
|
1209
|
+
rowData = data.cacheArray[ c.columns ];
|
1210
|
+
data.rawArray = rowData.raw;
|
1211
|
+
data.childRowText = '';
|
993
1212
|
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1213
|
+
if ( !wo.filter_childByColumn ) {
|
1214
|
+
txt = '';
|
1215
|
+
// child row cached text
|
1216
|
+
childRow = rowData.child;
|
1217
|
+
// so, if 'table.config.widgetOptions.filter_childRows' is true and there is
|
1218
|
+
// a match anywhere in the child row, then it will make the row visible
|
1219
|
+
// checked here so the option can be changed dynamically
|
1220
|
+
for ( indx = 0; indx < childRow.length; indx++ ) {
|
1221
|
+
txt += ' ' + childRow[indx].join( '' ) || '';
|
1222
|
+
}
|
1223
|
+
data.childRowText = wo.filter_childRows ?
|
1224
|
+
( wo.filter_ignoreCase ? txt.toLowerCase() : txt ) :
|
1225
|
+
'';
|
1226
|
+
}
|
1007
1227
|
|
1008
|
-
|
1009
|
-
|
1010
|
-
c.$filters.add(c.$externalFilters).filter('[data-column="'+ columnIndex + '"]').find('select option:selected').attr('data-function-name') || '' : '';
|
1011
|
-
// replace accents - see #357
|
1012
|
-
if (c.sortLocaleCompare) {
|
1013
|
-
data.filter = ts.replaceAccents(data.filter);
|
1014
|
-
}
|
1228
|
+
showRow = ts.filter.processRow( c, data, vars );
|
1229
|
+
childRow = rowData.$row.filter( ':gt( 0 )' );
|
1015
1230
|
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
$cell = c.$headerIndexed[columnIndex];
|
1026
|
-
hasSelect = $cell.hasClass('filter-select');
|
1027
|
-
filterMatched = null;
|
1028
|
-
if ( fxn || ( hasSelect && val ) ) {
|
1029
|
-
if (fxn === true || hasSelect) {
|
1030
|
-
// default selector uses exact match unless "filter-match" class is found
|
1031
|
-
filterMatched = ($cell.hasClass('filter-match')) ? data.iExact.search(data.iFilter) >= 0 : data.filter === data.exact;
|
1032
|
-
} else if (typeof fxn === 'function') {
|
1033
|
-
// filter callback( exact cell content, parser normalized content, filter input value, column index, jQuery row object )
|
1034
|
-
filterMatched = fxn(data.exact, data.cache, data.filter, columnIndex, $rows.eq(rowIndex), c);
|
1035
|
-
} else if (typeof fxn[ffxn || data.filter] === 'function') {
|
1036
|
-
// selector option function
|
1037
|
-
filterMatched = fxn[ffxn || data.filter](data.exact, data.cache, data.filter, columnIndex, $rows.eq(rowIndex), c);
|
1038
|
-
}
|
1231
|
+
if ( wo.filter_childRows && childRow.length ) {
|
1232
|
+
if ( wo.filter_childByColumn ) {
|
1233
|
+
// cycle through each child row
|
1234
|
+
for ( indx = 0; indx < childRow.length; indx++ ) {
|
1235
|
+
data.$row = childRow.eq( indx );
|
1236
|
+
data.cacheArray = rowData.child[ indx ];
|
1237
|
+
data.rawArray = data.cacheArray;
|
1238
|
+
// use OR comparison on child rows
|
1239
|
+
showRow = showRow || ts.filter.processRow( c, data, vars );
|
1039
1240
|
}
|
1040
|
-
if (filterMatched === null) {
|
1041
|
-
// cycle through the different filters
|
1042
|
-
// filters return a boolean or null if nothing matches
|
1043
|
-
$.each(ts.filter.types, function(type, typeFunction) {
|
1044
|
-
if ($.inArray(type, excludeMatch) < 0) {
|
1045
|
-
matches = typeFunction( c, data );
|
1046
|
-
if (matches !== null) {
|
1047
|
-
filterMatched = matches;
|
1048
|
-
return false;
|
1049
|
-
}
|
1050
|
-
}
|
1051
|
-
});
|
1052
|
-
if (filterMatched !== null) {
|
1053
|
-
result = filterMatched;
|
1054
|
-
// Look for match, and add child row data for matching
|
1055
|
-
} else {
|
1056
|
-
data.exact = (data.iExact + data.childRowText).indexOf( ts.filter.parseFilter(c, data.iFilter, columnIndex, data.parsed[columnIndex]) );
|
1057
|
-
result = ( (!wo.filter_startsWith && data.exact >= 0) || (wo.filter_startsWith && data.exact === 0) );
|
1058
|
-
}
|
1059
|
-
} else {
|
1060
|
-
result = filterMatched;
|
1061
|
-
}
|
1062
|
-
showRow = (result) ? showRow : false;
|
1063
1241
|
}
|
1242
|
+
childRow.toggleClass( wo.filter_filteredRow, !showRow );
|
1064
1243
|
}
|
1065
|
-
|
1066
|
-
|
1244
|
+
|
1245
|
+
rowData.$row
|
1246
|
+
.toggleClass( wo.filter_filteredRow, !showRow )[0]
|
1067
1247
|
.display = showRow ? '' : 'none';
|
1068
|
-
if (childRow.length) {
|
1069
|
-
childRow.toggleClass(wo.filter_filteredRow, !showRow);
|
1070
|
-
}
|
1071
1248
|
}
|
1072
1249
|
}
|
1073
|
-
c.filteredRows += $rows.not('.' + wo.filter_filteredRow).length;
|
1250
|
+
c.filteredRows += $rows.not( '.' + wo.filter_filteredRow ).length;
|
1074
1251
|
c.totalRows += $rows.length;
|
1075
|
-
ts.processTbody(table, $tbody, false);
|
1252
|
+
ts.processTbody( table, $tbody, false );
|
1076
1253
|
}
|
1077
1254
|
c.lastCombinedFilter = combinedFilters; // save last search
|
1078
|
-
|
1079
|
-
c
|
1080
|
-
|
1081
|
-
|
1255
|
+
// don't save 'filters' directly since it may have altered ( AnyMatch column searches )
|
1256
|
+
c.lastSearch = storedFilters;
|
1257
|
+
c.$table.data( 'lastSearch', storedFilters );
|
1258
|
+
if ( wo.filter_saveFilters && ts.storage ) {
|
1259
|
+
ts.storage( table, 'tablesorter-filters', storedFilters );
|
1260
|
+
}
|
1261
|
+
if ( c.debug ) {
|
1262
|
+
ts.benchmark( 'Completed filter widget search', time );
|
1082
1263
|
}
|
1083
|
-
if (
|
1084
|
-
|
1264
|
+
if ( wo.filter_initialized ) {
|
1265
|
+
c.$table.trigger( 'filterEnd', c );
|
1085
1266
|
}
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
}, 0);
|
1267
|
+
setTimeout( function() {
|
1268
|
+
c.$table.trigger( 'applyWidgets' ); // make sure zebra widget is applied
|
1269
|
+
}, 0 );
|
1090
1270
|
},
|
1091
|
-
getOptionSource: function(table, column, onlyAvail) {
|
1092
|
-
table = $(table)[0];
|
1271
|
+
getOptionSource: function( table, column, onlyAvail ) {
|
1272
|
+
table = $( table )[0];
|
1093
1273
|
var cts, indx, len,
|
1094
1274
|
c = table.config,
|
1095
1275
|
wo = c.widgetOptions,
|
1096
1276
|
parsed = [],
|
1097
1277
|
arry = false,
|
1098
1278
|
source = wo.filter_selectSource,
|
1099
|
-
last = c.$table.data('lastSearch') || [],
|
1100
|
-
fxn = $.isFunction(source) ? true : ts.getColumnData( table, source, column );
|
1279
|
+
last = c.$table.data( 'lastSearch' ) || [],
|
1280
|
+
fxn = $.isFunction( source ) ? true : ts.getColumnData( table, source, column );
|
1101
1281
|
|
1102
|
-
if (onlyAvail && last[column] !== '') {
|
1282
|
+
if ( onlyAvail && last[column] !== '' ) {
|
1103
1283
|
onlyAvail = false;
|
1104
1284
|
}
|
1105
1285
|
|
1106
1286
|
// filter select source option
|
1107
|
-
if (fxn === true) {
|
1287
|
+
if ( fxn === true ) {
|
1108
1288
|
// OVERALL source
|
1109
|
-
arry = source(table, column, onlyAvail);
|
1110
|
-
} else if ( fxn instanceof $ || ($.type(fxn) === 'string' && fxn.indexOf('</option>') >= 0) ) {
|
1289
|
+
arry = source( table, column, onlyAvail );
|
1290
|
+
} else if ( fxn instanceof $ || ( $.type( fxn ) === 'string' && fxn.indexOf( '</option>' ) >= 0 ) ) {
|
1111
1291
|
// selectSource is a jQuery object or string of options
|
1112
1292
|
return fxn;
|
1113
|
-
} else if ($.isArray(fxn)) {
|
1293
|
+
} else if ( $.isArray( fxn ) ) {
|
1114
1294
|
arry = fxn;
|
1115
|
-
} else if ($.type(source) === 'object' && fxn) {
|
1295
|
+
} else if ( $.type( source ) === 'object' && fxn ) {
|
1116
1296
|
// custom select source function for a SPECIFIC COLUMN
|
1117
|
-
arry = fxn(table, column, onlyAvail);
|
1297
|
+
arry = fxn( table, column, onlyAvail );
|
1118
1298
|
}
|
1119
|
-
if (arry === false) {
|
1299
|
+
if ( arry === false ) {
|
1120
1300
|
// fall back to original method
|
1121
|
-
arry = ts.filter.getOptions(table, column, onlyAvail);
|
1301
|
+
arry = ts.filter.getOptions( table, column, onlyAvail );
|
1122
1302
|
}
|
1123
1303
|
|
1124
1304
|
// get unique elements and sort the list
|
1125
|
-
// if $.tablesorter.sortText exists (not in the original tablesorter),
|
1305
|
+
// if $.tablesorter.sortText exists ( not in the original tablesorter ),
|
1126
1306
|
// then natural sort the list otherwise use a basic sort
|
1127
|
-
arry = $.grep(arry, function(value, indx) {
|
1128
|
-
return $.inArray(value, arry) === indx;
|
1307
|
+
arry = $.grep( arry, function( value, indx ) {
|
1308
|
+
return $.inArray( value, arry ) === indx;
|
1129
1309
|
});
|
1130
1310
|
|
1131
|
-
if (c.$headerIndexed[column].hasClass('filter-select-nosort')) {
|
1311
|
+
if ( c.$headerIndexed[ column ].hasClass( 'filter-select-nosort' ) ) {
|
1132
1312
|
// unsorted select options
|
1133
1313
|
return arry;
|
1134
1314
|
} else {
|
1135
1315
|
len = arry.length;
|
1136
1316
|
// parse select option values
|
1137
|
-
for (indx = 0; indx < len; indx++) {
|
1317
|
+
for ( indx = 0; indx < len; indx++ ) {
|
1138
1318
|
// parse array data using set column parser; this DOES NOT pass the original
|
1139
1319
|
// table cell to the parser format function
|
1140
|
-
parsed.push({
|
1320
|
+
parsed.push({
|
1321
|
+
t : arry[ indx ],
|
1322
|
+
p : c.parsers && c.parsers[ column ].format( arry[ indx ], table, [], column )
|
1323
|
+
});
|
1141
1324
|
}
|
1142
1325
|
|
1143
1326
|
// sort parsed select options
|
1144
1327
|
cts = c.textSorter || '';
|
1145
|
-
parsed.sort(function(a, b){
|
1328
|
+
parsed.sort( function( a, b ) {
|
1146
1329
|
// sortNatural breaks if you don't pass it strings
|
1147
|
-
var x = a.p.toString(),
|
1148
|
-
|
1330
|
+
var x = a.p.toString(),
|
1331
|
+
y = b.p.toString();
|
1332
|
+
if ( $.isFunction( cts ) ) {
|
1149
1333
|
// custom OVERALL text sorter
|
1150
|
-
return cts(x, y, true, column, table);
|
1151
|
-
} else if (typeof(cts) === 'object' && cts.hasOwnProperty(column)) {
|
1334
|
+
return cts( x, y, true, column, table );
|
1335
|
+
} else if ( typeof( cts ) === 'object' && cts.hasOwnProperty( column ) ) {
|
1152
1336
|
// custom text sorter for a SPECIFIC COLUMN
|
1153
|
-
return cts[column](x, y, true, column, table);
|
1154
|
-
} else if (ts.sortNatural) {
|
1337
|
+
return cts[column]( x, y, true, column, table );
|
1338
|
+
} else if ( ts.sortNatural ) {
|
1155
1339
|
// fall back to natural sort
|
1156
|
-
return ts.sortNatural(x, y);
|
1340
|
+
return ts.sortNatural( x, y );
|
1157
1341
|
}
|
1158
1342
|
// using an older version! do a basic sort
|
1159
1343
|
return true;
|
@@ -1161,184 +1345,221 @@ ts.filter = {
|
|
1161
1345
|
// rebuild arry from sorted parsed data
|
1162
1346
|
arry = [];
|
1163
1347
|
len = parsed.length;
|
1164
|
-
for (indx = 0; indx < len; indx++) {
|
1348
|
+
for ( indx = 0; indx < len; indx++ ) {
|
1165
1349
|
arry.push( parsed[indx].t );
|
1166
1350
|
}
|
1167
1351
|
return arry;
|
1168
1352
|
}
|
1169
1353
|
},
|
1170
|
-
getOptions: function(table, column, onlyAvail) {
|
1171
|
-
table = $(table)[0];
|
1172
|
-
var rowIndex, tbodyIndex, len, row, cache,
|
1354
|
+
getOptions: function( table, column, onlyAvail ) {
|
1355
|
+
table = $( table )[0];
|
1356
|
+
var rowIndex, tbodyIndex, len, row, cache,
|
1173
1357
|
c = table.config,
|
1174
1358
|
wo = c.widgetOptions,
|
1175
1359
|
arry = [];
|
1176
|
-
for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
|
1360
|
+
for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
|
1177
1361
|
cache = c.cache[tbodyIndex];
|
1178
1362
|
len = c.cache[tbodyIndex].normalized.length;
|
1179
1363
|
// loop through the rows
|
1180
|
-
for (rowIndex = 0; rowIndex < len; rowIndex++) {
|
1181
|
-
// get cached row from cache.row (old) or row data object
|
1182
|
-
|
1364
|
+
for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
|
1365
|
+
// get cached row from cache.row ( old ) or row data object
|
1366
|
+
// ( new; last item in normalized array )
|
1367
|
+
row = cache.row ?
|
1368
|
+
cache.row[ rowIndex ] :
|
1369
|
+
cache.normalized[ rowIndex ][ c.columns ].$row[0];
|
1183
1370
|
// check if has class filtered
|
1184
|
-
if (onlyAvail && row.className.match(wo.filter_filteredRow)) {
|
1371
|
+
if ( onlyAvail && row.className.match( wo.filter_filteredRow ) ) {
|
1372
|
+
continue;
|
1373
|
+
}
|
1185
1374
|
// get non-normalized cell content
|
1186
|
-
if (wo.filter_useParsedData ||
|
1187
|
-
|
1375
|
+
if ( wo.filter_useParsedData ||
|
1376
|
+
c.parsers[column].parsed ||
|
1377
|
+
c.$headerIndexed[column].hasClass( 'filter-parsed' ) ) {
|
1378
|
+
arry.push( '' + cache.normalized[ rowIndex ][ column ] );
|
1188
1379
|
} else {
|
1189
|
-
|
1190
|
-
|
1191
|
-
arry.push( $.trim( cell.getAttribute( c.textAttribute ) || cell.textContent || $(cell).text() ) );
|
1192
|
-
}
|
1380
|
+
// get raw cached data instead of content directly from the cells
|
1381
|
+
arry.push( cache.normalized[ rowIndex ][ c.columns ].raw[ column ] );
|
1193
1382
|
}
|
1194
1383
|
}
|
1195
1384
|
}
|
1196
1385
|
return arry;
|
1197
1386
|
},
|
1198
|
-
buildSelect: function(table, column, arry, updating, onlyAvail) {
|
1199
|
-
table = $(table)[0];
|
1200
|
-
column = parseInt(column, 10);
|
1201
|
-
if (!table.config.cache || $.isEmptyObject(table.config.cache)) {
|
1387
|
+
buildSelect: function( table, column, arry, updating, onlyAvail ) {
|
1388
|
+
table = $( table )[0];
|
1389
|
+
column = parseInt( column, 10 );
|
1390
|
+
if ( !table.config.cache || $.isEmptyObject( table.config.cache ) ) {
|
1391
|
+
return;
|
1392
|
+
}
|
1202
1393
|
var indx, val, txt, t, $filters, $filter,
|
1203
1394
|
c = table.config,
|
1204
1395
|
wo = c.widgetOptions,
|
1205
|
-
node = c.$headerIndexed[column],
|
1206
|
-
// t.data('placeholder') won't work in jQuery older than 1.4.3
|
1207
|
-
options = '<option value="">' +
|
1396
|
+
node = c.$headerIndexed[ column ],
|
1397
|
+
// t.data( 'placeholder' ) won't work in jQuery older than 1.4.3
|
1398
|
+
options = '<option value="">' +
|
1399
|
+
( node.data( 'placeholder' ) ||
|
1400
|
+
node.attr( 'data-placeholder' ) ||
|
1401
|
+
wo.filter_placeholder.select || ''
|
1402
|
+
) + '</option>',
|
1208
1403
|
// Get curent filter value
|
1209
|
-
currentValue = c.$table
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1404
|
+
currentValue = c.$table
|
1405
|
+
.find( 'thead' )
|
1406
|
+
.find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
|
1407
|
+
.val();
|
1408
|
+
// nothing included in arry ( external source ), so get the options from
|
1409
|
+
// filter_selectSource or column data
|
1410
|
+
if ( typeof arry === 'undefined' || arry === '' ) {
|
1411
|
+
arry = ts.filter.getOptionSource( table, column, onlyAvail );
|
1213
1412
|
}
|
1214
1413
|
|
1215
|
-
if ($.isArray(arry)) {
|
1414
|
+
if ( $.isArray( arry ) ) {
|
1216
1415
|
// build option list
|
1217
|
-
for (indx = 0; indx < arry.length; indx++) {
|
1218
|
-
txt = arry[indx] = ('' + arry[indx]).replace(/\"/g,
|
1416
|
+
for ( indx = 0; indx < arry.length; indx++ ) {
|
1417
|
+
txt = arry[indx] = ( '' + arry[indx] ).replace( /\"/g, '"' );
|
1219
1418
|
val = txt;
|
1220
1419
|
// allow including a symbol in the selectSource array
|
1221
|
-
//
|
1222
|
-
// and
|
1223
|
-
if (txt.indexOf(wo.filter_selectSourceSeparator) >= 0) {
|
1224
|
-
t = txt.split(wo.filter_selectSourceSeparator);
|
1420
|
+
// 'a-z|A through Z' so that 'a-z' becomes the option value
|
1421
|
+
// and 'A through Z' becomes the option text
|
1422
|
+
if ( txt.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
|
1423
|
+
t = txt.split( wo.filter_selectSourceSeparator );
|
1225
1424
|
val = t[0];
|
1226
1425
|
txt = t[1];
|
1227
1426
|
}
|
1228
|
-
// replace quotes - fixes #242 & ignore empty strings
|
1229
|
-
|
1427
|
+
// replace quotes - fixes #242 & ignore empty strings
|
1428
|
+
// see http://stackoverflow.com/q/14990971/145346
|
1429
|
+
options += arry[indx] !== '' ?
|
1430
|
+
'<option ' +
|
1431
|
+
( val === txt ? '' : 'data-function-name="' + arry[indx] + '" ' ) +
|
1432
|
+
'value="' + val + '">' + txt +
|
1433
|
+
'</option>' : '';
|
1230
1434
|
}
|
1231
1435
|
// clear arry so it doesn't get appended twice
|
1232
1436
|
arry = [];
|
1233
1437
|
}
|
1234
1438
|
|
1235
|
-
// update all selects in the same column (clone thead in sticky headers &
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1439
|
+
// update all selects in the same column ( clone thead in sticky headers &
|
1440
|
+
// any external selects ) - fixes 473
|
1441
|
+
$filters = ( c.$filters ? c.$filters : c.$table.children( 'thead' ) )
|
1442
|
+
.find( '.' + tscss.filter );
|
1443
|
+
if ( wo.filter_$externalFilters ) {
|
1444
|
+
$filters = $filters && $filters.length ?
|
1445
|
+
$filters.add( wo.filter_$externalFilters ) :
|
1446
|
+
wo.filter_$externalFilters;
|
1239
1447
|
}
|
1240
|
-
$filter = $filters.filter('select[data-column="' + column + '"]');
|
1448
|
+
$filter = $filters.filter( 'select[data-column="' + column + '"]' );
|
1241
1449
|
|
1242
1450
|
// make sure there is a select there!
|
1243
|
-
if ($filter.length) {
|
1244
|
-
$filter[ updating ? 'html' : 'append' ](options);
|
1245
|
-
if (!$.isArray(arry)) {
|
1451
|
+
if ( $filter.length ) {
|
1452
|
+
$filter[ updating ? 'html' : 'append' ]( options );
|
1453
|
+
if ( !$.isArray( arry ) ) {
|
1246
1454
|
// append options if arry is provided externally as a string or jQuery object
|
1247
|
-
// options (default value) was already added
|
1248
|
-
$filter.append(arry).val(currentValue);
|
1455
|
+
// options ( default value ) was already added
|
1456
|
+
$filter.append( arry ).val( currentValue );
|
1249
1457
|
}
|
1250
|
-
$filter.val(currentValue);
|
1458
|
+
$filter.val( currentValue );
|
1251
1459
|
}
|
1252
1460
|
},
|
1253
|
-
buildDefault: function(table, updating) {
|
1461
|
+
buildDefault: function( table, updating ) {
|
1254
1462
|
var columnIndex, $header, noSelect,
|
1255
1463
|
c = table.config,
|
1256
1464
|
wo = c.widgetOptions,
|
1257
1465
|
columns = c.columns;
|
1258
1466
|
// build default select dropdown
|
1259
|
-
for (columnIndex = 0; columnIndex < columns; columnIndex++) {
|
1467
|
+
for ( columnIndex = 0; columnIndex < columns; columnIndex++ ) {
|
1260
1468
|
$header = c.$headerIndexed[columnIndex];
|
1261
|
-
noSelect = !($header.hasClass('filter-false') || $header.hasClass('parser-false'));
|
1469
|
+
noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
|
1262
1470
|
// look for the filter-select class; build/update it if found
|
1263
|
-
if (($header.hasClass('filter-select') ||
|
1264
|
-
ts.
|
1471
|
+
if ( ( $header.hasClass( 'filter-select' ) ||
|
1472
|
+
ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
|
1473
|
+
ts.filter.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
|
1265
1474
|
}
|
1266
1475
|
}
|
1267
1476
|
}
|
1268
1477
|
};
|
1269
1478
|
|
1270
|
-
ts.getFilters = function(table, getRaw, setFilters, skipFirst) {
|
1479
|
+
ts.getFilters = function( table, getRaw, setFilters, skipFirst ) {
|
1271
1480
|
var i, $filters, $column, cols,
|
1272
1481
|
filters = false,
|
1273
|
-
c = table ? $(table)[0].config : '',
|
1482
|
+
c = table ? $( table )[0].config : '',
|
1274
1483
|
wo = c ? c.widgetOptions : '';
|
1275
|
-
if (getRaw !== true && wo && !wo.filter_columnFilters)
|
1276
|
-
|
1484
|
+
if ( ( getRaw !== true && wo && !wo.filter_columnFilters ) ||
|
1485
|
+
// setFilters called, but last search is exactly the same as the current
|
1486
|
+
// fixes issue #733 & #903 where calling update causes the input values to reset
|
1487
|
+
( $.isArray(setFilters) && setFilters.join('') === c.lastCombinedFilter ) ) {
|
1488
|
+
return $( table ).data( 'lastSearch' );
|
1277
1489
|
}
|
1278
|
-
if (c) {
|
1279
|
-
if (c.$filters) {
|
1280
|
-
$filters = c.$filters.find('.' + tscss.filter);
|
1490
|
+
if ( c ) {
|
1491
|
+
if ( c.$filters ) {
|
1492
|
+
$filters = c.$filters.find( '.' + tscss.filter );
|
1281
1493
|
}
|
1282
|
-
if (wo.filter_$externalFilters) {
|
1283
|
-
$filters = $filters && $filters.length ?
|
1494
|
+
if ( wo.filter_$externalFilters ) {
|
1495
|
+
$filters = $filters && $filters.length ?
|
1496
|
+
$filters.add( wo.filter_$externalFilters ) :
|
1497
|
+
wo.filter_$externalFilters;
|
1284
1498
|
}
|
1285
|
-
if ($filters && $filters.length) {
|
1499
|
+
if ( $filters && $filters.length ) {
|
1286
1500
|
filters = setFilters || [];
|
1287
|
-
for (i = 0; i < c.columns + 1; i++) {
|
1501
|
+
for ( i = 0; i < c.columns + 1; i++ ) {
|
1288
1502
|
cols = ( i === c.columns ?
|
1289
|
-
//
|
1503
|
+
// 'all' columns can now include a range or set of columms ( data-column='0-2,4,6-7' )
|
1290
1504
|
wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector :
|
1291
1505
|
'[data-column="' + i + '"]' );
|
1292
|
-
$column = $filters.filter(cols);
|
1293
|
-
if ($column.length) {
|
1506
|
+
$column = $filters.filter( cols );
|
1507
|
+
if ( $column.length ) {
|
1294
1508
|
// move the latest search to the first slot in the array
|
1295
1509
|
$column = ts.filter.getLatestSearch( $column );
|
1296
|
-
if ($.isArray(setFilters)) {
|
1297
|
-
// skip first (latest input) to maintain cursor position while typing
|
1298
|
-
if (skipFirst) {
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1510
|
+
if ( $.isArray( setFilters ) ) {
|
1511
|
+
// skip first ( latest input ) to maintain cursor position while typing
|
1512
|
+
if ( skipFirst ) {
|
1513
|
+
$column.slice( 1 );
|
1514
|
+
}
|
1515
|
+
if ( i === c.columns ) {
|
1516
|
+
// prevent data-column='all' from filling data-column='0,1' ( etc )
|
1517
|
+
cols = $column.filter( wo.filter_anyColumnSelector );
|
1302
1518
|
$column = cols.length ? cols : $column;
|
1303
1519
|
}
|
1304
1520
|
$column
|
1305
|
-
.val( setFilters[i] )
|
1306
|
-
.trigger('change.tsfilter');
|
1521
|
+
.val( setFilters[ i ] )
|
1522
|
+
.trigger( 'change.tsfilter' );
|
1307
1523
|
} else {
|
1308
1524
|
filters[i] = $column.val() || '';
|
1309
1525
|
// don't change the first... it will move the cursor
|
1310
|
-
if (i === c.columns) {
|
1311
|
-
// don't update range columns from
|
1312
|
-
$column
|
1526
|
+
if ( i === c.columns ) {
|
1527
|
+
// don't update range columns from 'all' setting
|
1528
|
+
$column
|
1529
|
+
.slice( 1 )
|
1530
|
+
.filter( '[data-column*="' + $column.attr( 'data-column' ) + '"]' )
|
1531
|
+
.val( filters[ i ] );
|
1313
1532
|
} else {
|
1314
|
-
$column
|
1533
|
+
$column
|
1534
|
+
.slice( 1 )
|
1535
|
+
.val( filters[ i ] );
|
1315
1536
|
}
|
1316
1537
|
}
|
1317
1538
|
// save any match input dynamically
|
1318
|
-
if (i === c.columns && $column.length) {
|
1539
|
+
if ( i === c.columns && $column.length ) {
|
1319
1540
|
wo.filter_$anyMatch = $column;
|
1320
1541
|
}
|
1321
1542
|
}
|
1322
1543
|
}
|
1323
1544
|
}
|
1324
1545
|
}
|
1325
|
-
if (filters.length === 0) {
|
1546
|
+
if ( filters.length === 0 ) {
|
1326
1547
|
filters = false;
|
1327
1548
|
}
|
1328
1549
|
return filters;
|
1329
1550
|
};
|
1330
1551
|
|
1331
|
-
ts.setFilters = function(table, filter, apply, skipFirst) {
|
1332
|
-
var c = table ? $(table)[0].config : '',
|
1333
|
-
valid = ts.getFilters(table, true, filter, skipFirst);
|
1334
|
-
if (c && apply) {
|
1552
|
+
ts.setFilters = function( table, filter, apply, skipFirst ) {
|
1553
|
+
var c = table ? $( table )[0].config : '',
|
1554
|
+
valid = ts.getFilters( table, true, filter, skipFirst );
|
1555
|
+
if ( c && apply ) {
|
1335
1556
|
// ensure new set filters are applied, even if the search is the same
|
1336
1557
|
c.lastCombinedFilter = null;
|
1337
1558
|
c.lastSearch = [];
|
1338
|
-
ts.filter.searching(c.table, filter, skipFirst);
|
1339
|
-
c.$table.trigger('filterFomatterUpdate');
|
1559
|
+
ts.filter.searching( c.table, filter, skipFirst );
|
1560
|
+
c.$table.trigger( 'filterFomatterUpdate' );
|
1340
1561
|
}
|
1341
1562
|
return !!valid;
|
1342
1563
|
};
|
1343
1564
|
|
1344
|
-
})(jQuery);
|
1565
|
+
})( jQuery );
|