jquery-tablesorter 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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);