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