jquery-tablesorter 1.4.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,924 @@
1
+ /*! Filter widget formatter functions - updated 6/4/2013
2
+ * requires: tableSorter 2.7.7+ and jQuery 1.4.3+
3
+ *
4
+ * uiSpinner (jQuery UI spinner)
5
+ * uiSlider (jQuery UI slider)
6
+ * uiRange (jQuery UI range slider)
7
+ * uiDateCompare (jQuery UI datepicker+compare selector; 1 input)
8
+ * uiDatepicker (jQuery UI datepicker; 2 inputs, filter range)
9
+ * html5Number (spinner+compare selector)
10
+ * html5Range (slider)
11
+ * html5Color (color)
12
+ */
13
+ /*jshint browser:true, jquery:true, unused:false */
14
+ /*global jQuery: false */
15
+ ;(function($){
16
+ "use strict";
17
+ $.tablesorter = $.tablesorter || {};
18
+
19
+ $.tablesorter.filterFormatter = {
20
+
21
+ /**********************\
22
+ jQuery UI Spinner
23
+ \**********************/
24
+ uiSpinner: function($cell, indx, spinnerDef) {
25
+ var o = $.extend({
26
+ min : 0,
27
+ max : 100,
28
+ step : 1,
29
+ value : 1,
30
+ delayed : true,
31
+ addToggle : true,
32
+ disabled : false,
33
+ exactMatch : true,
34
+ compare : ''
35
+ }, spinnerDef ),
36
+ // Add a hidden input to hold the range values
37
+ $input = $('<input class="filter" type="hidden">')
38
+ .appendTo($cell)
39
+ // hidden filter update (.tsfilter) namespace trigger by filter widget
40
+ .bind('change.tsfilter', function(){
41
+ updateSpinner({ value: this.value, delayed: false });
42
+ }),
43
+ $shcell = [],
44
+ c = $cell.closest('table')[0].config,
45
+
46
+ // this function updates the hidden input and adds the current values to the header cell text
47
+ updateSpinner = function(ui) {
48
+ var chkd = true, state,
49
+ // ui is not undefined on create
50
+ v = ui && ui.value && $.tablesorter.formatFloat((ui.value + '').replace(/[><=]/g,'')) || $cell.find('.spinner').val() || o.value;
51
+ if (o.addToggle) {
52
+ chkd = $cell.find('.toggle').is(':checked');
53
+ }
54
+ state = o.disabled || !chkd ? 'disable' : 'enable';
55
+ $cell.find('.filter')
56
+ // add equal to the beginning, so we filter exact numbers
57
+ .val( chkd ? (o.compare ? o.compare : o.exactMatch ? '=' : '') + v : '' )
58
+ .trigger('search', ui && typeof ui.delayed === 'boolean' ? ui.delayed : o.delayed).end()
59
+ .find('.spinner').spinner(state).val(v);
60
+ // update sticky header cell
61
+ if ($shcell.length) {
62
+ $shcell.find('.spinner').spinner(state).val(v);
63
+ if (o.addToggle) {
64
+ $shcell.find('.toggle')[0].checked = chkd;
65
+ }
66
+ }
67
+ };
68
+
69
+ // add callbacks; preserve added callbacks
70
+ o.oldcreate = o.create;
71
+ o.oldspin = o.spin;
72
+ o.create = function(event, ui) {
73
+ updateSpinner(); // ui is an empty object on create
74
+ if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); }
75
+ };
76
+ o.spin = function(event, ui) {
77
+ updateSpinner(ui);
78
+ if (typeof o.oldspin === 'function') { o.oldspin(event, ui); }
79
+ };
80
+ if (o.addToggle) {
81
+ $('<div class="button"><input id="uispinnerbutton' + indx + '" type="checkbox" class="toggle" /><label for="uispinnerbutton' + indx + '"></label></div>')
82
+ .appendTo($cell)
83
+ .find('.toggle')
84
+ .bind('change', function(){
85
+ updateSpinner();
86
+ });
87
+ }
88
+ // make sure we use parsed data
89
+ $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
90
+ // add a jQuery UI spinner!
91
+ $('<input class="spinner spinner' + indx + '" />')
92
+ .val(o.value)
93
+ .appendTo($cell)
94
+ .spinner(o)
95
+ .bind('change keyup', function(e){
96
+ updateSpinner();
97
+ });
98
+
99
+ // has sticky headers?
100
+ c.$table.bind('stickyHeadersInit', function(){
101
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
102
+ if (o.addToggle) {
103
+ $('<div class="button"><input id="stickyuispinnerbutton' + indx + '" type="checkbox" class="toggle" /><label for="stickyuispinnerbutton' + indx + '"></label></div>')
104
+ .appendTo($shcell)
105
+ .find('.toggle')
106
+ .bind('change', function(){
107
+ $cell.find('.toggle')[0].checked = this.checked;
108
+ updateSpinner();
109
+ });
110
+ }
111
+ // add a jQuery UI spinner!
112
+ $('<input class="spinner spinner' + indx + '" />')
113
+ .val(o.value)
114
+ .appendTo($shcell)
115
+ .spinner(o)
116
+ .bind('change keyup', function(e){
117
+ $cell.find('.spinner').val( this.value );
118
+ updateSpinner();
119
+ });
120
+ });
121
+
122
+ // on reset
123
+ c.$table.bind('filterReset', function(){
124
+ // turn off the toggle checkbox
125
+ if (o.addToggle) {
126
+ $cell.find('.toggle')[0].checked = false;
127
+ }
128
+ updateSpinner();
129
+ });
130
+
131
+ updateSpinner();
132
+ return $input;
133
+ },
134
+
135
+ /**********************\
136
+ jQuery UI Slider
137
+ \**********************/
138
+ uiSlider: function($cell, indx, sliderDef) {
139
+ var o = $.extend({
140
+ value : 0,
141
+ min : 0,
142
+ max : 100,
143
+ step : 1,
144
+ range : "min",
145
+ delayed : true,
146
+ valueToHeader : false,
147
+ exactMatch : true,
148
+ compare : '',
149
+ allText : 'all'
150
+ }, sliderDef ),
151
+ // Add a hidden input to hold the range values
152
+ $input = $('<input class="filter" type="hidden">')
153
+ .appendTo($cell)
154
+ // hidden filter update (.tsfilter) namespace trigger by filter widget
155
+ .bind('change.tsfilter', function(){
156
+ updateSlider({ value: this.value });
157
+ }),
158
+ $shcell = [],
159
+ c = $cell.closest('table')[0].config,
160
+
161
+ // this function updates the hidden input and adds the current values to the header cell text
162
+ updateSlider = function(ui) {
163
+ // ui is not undefined on create
164
+ var v = typeof ui !== "undefined" ? $.tablesorter.formatFloat((ui.value + '').replace(/[><=]/g,'')) || o.min : o.value,
165
+ val = o.compare ? v : v === o.min ? o.allText : v,
166
+ result = o.compare + val;
167
+ if (o.valueToHeader) {
168
+ // add range indication to the header cell above!
169
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(' (' + result + ')');
170
+ } else {
171
+ // add values to the handle data-value attribute so the css tooltip will work properly
172
+ $cell.find('.ui-slider-handle').addClass('value-popup').attr('data-value', result);
173
+ }
174
+ // update the hidden input;
175
+ // ****** ADD AN EQUAL SIGN TO THE BEGINNING! <- this makes the slide exactly match the number ******
176
+ // when the value is at the minimum, clear the hidden input so all rows will be seen
177
+ $cell.find('.filter')
178
+ .val( ( o.compare ? o.compare + v : v === o.min ? '' : (o.exactMatch ? '=' : '') + v ) )
179
+ .trigger('search', ui && typeof ui.delayed === 'boolean' ? ui.delayed : o.delayed).end()
180
+ .find('.slider').slider('value', v);
181
+
182
+ // update sticky header cell
183
+ if ($shcell.length) {
184
+ $shcell.find('.slider').slider('value', v);
185
+ if (o.valueToHeader) {
186
+ $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(' (' + result + ')');
187
+ } else {
188
+ $shcell.find('.ui-slider-handle').addClass('value-popup').attr('data-value', result);
189
+ }
190
+ }
191
+
192
+ };
193
+ $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
194
+
195
+ // add span to header for value - only works if the line in the updateSlider() function is also un-commented out
196
+ if (o.valueToHeader) {
197
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append('<span class="curvalue" />');
198
+ }
199
+
200
+ // add callbacks; preserve added callbacks
201
+ o.oldcreate = o.create;
202
+ o.oldslide = o.slide;
203
+ o.create = function(event, ui) {
204
+ updateSlider(); // ui is an empty object on create
205
+ if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); }
206
+ };
207
+ o.slide = function(event, ui) {
208
+ updateSlider(ui);
209
+ if (typeof o.oldslide === 'function') { o.oldslide(event, ui); }
210
+ };
211
+ // add a jQuery UI slider!
212
+ $('<div class="slider slider' + indx + '"/>')
213
+ .appendTo($cell)
214
+ .slider(o);
215
+
216
+ // on reset
217
+ c.$table.bind('filterReset', function(){
218
+ $cell.find('.slider').slider('value', o.value);
219
+ updateSlider();
220
+ });
221
+
222
+ // has sticky headers?
223
+ c.$table.bind('stickyHeadersInit', function(){
224
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
225
+
226
+ // add a jQuery UI slider!
227
+ $('<div class="slider slider' + indx + '"/>')
228
+ .val(o.value)
229
+ .appendTo($shcell)
230
+ .slider(o)
231
+ .bind('change keyup', function(e){
232
+ $cell.find('.slider').val( this.value );
233
+ updateSlider();
234
+ });
235
+
236
+ });
237
+
238
+ return $input;
239
+ },
240
+
241
+ /*************************\
242
+ jQuery UI Range Slider (2 handles)
243
+ \*************************/
244
+ uiRange: function($cell, indx, rangeDef) {
245
+ var o = $.extend({
246
+ values : [0, 100],
247
+ min : 0,
248
+ max : 100,
249
+ range : true,
250
+ delayed : true,
251
+ valueToHeader : false
252
+ }, rangeDef ),
253
+ // Add a hidden input to hold the range values
254
+ $input = $('<input class="filter" type="hidden">')
255
+ .appendTo($cell)
256
+ // hidden filter update (.tsfilter) namespace trigger by filter widget
257
+ .bind('change.tsfilter', function(){
258
+ var v = this.value.split(' - ');
259
+ if (this.value === '') { v = [ o.min, o.max ]; }
260
+ if (v && v[1]) {
261
+ updateUiRange({ values: v, delay: false });
262
+ }
263
+ }),
264
+ $shcell = [],
265
+ c = $cell.closest('table')[0].config,
266
+
267
+ // this function updates the hidden input and adds the current values to the header cell text
268
+ updateUiRange = function(ui) {
269
+ // ui.values are undefined for some reason on create
270
+ var val = ui && ui.values || o.values,
271
+ result = val[0] + ' - ' + val[1],
272
+ // make range an empty string if entire range is covered so the filter row will hide (if set)
273
+ range = val[0] === o.min && val[1] === o.max ? '' : result;
274
+ if (o.valueToHeader) {
275
+ // add range indication to the header cell above (if not using the css method)!
276
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.currange').html(' (' + result + ')');
277
+ } else {
278
+ // add values to the handle data-value attribute so the css tooltip will work properly
279
+ $cell.find('.ui-slider-handle')
280
+ .addClass('value-popup')
281
+ .eq(0).attr('data-value', val[0]).end() // adding value to data attribute
282
+ .eq(1).attr('data-value', val[1]); // value popup shown via css
283
+ }
284
+ // update the hidden input
285
+ $cell.find('.filter').val(range)
286
+ .trigger('search', ui && typeof ui.delayed === 'boolean' ? ui.delayed : o.delayed).end()
287
+ .find('.range').slider('values', val);
288
+ // update sticky header cell
289
+ if ($shcell.length) {
290
+ $shcell.find('.range').slider('values', val);
291
+ if (o.valueToHeader) {
292
+ $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.currange').html(' (' + result + ')');
293
+ } else {
294
+ $shcell.find('.ui-slider-handle')
295
+ .addClass('value-popup')
296
+ .eq(0).attr('data-value', val[0]).end() // adding value to data attribute
297
+ .eq(1).attr('data-value', val[1]); // value popup shown via css
298
+ }
299
+ }
300
+
301
+ };
302
+ $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
303
+
304
+ // add span to header for value - only works if the line in the updateUiRange() function is also un-commented out
305
+ if (o.valueToHeader) {
306
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append('<span class="currange"/>');
307
+ }
308
+
309
+ // add callbacks; preserve added callbacks
310
+ o.oldcreate = o.create;
311
+ o.oldslide = o.slide;
312
+ // add a jQuery UI range slider!
313
+ o.create = function(event, ui) {
314
+ updateUiRange(); // ui is an empty object on create
315
+ if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); }
316
+ };
317
+ o.slide = function(event, ui) {
318
+ updateUiRange(ui);
319
+ if (typeof o.oldslide === 'function') { o.oldslide(event, ui); }
320
+ };
321
+ $('<div class="range range' + indx +'"/>')
322
+ .appendTo($cell)
323
+ .slider(o);
324
+
325
+ // on reset
326
+ c.$table.bind('filterReset', function(){
327
+ $cell.find('.range').slider('values', o.values);
328
+ updateUiRange();
329
+ });
330
+
331
+ // has sticky headers?
332
+ c.$table.bind('stickyHeadersInit', function(){
333
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
334
+
335
+ // add a jQuery UI slider!
336
+ $('<div class="range range' + indx + '"/>')
337
+ .val(o.value)
338
+ .appendTo($shcell)
339
+ .slider(o)
340
+ .bind('change keyup', function(e){
341
+ $cell.find('.range').val( this.value );
342
+ updateUiRange();
343
+ });
344
+
345
+ });
346
+
347
+ // return the hidden input so the filter widget has a reference to it
348
+ return $input;
349
+ },
350
+
351
+ /*************************\
352
+ jQuery UI Datepicker compare (1 input)
353
+ \*************************/
354
+ uiDateCompare: function($cell, indx, defDate) {
355
+ var o = $.extend({
356
+ defaultDate : '',
357
+ cellText : '',
358
+ changeMonth : true,
359
+ changeYear : true,
360
+ numberOfMonths : 1,
361
+ compare : '',
362
+ compareOptions : false
363
+ }, defDate),
364
+ $hdr = $cell.closest('thead').find('th[data-column=' + indx + ']'),
365
+ // Add a hidden input to hold the range values
366
+ $input = $('<input class="dateCompare" type="hidden">')
367
+ .appendTo($cell)
368
+ // hidden filter update (.tsfilter) namespace trigger by filter widget
369
+ .bind('change.tsfilter', function(){
370
+ var v = this.value;
371
+ if (v) {
372
+ o.onClose(v);
373
+ }
374
+ }),
375
+ t, l, $shcell = [],
376
+ c = $cell.closest('table')[0].config,
377
+
378
+ // this function updates the hidden input
379
+ updateCompare = function(v) {
380
+ var date = new Date($cell.find('.date').datepicker('getDate')).getTime();
381
+
382
+ $cell.find('.compare').val(v);
383
+ $cell.find('.dateCompare')
384
+ // add equal to the beginning, so we filter exact numbers
385
+ .val(v + date)
386
+ .trigger('search', o.delayed).end();
387
+ // update sticky header cell
388
+ if ($shcell.length) {
389
+ $shcell.find('.compare').val(v);
390
+ }
391
+ };
392
+
393
+ // make sure we're using parsed dates in the search
394
+ $hdr.addClass('filter-parsed');
395
+
396
+ // Add date range picker
397
+ if (o.compareOptions) {
398
+ l = '<select class="compare">';
399
+ for(var myOption in o.compareOptions) {
400
+ l += '<option value="' + myOption + '"';
401
+ if (myOption === o.compare)
402
+ l += ' selected="selected"';
403
+ l += '>' + myOption + '</option>';
404
+ }
405
+ l += '</select>';
406
+ $cell.append(l)
407
+ .find('.compare')
408
+ .bind('change', function(){
409
+ updateCompare($(this).val());
410
+ });
411
+ } else if (o.cellText) {
412
+ l = '<label>' + o.cellText + '</label>';
413
+ $cell.append(l);
414
+ }
415
+
416
+ t = '<input type="text" class="date date' + indx +
417
+ '" placeholder="' + ($hdr.data('placeholder') || $hdr.attr('data-placeholder') || '') + '" />';
418
+ $(t).appendTo($cell);
419
+
420
+ // add callbacks; preserve added callbacks
421
+ o.oldonClose = o.onClose;
422
+
423
+ o.onClose = function( selectedDate, ui ) {
424
+ var date = new Date($cell.find('.date').datepicker('getDate')).getTime() || '';
425
+ var compare = ( $cell.find('.compare').val() || o.compare);
426
+ $cell
427
+ // update hidden input
428
+ .find('.dateCompare').val( compare + date )
429
+ .trigger('search').end()
430
+ .find('.date')
431
+ .datepicker('setDate', selectedDate);
432
+
433
+ // update sticky header cell
434
+ if ($shcell.length) {
435
+ $shcell.find('.date').datepicker('setDate', selectedDate);
436
+ }
437
+
438
+ if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); }
439
+ };
440
+ $cell.find('.date').datepicker(o);
441
+
442
+ if (o.filterDate) {
443
+ $cell.find('.date').datepicker('setDate', o.filterDate);
444
+ }
445
+
446
+ // on reset
447
+ c.$table.bind('filterReset', function(){
448
+ $cell.find('.date').val('').datepicker('option', 'currentText', '' );
449
+ if ($shcell.length) {
450
+ $shcell.find('.date').val('').datepicker('option', 'currentText', '' );
451
+ }
452
+ });
453
+
454
+ // has sticky headers?
455
+ c.$table.bind('stickyHeadersInit', function(){
456
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
457
+ if (o.compareOptions) {
458
+ $shcell.append(l)
459
+ .find('.compare')
460
+ .bind('change', function(){
461
+ updateCompare($(this).val());
462
+ });
463
+ } else if (o.cellText) {
464
+ $shcell.append(l);
465
+ }
466
+
467
+ // add a jQuery datepicker!
468
+ $shcell
469
+ .append(t)
470
+ .find('.date')
471
+ .datepicker(o);
472
+ });
473
+
474
+ // return the hidden input so the filter widget has a reference to it
475
+ return $input.val( o.defaultDate ? o.defaultDate : '' );
476
+ },
477
+
478
+ /*************************\
479
+ jQuery UI Datepicker (2 inputs)
480
+ \*************************/
481
+ uiDatepicker: function($cell, indx, defDate) {
482
+ var o = $.extend({
483
+ from : '',
484
+ to : '',
485
+ textFrom : 'from',
486
+ textTo : 'to',
487
+ changeMonth : true,
488
+ changeYear : true,
489
+ numberOfMonths : 1
490
+ }, defDate),
491
+ t, closeFrom, $shcell = [],
492
+ // Add a hidden input to hold the range values
493
+ $input = $('<input class="dateRange" type="hidden">')
494
+ .appendTo($cell)
495
+ // hidden filter update (.tsfilter) namespace trigger by filter widget
496
+ .bind('change.tsfilter', function(){
497
+ var v = this.value;
498
+ if (v.match(' - ')) {
499
+ v = v.split(' - ');
500
+ $cell.find('.dateTo').val(v[1]);
501
+ closeFrom(v[0]);
502
+ } else if (v.match('>=')) {
503
+ closeFrom( v.replace('>=', '') );
504
+ } else if (v.match('<=')) {
505
+ o.onClose( v.replace('<=', '') );
506
+ }
507
+ }),
508
+ c = $cell.closest('table')[0].config;
509
+
510
+ // make sure we're using parsed dates in the search
511
+ $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed');
512
+ // Add date range picker
513
+ t = '<label>' + o.textFrom + '</label><input type="text" class="dateFrom" /><label>' + o.textTo + '</label><input type="text" class="dateTo" />';
514
+ $(t).appendTo($cell);
515
+
516
+ // add callbacks; preserve added callbacks
517
+ o.oldonClose = o.onClose;
518
+
519
+ o.defaultDate = o.from || o.defaultDate;
520
+
521
+ closeFrom = o.onClose = function( selectedDate, ui ) {
522
+ var from = new Date($cell.find('.dateFrom').datepicker('getDate')).getTime() || '',
523
+ to = new Date($cell.find('.dateTo').datepicker('getDate')).getTime() || '',
524
+ range = from ? ( to ? from + ' - ' + to : '>=' + from ) : (to ? '<=' + to : '');
525
+ $cell
526
+ .find('.dateTo').datepicker('option', 'minDate', selectedDate ).end()
527
+ .find('.dateFrom').val(selectedDate).end()
528
+ // update hidden input
529
+ .find('.dateRange').val(range)
530
+ .trigger('search');
531
+ // update sticky header cell
532
+ if ($shcell.length) {
533
+ $shcell
534
+ .find('.dateTo').datepicker('option', 'minDate', selectedDate ).end()
535
+ .find('.dateFrom').val(selectedDate);
536
+ }
537
+ if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); }
538
+ };
539
+
540
+ $cell.find('.dateFrom').datepicker(o);
541
+ o.defaultDate = o.to || '+7d'; // set to date +7 days from today (if not defined)
542
+ o.onClose = function( selectedDate, ui ) {
543
+ var from = new Date( $cell.find('.dateFrom').datepicker('getDate') ).getTime() || '',
544
+ to = new Date( $cell.find('.dateTo').datepicker('getDate') ).getTime() || '',
545
+ range = from ? ( to ? from + ' - ' + to : '>=' + from ) : (to ? '<=' + to : '');
546
+ $cell
547
+ .find('.dateFrom').datepicker('option', 'maxDate', selectedDate ).end()
548
+ .find('.dateTo').val(selectedDate).end()
549
+ .find('.dateRange').val(range)
550
+ .trigger('search');
551
+ // update sticky header cell
552
+ if ($shcell.length) {
553
+ $shcell
554
+ .find('.dateFrom').datepicker('option', 'maxDate', selectedDate ).end()
555
+ .find('.dateTo').val(selectedDate);
556
+ }
557
+ if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); }
558
+ };
559
+ $cell.find('.dateTo').datepicker(o);
560
+
561
+ // has sticky headers?
562
+ c.$table.bind('stickyHeadersInit', function(){
563
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
564
+ // add a jQuery datepicker!
565
+ $shcell.append(t).find('.dateTo').datepicker(o);
566
+ o.defaultDate = o.from || o.defaultDate || new Date();
567
+ o.onClose = closeFrom;
568
+ $shcell.find('.dateFrom').datepicker(o);
569
+ });
570
+
571
+ // on reset
572
+ $cell.closest('table').bind('filterReset', function(){
573
+ $cell.find('.dateFrom, .dateTo').val('');
574
+ if ($shcell.length) {
575
+ $shcell.find('.dateFrom, .dateTo').val('');
576
+ }
577
+ });
578
+
579
+ // return the hidden input so the filter widget has a reference to it
580
+ t = o.from ? ( o.to ? o.from + ' - ' + o.to : '>=' + o.from ) : (o.to ? '<=' + o.to : '');
581
+ return $input.val( t );
582
+ },
583
+
584
+ /**********************\
585
+ HTML5 Number (spinner)
586
+ \**********************/
587
+ html5Number : function($cell, indx, def5Num) {
588
+ var t, o = $.extend({
589
+ value : 0,
590
+ min : 0,
591
+ max : 100,
592
+ step : 1,
593
+ delayed : true,
594
+ disabled : false,
595
+ addToggle : true,
596
+ exactMatch : true,
597
+ compare : '',
598
+ compareOptions : false,
599
+ skipTest: false
600
+ }, def5Num),
601
+
602
+ // test browser for HTML5 range support
603
+ $number = $('<input type="number" style="visibility:hidden;" value="test">').appendTo($cell),
604
+ // test if HTML5 number is supported - from Modernizr
605
+ numberSupported = o.skipTest || $number.attr('type') === 'number' && $number.val() !== 'test',
606
+ t, l, $shcell = [],
607
+ c = $cell.closest('table')[0].config,
608
+
609
+ updateCompare = function(v) {
610
+ var number = $cell.find('.number').val();
611
+
612
+ $cell.find('.compare').val(v);
613
+ $cell.find('input[type=hidden]')
614
+ // add equal to the beginning, so we filter exact numbers
615
+ .val(v + number)
616
+ .trigger('search', o.delayed).end();
617
+ // update sticky header cell
618
+ if ($shcell.length) {
619
+ $shcell.find('.compare').val(v);
620
+ }
621
+ },
622
+
623
+ updateNumber = function(v, delayed){
624
+ var chkd = o.addToggle ? $cell.find('.toggle').is(':checked') : true;
625
+ var compare = ( $cell.find('.compare').val() || o.compare);
626
+ $cell.find('input[type=hidden]')
627
+ // add equal to the beginning, so we filter exact numbers
628
+ .val( !o.addToggle || chkd ? (o.compare ? o.compare : o.exactMatch ? '=' : '') + v : '' )
629
+ .val( !o.addToggle || chkd ? compare + v : '' )
630
+ .trigger('search', delayed ? delayed : o.delayed).end()
631
+ .find('.number').val(v);
632
+ if ($cell.find('.number').length) {
633
+ $cell.find('.number')[0].disabled = (o.disabled || !chkd);
634
+ }
635
+ // update sticky header cell
636
+ if ($shcell.length) {
637
+ $shcell.find('.number').val(v)[0].disabled = (o.disabled || !chkd);
638
+ if (o.addToggle) {
639
+ $shcell.find('.toggle')[0].checked = chkd;
640
+ }
641
+ }
642
+ };
643
+ $number.remove();
644
+
645
+ if (numberSupported) {
646
+ l = o.addToggle ? '<div class="button"><input id="html5button' + indx + '" type="checkbox" class="toggle" /><label for="html5button' + indx + '"></label></div>' : '';
647
+ }
648
+
649
+ if (o.compareOptions) {
650
+ l = '<select class="compare">';
651
+ for(var myOption in o.compareOptions) {
652
+ l += '<option value="' + myOption + '"';
653
+ if (myOption === o.compare)
654
+ l += ' selected="selected"';
655
+ l += '>' + myOption + '</option>';
656
+ }
657
+ l += '</select>';
658
+ $cell.append(l)
659
+ .find('.compare')
660
+ .bind('change', function(){
661
+ updateCompare($(this).val());
662
+ });
663
+ } else {
664
+ if (l)
665
+ $cell.append(l);
666
+ }
667
+
668
+ if (numberSupported) {
669
+ t = '<input class="number" type="number" min="' + o.min + '" max="' + o.max + '" value="' +
670
+ o.value + '" step="' + o.step + '" />';
671
+ // add HTML5 number (spinner)
672
+ $cell
673
+ .append(t + '<input type="hidden" />')
674
+ .find('.toggle, .number').bind('change', function(){
675
+ updateNumber( $cell.find('.number').val() );
676
+ })
677
+ .closest('thead').find('th[data-column=' + indx + ']')
678
+ .addClass('filter-parsed') // get exact numbers from column
679
+ // on reset
680
+ .closest('table').bind('filterReset', function(){
681
+ // turn off the toggle checkbox
682
+ if (o.addToggle) {
683
+ $cell.find('.toggle')[0].checked = false;
684
+ if ($shcell.length) {
685
+ $shcell.find('.toggle')[0].checked = false;
686
+ }
687
+ }
688
+ updateNumber( $cell.find('.number').val() );
689
+ });
690
+
691
+ // hidden filter update (.tsfilter) namespace trigger by filter widget
692
+ // FIXME TheSin, Not sure why but this breaks updates
693
+ // Commenting out till it's fixed.
694
+ //$cell.find('input[type=hidden]').bind('change.tsfilter', function(){
695
+ // updateNumber( this.value );
696
+ //});
697
+
698
+ // has sticky headers?
699
+ c.$table.bind('stickyHeadersInit', function(){
700
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
701
+ if (o.compareOptions) {
702
+ $shcell.append(l)
703
+ .find('.compare')
704
+ .bind('change', function(){
705
+ updateCompare($(this).val());
706
+ });
707
+ } else {
708
+ $shcell.append(l);
709
+ }
710
+
711
+ $shcell
712
+ .append(t)
713
+ .find('.toggle, .number').bind('change', function(){
714
+ updateNumber( $shcell.find('.number').val() );
715
+ });
716
+ updateNumber( $cell.find('.number').val() );
717
+ });
718
+
719
+ updateNumber( $cell.find('.number').val() );
720
+
721
+ }
722
+
723
+ return numberSupported ? $cell.find('input[type="hidden"]') : $('<input type="search">');
724
+ },
725
+
726
+ /**********************\
727
+ HTML5 range slider
728
+ \**********************/
729
+ html5Range : function($cell, indx, def5Range) {
730
+ var t, o = $.extend({
731
+ value : 0,
732
+ min : 0,
733
+ max : 100,
734
+ step : 1,
735
+ delayed : true,
736
+ valueToHeader : true,
737
+ exactMatch : true,
738
+ compare : '',
739
+ allText : 'all',
740
+ skipTest : false
741
+ }, def5Range),
742
+
743
+ // test browser for HTML5 range support
744
+ $range = $('<input type="range" style="visibility:hidden;" value="test">').appendTo($cell),
745
+ // test if HTML5 range is supported - from Modernizr (but I left out the method to detect in Safari 2-4)
746
+ // see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/inputtypes.js
747
+ rangeSupported = o.skipTest || $range.attr('type') === 'range' && $range.val() !== 'test',
748
+ $shcell = [],
749
+ c = $cell.closest('table')[0].config,
750
+
751
+ updateRange = function(v, delayed){
752
+ /*jshint eqeqeq:false */
753
+ v = (v + '').replace(/[<>=]/g,'') || o.min; // hidden input changes may include compare symbols
754
+ var t = ' (' + (o.compare ? o.compare + v : v == o.min ? o.allText : v) + ')';
755
+ $cell.find('input[type=hidden]')
756
+ // add equal to the beginning, so we filter exact numbers
757
+ .val( ( o.compare ? o.compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) ) )
758
+ //( val == o.min ? '' : val + (o.exactMatch ? '=' : ''))
759
+ .trigger('search', delayed ? delayed : o.delayed).end()
760
+ .find('.range').val(v);
761
+ // or add current value to the header cell, if desired
762
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t);
763
+ // update sticky header cell
764
+ if ($shcell.length) {
765
+ $shcell.find('.range').val(v);
766
+ $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t);
767
+ }
768
+ };
769
+ $range.remove();
770
+
771
+ if (rangeSupported) {
772
+ // add HTML5 range
773
+ $cell
774
+ .html('<input type="hidden"><input class="range" type="range" min="' + o.min + '" max="' + o.max + '" value="' + o.value + '" />')
775
+ .closest('thead').find('th[data-column=' + indx + ']')
776
+ .addClass('filter-parsed') // get exact numbers from column
777
+ // add span to header for the current slider value
778
+ .find('.tablesorter-header-inner').append('<span class="curvalue" />');
779
+
780
+ $cell.find('.range').bind('change', function(){
781
+ updateRange( this.value );
782
+ });
783
+
784
+ // hidden filter update (.tsfilter) namespace trigger by filter widget
785
+ $cell.find('input[type=hidden]').bind('change.tsfilter', function(){
786
+ /*jshint eqeqeq:false */
787
+ var v = this.value;
788
+ if (v !== this.lastValue) {
789
+ this.lastValue = ( o.compare ? o.compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) );
790
+ this.value = this.lastValue;
791
+ updateRange( v );
792
+ }
793
+ });
794
+
795
+ // has sticky headers?
796
+ c.$table.bind('stickyHeadersInit', function(){
797
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
798
+ $shcell
799
+ .html('<input class="range" type="range" min="' + o.min + '" max="' + o.max + '" value="' + o.value + '" />')
800
+ .find('.range').bind('change', function(){
801
+ updateRange( $shcell.find('.range').val() );
802
+ });
803
+ updateRange( $cell.find('.range').val() );
804
+ });
805
+
806
+ // on reset
807
+ $cell.closest('table').bind('filterReset', function(){
808
+ // just turn off the colorpicker
809
+ updateRange(o.value);
810
+ });
811
+
812
+ updateRange( $cell.find('.range').val() );
813
+
814
+ }
815
+
816
+ return rangeSupported ? $cell.find('input[type="hidden"]') : $('<input type="search">');
817
+ },
818
+
819
+ /**********************\
820
+ HTML5 Color picker
821
+ \**********************/
822
+ html5Color: function($cell, indx, defColor) {
823
+ var t, o = $.extend({
824
+ value : '#000000',
825
+ disabled : false,
826
+ addToggle : true,
827
+ exactMatch : true,
828
+ valueToHeader : false,
829
+ skipTest : false
830
+ }, defColor),
831
+ // Add a hidden input to hold the range values
832
+ $color = $('<input type="color" style="visibility:hidden;" value="test">').appendTo($cell),
833
+ // test if HTML5 color is supported - from Modernizr
834
+ colorSupported = o.skipTest || $color.attr('type') === 'color' && $color.val() !== 'test',
835
+ $shcell = [],
836
+ c = $cell.closest('table')[0].config,
837
+
838
+ updateColor = function(v){
839
+ v = v || o.value;
840
+ var chkd = true,
841
+ t = ' (' + v + ')';
842
+ if (o.addToggle) {
843
+ chkd = $cell.find('.toggle').is(':checked');
844
+ }
845
+ if ($cell.find('.colorpicker').length) {
846
+ $cell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd);
847
+ }
848
+
849
+ $cell.find('input[type=hidden]')
850
+ .val( chkd ? v + (o.exactMatch ? '=' : '') : '' )
851
+ .trigger('search');
852
+ if (o.valueToHeader) {
853
+ // add current color to the header cell
854
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t);
855
+ } else {
856
+ // current color to span in cell
857
+ $cell.find('.currentColor').html(t);
858
+ }
859
+
860
+ // update sticky header cell
861
+ if ($shcell.length) {
862
+ $shcell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd);
863
+ if (o.addToggle) {
864
+ $shcell.find('.toggle')[0].checked = chkd;
865
+ }
866
+ if (o.valueToHeader) {
867
+ // add current color to the header cell
868
+ $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t);
869
+ } else {
870
+ // current color to span in cell
871
+ $shcell.find('.currentColor').html(t);
872
+ }
873
+ }
874
+ };
875
+ $color.remove();
876
+
877
+ if (colorSupported) {
878
+ // add HTML5 color picker
879
+ t = '<div class="color-controls-wrapper">';
880
+ t += o.addToggle ? '<div class="button"><input id="colorbutton' + indx + '" type="checkbox" class="toggle" /><label for="colorbutton' + indx + '"></label></div>' : '';
881
+ t += '<input type="hidden"><input class="colorpicker" type="color" />';
882
+ t += (o.valueToHeader ? '' : '<span class="currentColor">(#000000)</span>') + '</div>';
883
+ $cell.html(t);
884
+
885
+ // add span to header for the current color value - only works if the line in the updateColor() function is also un-commented out
886
+ if (o.valueToHeader) {
887
+ $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append('<span class="curcolor" />');
888
+ }
889
+
890
+ $cell.find('.toggle, .colorpicker').bind('change', function(){
891
+ updateColor( $cell.find('.colorpicker').val() );
892
+ });
893
+
894
+ // hidden filter update (.tsfilter) namespace trigger by filter widget
895
+ $cell.find('input[type=hidden]').bind('change.tsfilter', function(){
896
+ updateColor( this.value );
897
+ });
898
+
899
+ // on reset
900
+ $cell.closest('table').bind('filterReset', function(){
901
+ // just turn off the colorpicker
902
+ $cell.find('.toggle')[0].checked = false;
903
+ updateColor( $cell.find('.colorpicker').val() );
904
+ });
905
+
906
+ // has sticky headers?
907
+ c.$table.bind('stickyHeadersInit', function(){
908
+ $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx);
909
+ $shcell
910
+ .html(t)
911
+ .find('.toggle, .colorpicker').bind('change', function(){
912
+ updateColor( $shcell.find('.colorpicker').val() );
913
+ });
914
+ updateColor( $shcell.find('.colorpicker').val() );
915
+ });
916
+
917
+ updateColor( o.value );
918
+ }
919
+ return colorSupported ? $cell.find('input[type="hidden"]') : $('<input type="search">');
920
+ }
921
+
922
+ };
923
+
924
+ })(jQuery);