2 |
- |
1 |
/*! Parser: input & select - updated 2018-07-10 (v2.30.7) *//*
|
|
|
2 |
* for jQuery 1.7+ & tablesorter 2.7.11+
|
|
|
3 |
* Demo: http://mottie.github.com/tablesorter/docs/example-widget-grouping.html
|
|
|
4 |
*/
|
|
|
5 |
/*jshint browser: true, jquery:true, unused:false */
|
|
|
6 |
;( function( $ ) {
|
|
|
7 |
'use strict';
|
|
|
8 |
|
|
|
9 |
var updateServer = function( /* event, $table, $input */ ) {
|
|
|
10 |
// do something here to update your server, if needed
|
|
|
11 |
// event = change event object
|
|
|
12 |
// $table = jQuery object of the table that was just updated
|
|
|
13 |
// $input = jQuery object(s) of the input or select that was modified; in v2.24.6,
|
|
|
14 |
// if the thead has a checkbox, $input may include multiple elements
|
|
|
15 |
};
|
|
|
16 |
|
|
|
17 |
// Custom parser for parsing input values
|
|
|
18 |
// updated dynamically using the 'change' function below
|
|
|
19 |
$.tablesorter.addParser({
|
|
|
20 |
id : 'inputs',
|
|
|
21 |
is : function() {
|
|
|
22 |
return false;
|
|
|
23 |
},
|
|
|
24 |
format : function( txt, table, cell ) {
|
|
|
25 |
var $input = $( cell ).find( 'input' );
|
|
|
26 |
return $input.length ? $input.val() : txt;
|
|
|
27 |
},
|
|
|
28 |
parsed : true, // filter widget flag
|
|
|
29 |
type : 'text'
|
|
|
30 |
});
|
|
|
31 |
|
|
|
32 |
$.tablesorter.addParser({
|
|
|
33 |
id : 'inputs-numeric',
|
|
|
34 |
is : function() {
|
|
|
35 |
return false;
|
|
|
36 |
},
|
|
|
37 |
format : function( txt, table, cell ) {
|
|
|
38 |
var $input = $( cell ).find( 'input' );
|
|
|
39 |
var val = $input.length ? $input.val() : txt,
|
|
|
40 |
num = $.tablesorter.formatFloat( ( val || '' ).replace( /[^\w,. \-()]/g, '' ), table );
|
|
|
41 |
return txt && typeof num === 'number' ? num :
|
|
|
42 |
txt ? $.trim( txt && table.config.ignoreCase ? txt.toLocaleLowerCase() : txt ) : txt;
|
|
|
43 |
},
|
|
|
44 |
parsed : true, // filter widget flag
|
|
|
45 |
type : 'numeric'
|
|
|
46 |
});
|
|
|
47 |
|
|
|
48 |
// Custom parser for including checkbox status if using the grouping widget
|
|
|
49 |
// updated dynamically using the 'change' function below
|
|
|
50 |
$.tablesorter.addParser({
|
|
|
51 |
id : 'checkbox',
|
|
|
52 |
is : function() {
|
|
|
53 |
return false;
|
|
|
54 |
},
|
|
|
55 |
format : function( txt, table, cell ) {
|
|
|
56 |
var $cell = $( cell ),
|
|
|
57 |
wo = table.config.widgetOptions,
|
|
|
58 |
// returning plain language here because this is what is shown in the
|
|
|
59 |
// group headers - change it as desired
|
|
|
60 |
status = wo.group_checkbox ? wo.group_checkbox : [ 'checked', 'unchecked' ],
|
|
|
61 |
$input = $cell.find( 'input[type="checkbox"]' ),
|
|
|
62 |
isChecked = $input.length ? $input[ 0 ].checked : '';
|
|
|
63 |
return $input.length ? status[ isChecked ? 0 : 1 ] : txt;
|
|
|
64 |
},
|
|
|
65 |
parsed : true, // filter widget flag
|
|
|
66 |
type : 'text'
|
|
|
67 |
});
|
|
|
68 |
|
|
|
69 |
$.tablesorter.addParser({
|
|
|
70 |
id: 'radio',
|
|
|
71 |
is: function() {
|
|
|
72 |
return false;
|
|
|
73 |
},
|
|
|
74 |
format: function(txt, table, cell) {
|
|
|
75 |
var $input = $(cell).find('input:checked');
|
|
|
76 |
return $input.length ? $input.val() : txt;
|
|
|
77 |
},
|
|
|
78 |
parsed: true,
|
|
|
79 |
type: 'text'
|
|
|
80 |
});
|
|
|
81 |
|
|
|
82 |
// Custom parser which returns the currently selected options
|
|
|
83 |
// updated dynamically using the 'change' function below
|
|
|
84 |
$.tablesorter.addParser({
|
|
|
85 |
id : 'select',
|
|
|
86 |
is : function() {
|
|
|
87 |
return false;
|
|
|
88 |
},
|
|
|
89 |
format : function( txt, table, cell ) {
|
|
|
90 |
var $select = $( cell ).find( 'select' );
|
|
|
91 |
return $select.length ? $select.val() : txt;
|
|
|
92 |
},
|
|
|
93 |
parsed : true, // filter widget flag
|
|
|
94 |
type : 'text'
|
|
|
95 |
});
|
|
|
96 |
|
|
|
97 |
// Select parser to get the selected text
|
|
|
98 |
$.tablesorter.addParser({
|
|
|
99 |
id : 'select-text',
|
|
|
100 |
is : function() {
|
|
|
101 |
return false;
|
|
|
102 |
},
|
|
|
103 |
format : function( txt, table, cell ) {
|
|
|
104 |
var $select = $( cell ).find( 'select' );
|
|
|
105 |
return $select.length ? $select.find( 'option:selected' ).text() || '' : txt;
|
|
|
106 |
},
|
|
|
107 |
parsed : true, // filter widget flag
|
|
|
108 |
type : 'text'
|
|
|
109 |
});
|
|
|
110 |
|
|
|
111 |
// Custom parser for parsing textarea values
|
|
|
112 |
// updated dynamically using the 'change' function below
|
|
|
113 |
$.tablesorter.addParser({
|
|
|
114 |
id : 'textarea',
|
|
|
115 |
is : function() {
|
|
|
116 |
return false;
|
|
|
117 |
},
|
|
|
118 |
format : function( txt, table, cell ) {
|
|
|
119 |
var $textarea = $( cell ).find( 'textarea' );
|
|
|
120 |
return $textarea.length ? $textarea.val() : txt;
|
|
|
121 |
},
|
|
|
122 |
parsed : true, // filter widget flag
|
|
|
123 |
type : 'text'
|
|
|
124 |
});
|
|
|
125 |
|
|
|
126 |
// update defaults for validator; values must be falsy
|
|
|
127 |
$.tablesorter.defaults.checkboxClass = '';
|
|
|
128 |
$.tablesorter.defaults.checkboxVisible = '';
|
|
|
129 |
|
|
|
130 |
// update select and all input types in the tablesorter cache when the change event fires.
|
|
|
131 |
// This method only works with jQuery 1.7+
|
|
|
132 |
// you can change it to use delegate (v1.4.3+) or live (v1.3+) as desired
|
|
|
133 |
// if this code interferes somehow, target the specific table $('#mytable'), instead of $('table')
|
|
|
134 |
$( function() {
|
|
|
135 |
if ( !$.fn.on ) { return; }
|
|
|
136 |
var toggleRowClass = function( $row, checkboxClass, indx, isChecked ) {
|
|
|
137 |
// adding class to row, indicating that a checkbox is checked; includes
|
|
|
138 |
// a column index in case more than one checkbox happens to be in a row
|
|
|
139 |
$row.toggleClass( checkboxClass + '-' + indx, isChecked );
|
|
|
140 |
// don't remove checked class if other columns have a check
|
|
|
141 |
if ( ( $row[0].className || '' ).match( checkboxClass + '-' ) ) {
|
|
|
142 |
$row.addClass( checkboxClass );
|
|
|
143 |
} else {
|
|
|
144 |
$row.removeClass( checkboxClass );
|
|
|
145 |
}
|
|
|
146 |
},
|
|
|
147 |
updateCheckbox = function($el, state) {
|
|
|
148 |
if ($el.length && $el[0].nodeName !== 'INPUT') {
|
|
|
149 |
$el = $el.find( 'input[type="checkbox"]' );
|
|
|
150 |
}
|
|
|
151 |
if ($el.length) {
|
|
|
152 |
var ua = window.navigator.userAgent;
|
|
|
153 |
if (state === 'indeterminate') {
|
|
|
154 |
// needed for IE
|
|
|
155 |
$el.prop('checked', !(ua.indexOf('Trident/') > -1 || ua.indexOf('Edge/') > -1));
|
|
|
156 |
$el.prop('indeterminate', true);
|
|
|
157 |
} else {
|
|
|
158 |
$el.prop('checked', state);
|
|
|
159 |
$el.prop('indeterminate', false);
|
|
|
160 |
}
|
|
|
161 |
}
|
|
|
162 |
},
|
|
|
163 |
updateHeaderCheckbox = function( $table, checkboxClass ) {
|
|
|
164 |
var $sticky,
|
|
|
165 |
$rows = $table.children( 'tbody' ).children( ':visible' ), // (include child rows?)
|
|
|
166 |
len = $rows.length,
|
|
|
167 |
c = $table[0].config,
|
|
|
168 |
wo = c && c.widgetOptions,
|
|
|
169 |
$headers = c && c.$headers.add( $( c.namespace + '_extra_headers' ) ) || $table.children( 'thead' ),
|
|
|
170 |
hasSticky = wo && wo.$sticky;
|
|
|
171 |
// set indeterminate state on header checkbox
|
|
|
172 |
$headers.find( 'input[type="checkbox"]' ).each( function() {
|
|
|
173 |
if (hasSticky) {
|
|
|
174 |
$sticky = hasSticky.find( '[data-column="' + column + '"]' );
|
|
|
175 |
}
|
|
|
176 |
var column = $( this ).closest( 'td, th' ).attr( 'data-column' ),
|
|
|
177 |
vis = $rows.filter( '.' + checkboxClass + '-' + column ).length,
|
|
|
178 |
allChecked = vis === len && len > 0;
|
|
|
179 |
if ( vis === 0 || allChecked ) {
|
|
|
180 |
updateCheckbox($(this), allChecked);
|
|
|
181 |
if ($sticky) {
|
|
|
182 |
updateCheckbox($sticky, allChecked);
|
|
|
183 |
}
|
|
|
184 |
} else {
|
|
|
185 |
updateCheckbox($(this), 'indeterminate');
|
|
|
186 |
if ($sticky) {
|
|
|
187 |
updateCheckbox($sticky, 'indeterminate');
|
|
|
188 |
}
|
|
|
189 |
}
|
|
|
190 |
});
|
|
|
191 |
|
|
|
192 |
};
|
|
|
193 |
|
|
|
194 |
$( 'table' ).on( 'tablesorter-initialized updateComplete', function() {
|
|
|
195 |
this.tablesorterBusy = false;
|
|
|
196 |
var namespace = '.parser-forms';
|
|
|
197 |
$( this )
|
|
|
198 |
// add namespace to table in case of version mismatch (v2.28.10)
|
|
|
199 |
.addClass( this.config.namespace.slice(1) )
|
|
|
200 |
.children( 'tbody' )
|
|
|
201 |
.off( namespace )
|
|
|
202 |
.on( 'mouseleave' + namespace, function( event ) {
|
|
|
203 |
// make sure we restore original values (trigger blur)
|
|
|
204 |
// isTbody is needed to prevent the select from closing in IE
|
|
|
205 |
// see https://connect.microsoft.com/IE/feedbackdetail/view/962618/
|
|
|
206 |
if ( event.target.nodeName === 'TBODY' ) {
|
|
|
207 |
$( ':focus' ).blur();
|
|
|
208 |
}
|
|
|
209 |
})
|
|
|
210 |
.on( 'focus' + namespace, 'select, input:not([type=checkbox]), textarea', function( event ) {
|
|
|
211 |
var $row = $( event.target ).closest( 'tr' ),
|
|
|
212 |
c = $row.closest( 'table' )[0].config;
|
|
|
213 |
if ( !c || c && c.ignoreChildRow && $row.hasClass( c.cssChildRow ) ) {
|
|
|
214 |
return;
|
|
|
215 |
}
|
|
|
216 |
$( this ).data( 'ts-original-value', this.value );
|
|
|
217 |
})
|
|
|
218 |
.on( 'blur' + namespace, 'input:not([type=checkbox]), textarea', function( event ) {
|
|
|
219 |
var $row = $( event.target ).closest( 'tr' ),
|
|
|
220 |
c = $row.closest( 'table' )[0].config;
|
|
|
221 |
if ( !c || c && c.ignoreChildRow && $row.hasClass( c.cssChildRow ) ) {
|
|
|
222 |
return;
|
|
|
223 |
}
|
|
|
224 |
// restore input value;
|
|
|
225 |
// 'change' is triggered before 'blur' so this doesn't replace the new update with the original
|
|
|
226 |
this.value = $( this ).data( 'ts-original-value' );
|
|
|
227 |
})
|
|
|
228 |
.on( 'change keyup '.split( ' ' ).join( namespace + ' ' ), 'select, input, textarea', function( event ) {
|
|
|
229 |
var $row = $( this ).closest( 'tr' ),
|
|
|
230 |
c = $row.closest( 'table' )[0].config;
|
|
|
231 |
if ( !c || c && c.ignoreChildRow && $row.hasClass( c.cssChildRow ) ) {
|
|
|
232 |
return;
|
|
|
233 |
}
|
|
|
234 |
if ( event.which === 27 && !( this.nodeName === 'INPUT' && this.type === 'checkbox' ) ) {
|
|
|
235 |
// escape: restore original value
|
|
|
236 |
this.value = $( this ).data( 'ts-original-value' );
|
|
|
237 |
return;
|
|
|
238 |
}
|
|
|
239 |
// Update cell cache using... select: change, input: enter or textarea: alt + enter
|
|
|
240 |
if ( event.type === 'change' ||
|
|
|
241 |
( event.type === 'keyup' && event.which === 13 &&
|
|
|
242 |
( event.target.nodeName === 'INPUT' || event.target.nodeName === 'TEXTAREA' && event.altKey ) ) ) {
|
|
|
243 |
var undef, checkboxClass,
|
|
|
244 |
$target = $( event.target ),
|
|
|
245 |
isCheckbox = event.target.type === 'checkbox',
|
|
|
246 |
$cell = $target.closest( 'td' ),
|
|
|
247 |
indx = $cell[ 0 ].cellIndex,
|
|
|
248 |
busy = c.table.tablesorterBusy,
|
|
|
249 |
$hdr = c.$headerIndexed && c.$headerIndexed[ indx ] || [],
|
|
|
250 |
val = isCheckbox ? event.target.checked : $target.val();
|
|
|
251 |
// abort if not a tablesorter table, or busy
|
|
|
252 |
if ( $.isEmptyObject( c ) || busy !== false ) {
|
|
|
253 |
return;
|
|
|
254 |
}
|
|
|
255 |
if ( isCheckbox ) {
|
|
|
256 |
checkboxClass = c.checkboxClass || 'checked';
|
|
|
257 |
toggleRowClass( $cell.closest( 'tr' ), checkboxClass, indx, val );
|
|
|
258 |
updateHeaderCheckbox( c.$table, checkboxClass );
|
|
|
259 |
}
|
|
|
260 |
// don't use updateCell if column is set to 'sorter-false' and 'filter-false',
|
|
|
261 |
// or column is set to 'parser-false'
|
|
|
262 |
if ( $hdr.length && ( $hdr.hasClass( 'parser-false' ) ||
|
|
|
263 |
( $hdr.hasClass( 'sorter-false' ) && $hdr.hasClass( 'filter-false' ) ) ) ||
|
|
|
264 |
// table already updating; get out of here, we might be in an endless loop (in IE)! See #971
|
|
|
265 |
( event.type === 'change' && c.table.isUpdating ) ) {
|
|
|
266 |
return;
|
|
|
267 |
}
|
|
|
268 |
// ignore change event if nothing changed
|
|
|
269 |
if ( c && val !== $target.data( 'ts-original-value' ) || isCheckbox ) {
|
|
|
270 |
$target.data( 'ts-original-value', val );
|
|
|
271 |
c.table.tablesorterBusy = true;
|
|
|
272 |
// pass undefined resort value so it falls back to config.resort setting
|
|
|
273 |
$.tablesorter.updateCell( c, $cell, undef, function() {
|
|
|
274 |
updateServer( event, c.$table, $target );
|
|
|
275 |
c.table.tablesorterBusy = false;
|
|
|
276 |
});
|
|
|
277 |
}
|
|
|
278 |
}
|
|
|
279 |
});
|
|
|
280 |
|
|
|
281 |
// add code for a checkbox in the header to set/unset all checkboxes in a column
|
|
|
282 |
if ( $( this ).children( 'thead' ).find( 'input[type="checkbox"]' ) ) {
|
|
|
283 |
$( this )
|
|
|
284 |
.off( namespace )
|
|
|
285 |
.on( 'tablesorter-ready' + namespace, function() {
|
|
|
286 |
var checkboxClass,
|
|
|
287 |
$table = $( this ),
|
|
|
288 |
c = $table.length && $table[ 0 ].config;
|
|
|
289 |
if ( !$.isEmptyObject( c ) ) {
|
|
|
290 |
this.tablesorterBusy = true;
|
|
|
291 |
checkboxClass = c && c.checkboxClass || 'checked';
|
|
|
292 |
// set indeterminate state on header checkbox
|
|
|
293 |
updateHeaderCheckbox( $table, checkboxClass );
|
|
|
294 |
this.tablesorterBusy = false;
|
|
|
295 |
}
|
|
|
296 |
})
|
|
|
297 |
.children( 'thead' )
|
|
|
298 |
.add( this.config.widgetOptions.$sticky )
|
|
|
299 |
.off( namespace )
|
|
|
300 |
// modified from http://jsfiddle.net/abkNM/6163/
|
|
|
301 |
// click needed for IE; a change isn't fired when going from an indeterminate checkbox to
|
|
|
302 |
// either checked or unchecked
|
|
|
303 |
.on( 'click' + namespace + ' change' + namespace, 'input[type="checkbox"]', function( event ) {
|
|
|
304 |
var c, undef, onlyVisible, column, $target, isParsed, checkboxClass,
|
|
|
305 |
$checkbox = $( this ),
|
|
|
306 |
isChecked = this.checked,
|
|
|
307 |
$table = $checkbox.closest( 'table' ),
|
|
|
308 |
isSticky = $table.length && $table[0].className.match(/(tablesorter\w+)_extra_table/);
|
|
|
309 |
if (isSticky) {
|
|
|
310 |
isSticky = isSticky[1];
|
|
|
311 |
$table = $('.' + isSticky + ':not(.' + isSticky + '_extra_table)');
|
|
|
312 |
}
|
|
|
313 |
c = $table.length && $table[ 0 ].config;
|
|
|
314 |
if ( $table.length && c && !$table[ 0 ].tablesorterBusy ) {
|
|
|
315 |
column = parseInt( $checkbox.closest( 'td, th' ).attr( 'data-column' ), 10 );
|
|
|
316 |
isParsed = c.parsers[ column ].id === 'checkbox';
|
|
|
317 |
onlyVisible = c.checkboxVisible;
|
|
|
318 |
$table[ 0 ].tablesorterBusy = true; // prevent "change" event from calling updateCell numerous times (see #971)
|
|
|
319 |
updateCheckbox(
|
|
|
320 |
$target = $table
|
|
|
321 |
.children( 'tbody' )
|
|
|
322 |
.children( 'tr' + ( typeof onlyVisible === 'undefined' || onlyVisible === true ? ':visible' : '' ) )
|
|
|
323 |
.children( ':nth-child(' + ( column + 1 ) + ')' ),
|
|
|
324 |
isChecked
|
|
|
325 |
);
|
|
|
326 |
// add checkbox class names to row
|
|
|
327 |
checkboxClass = c.checkboxClass || 'checked';
|
|
|
328 |
$target.each( function() {
|
|
|
329 |
toggleRowClass( $( this ).closest( 'tr' ), checkboxClass, column, isChecked );
|
|
|
330 |
});
|
|
|
331 |
if (isSticky) {
|
|
|
332 |
// make main table checkbox match sticky header checkbox
|
|
|
333 |
updateCheckbox($table.children( 'thead' ).find( '[data-column="' + column + '"]' ), isChecked);
|
|
|
334 |
} else if (c.widgetOptions.$sticky) {
|
|
|
335 |
updateCheckbox(c.widgetOptions.$sticky.find( 'thead' ).find( '[data-column="' + column + '"]' ), isChecked);
|
|
|
336 |
}
|
|
|
337 |
updateHeaderCheckbox( $table, checkboxClass );
|
|
|
338 |
if ( isParsed ) {
|
|
|
339 |
// only update cache if checkboxes are being sorted
|
|
|
340 |
$.tablesorter.update( c, undef, function() {
|
|
|
341 |
updateServer( event, $table, $target );
|
|
|
342 |
$table[ 0 ].tablesorterBusy = false;
|
|
|
343 |
});
|
|
|
344 |
} else {
|
|
|
345 |
updateServer( event, $table, $target );
|
|
|
346 |
$table[ 0 ].tablesorterBusy = false;
|
|
|
347 |
}
|
|
|
348 |
// needed for IE8
|
|
|
349 |
return true;
|
|
|
350 |
}
|
|
|
351 |
// update already going on, don't do anything!
|
|
|
352 |
return false;
|
|
|
353 |
});
|
|
|
354 |
}
|
|
|
355 |
|
|
|
356 |
});
|
|
|
357 |
});
|
|
|
358 |
|
|
|
359 |
})( jQuery );
|