jquery-tablesorter 1.14.1 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/jquery-tablesorter/version.rb +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter.js +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter/addons/pager/jquery.tablesorter.pager.js +5 -9
- data/vendor/assets/javascripts/jquery-tablesorter/extras/jquery.dragtable.mod.js +1 -4
- data/vendor/assets/javascripts/jquery-tablesorter/{jquery.metadata.js → extras/jquery.metadata.js} +1 -0
- data/vendor/assets/javascripts/jquery-tablesorter/extras/jquery.quicksearch.js +8 -4
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +116 -107
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets.js +232 -171
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-file-type.js +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-input-select.js +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-chart.js +2 -3
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-columns.js +78 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-cssStickyHeaders.js +14 -12
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-editable.js +4 -4
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-filter-formatter-html5.js +429 -0
- data/vendor/assets/javascripts/jquery-tablesorter/{jquery.tablesorter.widgets-filter-formatter.js → widgets/widget-filter-formatter-jui.js} +1 -381
- data/vendor/assets/javascripts/jquery-tablesorter/{jquery.tablesorter.widgets-filter-formatter-select2.js → widgets/widget-filter-formatter-select2.js} +0 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-filter.js +1307 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-formatter.js +3 -3
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-grouping.js +4 -4
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-math.js +3 -3
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-pager.js +4 -8
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-resizable.js +176 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-saveSort.js +68 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-staticRow.js +3 -3
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-stickyHeaders.js +269 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-storage.js +76 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-uitheme.js +184 -0
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.black-ice.css +1 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.blue.css +1 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.dark.css +1 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.default.css +1 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.dropbox.css +1 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.green.css +1 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.grey.css +1 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.ice.css +1 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.jui.css +1 -1
- data/vendor/assets/stylesheets/jquery-tablesorter/theme.metro-dark.css +1 -1
- metadata +15 -7
@@ -10,11 +10,11 @@
|
|
10
10
|
|
11
11
|
ts.formatter = {
|
12
12
|
init : function( c ) {
|
13
|
-
var events =
|
13
|
+
var events = c.widgetOptions.formatter_event +
|
14
14
|
' pagerComplete updateComplete '.split(' ').join('.tsformatter ');
|
15
15
|
c.$table
|
16
|
-
.off(
|
17
|
-
.on(
|
16
|
+
.off( events.replace(/\s+/g, ' ') )
|
17
|
+
.on( events, function() {
|
18
18
|
ts.formatter.setup( c );
|
19
19
|
});
|
20
20
|
ts.formatter.setup( c );
|
@@ -54,7 +54,7 @@ ts.grouping = {
|
|
54
54
|
|
55
55
|
update : function(table, c, wo){
|
56
56
|
if ($.isEmptyObject(c.cache)) { return; }
|
57
|
-
var rowIndex, tbodyIndex, currentGroup, $rows, groupClass, grouping,
|
57
|
+
var rowIndex, tbodyIndex, currentGroup, $rows, groupClass, grouping, norm_rows, saveName, direction,
|
58
58
|
lang = wo.grouping_language,
|
59
59
|
group = '',
|
60
60
|
savedGroup = false,
|
@@ -89,15 +89,15 @@ ts.grouping = {
|
|
89
89
|
}
|
90
90
|
}
|
91
91
|
for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++) {
|
92
|
-
|
92
|
+
norm_rows = c.cache[tbodyIndex].normalized;
|
93
93
|
group = ''; // clear grouping across tbodies
|
94
94
|
$rows = c.$tbodies.eq(tbodyIndex).children('tr').not('.' + c.cssChildRow);
|
95
95
|
for (rowIndex = 0; rowIndex < $rows.length; rowIndex++) {
|
96
96
|
if ( $rows.eq(rowIndex).is(':visible') ) {
|
97
97
|
// fixes #438
|
98
98
|
if (ts.grouping.types[grouping[1]]) {
|
99
|
-
currentGroup =
|
100
|
-
ts.grouping.types[grouping[1]]( c, c.$headers.filter('[data-column="' + column + '"]:last'),
|
99
|
+
currentGroup = norm_rows[rowIndex] ?
|
100
|
+
ts.grouping.types[grouping[1]]( c, c.$headers.filter('[data-column="' + column + '"]:last'), norm_rows[rowIndex][column], /date/.test(groupClass) ?
|
101
101
|
grouping[2] : parseInt(grouping[2] || 1, 10) || 1, group, lang ) : currentGroup;
|
102
102
|
if (group !== currentGroup) {
|
103
103
|
group = currentGroup;
|
@@ -393,8 +393,8 @@
|
|
393
393
|
},
|
394
394
|
init : function(table, thisWidget, c, wo){
|
395
395
|
c.$table
|
396
|
-
.off(
|
397
|
-
.on(
|
396
|
+
.off( (math.events + ' updateComplete.tsmath ' + wo.math_event).replace(/\s+/g, ' ') )
|
397
|
+
.on(math.events + ' ' + wo.math_event, function(e){
|
398
398
|
var init = e.type === 'tablesorter-initialized';
|
399
399
|
if (e.type === 'updateAll') {
|
400
400
|
// redo data-column indexes in case columns were rearranged
|
@@ -415,7 +415,7 @@
|
|
415
415
|
remove: function(table, c, wo, refreshing){
|
416
416
|
if (refreshing) { return; }
|
417
417
|
$(table)
|
418
|
-
.off(
|
418
|
+
.off( (math.events + ' updateComplete.tsmath ' + wo.math_event).replace(/\s+/g, ' ') )
|
419
419
|
.find('[data-' + wo.math_data + ']').empty();
|
420
420
|
}
|
421
421
|
});
|
@@ -167,7 +167,7 @@ tsp = ts.pager = {
|
|
167
167
|
p.initializing = true;
|
168
168
|
if (wo.pager_savePages && ts.storage) {
|
169
169
|
t = ts.storage(table, wo.pager_storageKey) || {}; // fixes #387
|
170
|
-
p.page = ( isNaN(t.page) ? p.page : t.page ) || p.setPage ||
|
170
|
+
p.page = ( isNaN(t.page) ? p.page : t.page ) || p.setPage || 0;
|
171
171
|
p.size = ( isNaN(t.size) ? p.size : t.size ) || p.setSize || 10;
|
172
172
|
$.data(table, 'pagerLastSize', p.size);
|
173
173
|
}
|
@@ -371,8 +371,7 @@ tsp = ts.pager = {
|
|
371
371
|
},
|
372
372
|
|
373
373
|
calcFilters: function(table, c) {
|
374
|
-
var
|
375
|
-
wo = c.widgetOptions,
|
374
|
+
var wo = c.widgetOptions,
|
376
375
|
p = c.pager,
|
377
376
|
hasFilters = c.$table.hasClass('hasFilters');
|
378
377
|
if (hasFilters && !wo.pager_ajaxUrl) {
|
@@ -380,10 +379,8 @@ tsp = ts.pager = {
|
|
380
379
|
// delayInit: true so nothing is in the cache
|
381
380
|
p.filteredRows = p.totalRows = c.$tbodies.eq(0).children('tr').not( wo.pager_countChildRows ? '' : '.' + c.cssChildRow ).length;
|
382
381
|
} else {
|
383
|
-
// just in case the pager tbody isn't the first tbody
|
384
|
-
tbodyIndex = c.$table.children('tbody').index( c.$tbodies.eq(0) );
|
385
382
|
p.filteredRows = 0;
|
386
|
-
$.each(c.cache[
|
383
|
+
$.each(c.cache[0].normalized, function(i, el) {
|
387
384
|
p.filteredRows += p.regexRows.test(el[c.columns].$row[0].className) ? 0 : 1;
|
388
385
|
});
|
389
386
|
}
|
@@ -898,8 +895,7 @@ tsp = ts.pager = {
|
|
898
895
|
if ( !$.isEmptyObject(table.config.cache) ) {
|
899
896
|
var i,
|
900
897
|
rows = [],
|
901
|
-
|
902
|
-
n = table.config.cache[tbodyIndex].normalized;
|
898
|
+
n = table.config.cache[0].normalized;
|
903
899
|
p.totalRows = n.length;
|
904
900
|
for (i = 0; i < p.totalRows; i++) {
|
905
901
|
rows.push(n[i][c.columns].$row);
|
@@ -0,0 +1,176 @@
|
|
1
|
+
/*! Widget: resizable */
|
2
|
+
;(function ($, window) {
|
3
|
+
'use strict';
|
4
|
+
var ts = $.tablesorter = $.tablesorter || {};
|
5
|
+
|
6
|
+
$.extend(ts.css, {
|
7
|
+
resizer : 'tablesorter-resizer' // resizable
|
8
|
+
});
|
9
|
+
|
10
|
+
// this widget saves the column widths if
|
11
|
+
// $.tablesorter.storage function is included
|
12
|
+
// **************************
|
13
|
+
ts.addWidget({
|
14
|
+
id: "resizable",
|
15
|
+
priority: 40,
|
16
|
+
options: {
|
17
|
+
resizable : true,
|
18
|
+
resizable_addLastColumn : false,
|
19
|
+
resizable_widths : [],
|
20
|
+
resizable_throttle : false // set to true (5ms) or any number 0-10 range
|
21
|
+
},
|
22
|
+
format: function(table, c, wo) {
|
23
|
+
if (c.$table.hasClass('hasResizable')) { return; }
|
24
|
+
c.$table.addClass('hasResizable');
|
25
|
+
ts.resizableReset(table, true); // set default widths
|
26
|
+
var $rows, $columns, $column, column, timer,
|
27
|
+
storedSizes = {},
|
28
|
+
$table = c.$table,
|
29
|
+
$wrap = $table.parent(),
|
30
|
+
overflow = $table.parent().css('overflow') === 'auto',
|
31
|
+
mouseXPosition = 0,
|
32
|
+
$target = null,
|
33
|
+
$next = null,
|
34
|
+
fullWidth = Math.abs($table.parent().width() - $table.width()) < 20,
|
35
|
+
mouseMove = function(event){
|
36
|
+
if (mouseXPosition === 0 || !$target) { return; }
|
37
|
+
// resize columns
|
38
|
+
var leftEdge = event.pageX - mouseXPosition,
|
39
|
+
targetWidth = $target.width();
|
40
|
+
$target.width( targetWidth + leftEdge );
|
41
|
+
if ($target.width() !== targetWidth && fullWidth) {
|
42
|
+
$next.width( $next.width() - leftEdge );
|
43
|
+
} else if (overflow) {
|
44
|
+
$table.width(function(i, w){
|
45
|
+
return w + leftEdge;
|
46
|
+
});
|
47
|
+
if (!$next.length) {
|
48
|
+
// if expanding right-most column, scroll the wrapper
|
49
|
+
$wrap[0].scrollLeft = $table.width();
|
50
|
+
}
|
51
|
+
}
|
52
|
+
mouseXPosition = event.pageX;
|
53
|
+
},
|
54
|
+
stopResize = function() {
|
55
|
+
if (ts.storage && $target && $next) {
|
56
|
+
storedSizes = {};
|
57
|
+
storedSizes[$target.index()] = $target.width();
|
58
|
+
storedSizes[$next.index()] = $next.width();
|
59
|
+
$target.width( storedSizes[$target.index()] );
|
60
|
+
$next.width( storedSizes[$next.index()] );
|
61
|
+
if (wo.resizable !== false) {
|
62
|
+
// save all column widths
|
63
|
+
ts.storage(table, 'tablesorter-resizable', c.$headers.map(function(){ return $(this).width(); }).get() );
|
64
|
+
}
|
65
|
+
}
|
66
|
+
mouseXPosition = 0;
|
67
|
+
$target = $next = null;
|
68
|
+
$(window).trigger('resize'); // will update stickyHeaders, just in case
|
69
|
+
};
|
70
|
+
storedSizes = (ts.storage && wo.resizable !== false) ? ts.storage(table, 'tablesorter-resizable') : {};
|
71
|
+
// process only if table ID or url match
|
72
|
+
if (storedSizes) {
|
73
|
+
for (column in storedSizes) {
|
74
|
+
if (!isNaN(column) && column < c.$headers.length) {
|
75
|
+
c.$headers.eq(column).width(storedSizes[column]); // set saved resizable widths
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
$rows = $table.children('thead:first').children('tr');
|
80
|
+
// add resizable-false class name to headers (across rows as needed)
|
81
|
+
$rows.children().each(function() {
|
82
|
+
var canResize,
|
83
|
+
$column = $(this);
|
84
|
+
column = $column.attr('data-column');
|
85
|
+
canResize = ts.getData( $column, ts.getColumnData( table, c.headers, column ), 'resizable') === "false";
|
86
|
+
$rows.children().filter('[data-column="' + column + '"]')[canResize ? 'addClass' : 'removeClass']('resizable-false');
|
87
|
+
});
|
88
|
+
// add wrapper inside each cell to allow for positioning of the resizable target block
|
89
|
+
$rows.each(function() {
|
90
|
+
$column = $(this).children().not('.resizable-false');
|
91
|
+
if (!$(this).find('.' + ts.css.wrapper).length) {
|
92
|
+
// Firefox needs this inner div to position the resizer correctly
|
93
|
+
$column.wrapInner('<div class="' + ts.css.wrapper + '" style="position:relative;height:100%;width:100%"></div>');
|
94
|
+
}
|
95
|
+
// don't include the last column of the row
|
96
|
+
if (!wo.resizable_addLastColumn) { $column = $column.slice(0,-1); }
|
97
|
+
$columns = $columns ? $columns.add($column) : $column;
|
98
|
+
});
|
99
|
+
$columns
|
100
|
+
.each(function() {
|
101
|
+
var $column = $(this),
|
102
|
+
padding = parseInt($column.css('padding-right'), 10) + 10; // 10 is 1/2 of the 20px wide resizer
|
103
|
+
$column
|
104
|
+
.find('.' + ts.css.wrapper)
|
105
|
+
.append('<div class="' + ts.css.resizer + '" style="cursor:w-resize;position:absolute;z-index:1;right:-' +
|
106
|
+
padding + 'px;top:0;height:100%;width:20px;"></div>');
|
107
|
+
})
|
108
|
+
.find('.' + ts.css.resizer)
|
109
|
+
.bind('mousedown', function(event) {
|
110
|
+
// save header cell and mouse position
|
111
|
+
$target = $(event.target).closest('th');
|
112
|
+
var $header = c.$headers.filter('[data-column="' + $target.attr('data-column') + '"]');
|
113
|
+
if ($header.length > 1) { $target = $target.add($header); }
|
114
|
+
// if table is not as wide as it's parent, then resize the table
|
115
|
+
$next = event.shiftKey ? $target.parent().find('th').not('.resizable-false').filter(':last') : $target.nextAll(':not(.resizable-false)').eq(0);
|
116
|
+
mouseXPosition = event.pageX;
|
117
|
+
});
|
118
|
+
$(document)
|
119
|
+
.bind('mousemove.tsresize', function(event) {
|
120
|
+
// ignore mousemove if no mousedown
|
121
|
+
if (mouseXPosition === 0 || !$target) { return; }
|
122
|
+
if (wo.resizable_throttle) {
|
123
|
+
clearTimeout(timer);
|
124
|
+
timer = setTimeout(function(){
|
125
|
+
mouseMove(event);
|
126
|
+
}, isNaN(wo.resizable_throttle) ? 5 : wo.resizable_throttle );
|
127
|
+
} else {
|
128
|
+
mouseMove(event);
|
129
|
+
}
|
130
|
+
})
|
131
|
+
.bind('mouseup.tsresize', function() {
|
132
|
+
stopResize();
|
133
|
+
});
|
134
|
+
|
135
|
+
// right click to reset columns to default widths
|
136
|
+
$table.find('thead:first').bind('contextmenu.tsresize', function() {
|
137
|
+
ts.resizableReset(table);
|
138
|
+
// $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset
|
139
|
+
var allowClick = $.isEmptyObject ? $.isEmptyObject(storedSizes) : true;
|
140
|
+
storedSizes = {};
|
141
|
+
return allowClick;
|
142
|
+
});
|
143
|
+
},
|
144
|
+
remove: function(table, c) {
|
145
|
+
c.$table
|
146
|
+
.removeClass('hasResizable')
|
147
|
+
.children('thead')
|
148
|
+
.unbind('mouseup.tsresize mouseleave.tsresize contextmenu.tsresize')
|
149
|
+
.children('tr').children()
|
150
|
+
.unbind('mousemove.tsresize mouseup.tsresize')
|
151
|
+
// don't remove "tablesorter-wrapper" as uitheme uses it too
|
152
|
+
.find('.' + ts.css.resizer).remove();
|
153
|
+
ts.resizableReset(table);
|
154
|
+
}
|
155
|
+
});
|
156
|
+
ts.resizableReset = function(table, nosave) {
|
157
|
+
$(table).each(function(){
|
158
|
+
var $t,
|
159
|
+
c = this.config,
|
160
|
+
wo = c && c.widgetOptions;
|
161
|
+
if (table && c) {
|
162
|
+
c.$headers.each(function(i){
|
163
|
+
$t = $(this);
|
164
|
+
if (wo.resizable_widths && wo.resizable_widths[i]) {
|
165
|
+
$t.css('width', wo.resizable_widths[i]);
|
166
|
+
} else if (!$t.hasClass('resizable-false')) {
|
167
|
+
// don't clear the width of any column that is not resizable
|
168
|
+
$t.css('width','');
|
169
|
+
}
|
170
|
+
});
|
171
|
+
if (ts.storage && !nosave) { ts.storage(this, 'tablesorter-resizable', {}); }
|
172
|
+
}
|
173
|
+
});
|
174
|
+
};
|
175
|
+
|
176
|
+
})(jQuery, window);
|
@@ -0,0 +1,68 @@
|
|
1
|
+
/*! Widget: saveSort */
|
2
|
+
;(function ($) {
|
3
|
+
'use strict';
|
4
|
+
var ts = $.tablesorter = $.tablesorter || {};
|
5
|
+
|
6
|
+
// this widget saves the last sort only if the
|
7
|
+
// saveSort widget option is true AND the
|
8
|
+
// $.tablesorter.storage function is included
|
9
|
+
// **************************
|
10
|
+
ts.addWidget({
|
11
|
+
id: 'saveSort',
|
12
|
+
priority: 20,
|
13
|
+
options: {
|
14
|
+
saveSort : true
|
15
|
+
},
|
16
|
+
init: function(table, thisWidget, c, wo) {
|
17
|
+
// run widget format before all other widgets are applied to the table
|
18
|
+
thisWidget.format(table, c, wo, true);
|
19
|
+
},
|
20
|
+
format: function(table, c, wo, init) {
|
21
|
+
var stored, time,
|
22
|
+
$table = c.$table,
|
23
|
+
saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true
|
24
|
+
sortList = { "sortList" : c.sortList };
|
25
|
+
if (c.debug) {
|
26
|
+
time = new Date();
|
27
|
+
}
|
28
|
+
if ($table.hasClass('hasSaveSort')) {
|
29
|
+
if (saveSort && table.hasInitialized && ts.storage) {
|
30
|
+
ts.storage( table, 'tablesorter-savesort', sortList );
|
31
|
+
if (c.debug) {
|
32
|
+
ts.benchmark('saveSort widget: Saving last sort: ' + c.sortList, time);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
} else {
|
36
|
+
// set table sort on initial run of the widget
|
37
|
+
$table.addClass('hasSaveSort');
|
38
|
+
sortList = '';
|
39
|
+
// get data
|
40
|
+
if (ts.storage) {
|
41
|
+
stored = ts.storage( table, 'tablesorter-savesort' );
|
42
|
+
sortList = (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : '';
|
43
|
+
if (c.debug) {
|
44
|
+
ts.benchmark('saveSort: Last sort loaded: "' + sortList + '"', time);
|
45
|
+
}
|
46
|
+
$table.bind('saveSortReset', function(event) {
|
47
|
+
event.stopPropagation();
|
48
|
+
ts.storage( table, 'tablesorter-savesort', '' );
|
49
|
+
});
|
50
|
+
}
|
51
|
+
// init is true when widget init is run, this will run this widget before all other widgets have initialized
|
52
|
+
// this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice.
|
53
|
+
if (init && sortList && sortList.length > 0) {
|
54
|
+
c.sortList = sortList;
|
55
|
+
} else if (table.hasInitialized && sortList && sortList.length > 0) {
|
56
|
+
// update sort change
|
57
|
+
$table.trigger('sorton', [sortList]);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
},
|
61
|
+
remove: function(table, c) {
|
62
|
+
c.$table.removeClass('hasSaveSort');
|
63
|
+
// clear storage
|
64
|
+
if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); }
|
65
|
+
}
|
66
|
+
});
|
67
|
+
|
68
|
+
})(jQuery);
|
@@ -59,8 +59,8 @@ ts.addWidget({
|
|
59
59
|
addIndexes(table);
|
60
60
|
// refresh static rows after updates
|
61
61
|
c.$table
|
62
|
-
.unbind(
|
63
|
-
.bind(
|
62
|
+
.unbind( ('updateComplete.tsstaticrows ' + wo.staticRow_event).replace(/\s+/g, ' ') )
|
63
|
+
.bind('updateComplete.tsstaticrows ' + wo.staticRow_event, function(){
|
64
64
|
addIndexes(table);
|
65
65
|
c.$table.trigger('applyWidgets');
|
66
66
|
});
|
@@ -113,7 +113,7 @@ ts.addWidget({
|
|
113
113
|
},
|
114
114
|
|
115
115
|
remove : function(table, c, wo){
|
116
|
-
c.$table.unbind(
|
116
|
+
c.$table.unbind( ('updateComplete.tsstaticrows ' + wo.staticRow_event).replace(/\s+/g, ' ') );
|
117
117
|
}
|
118
118
|
|
119
119
|
});
|
@@ -0,0 +1,269 @@
|
|
1
|
+
/*! Widget: stickyHeaders */
|
2
|
+
;(function ($, window) {
|
3
|
+
'use strict';
|
4
|
+
var ts = $.tablesorter = $.tablesorter || {};
|
5
|
+
|
6
|
+
$.extend(ts.css, {
|
7
|
+
sticky : 'tablesorter-stickyHeader', // stickyHeader
|
8
|
+
stickyVis : 'tablesorter-sticky-visible',
|
9
|
+
stickyWrap: 'tablesorter-sticky-wrapper'
|
10
|
+
});
|
11
|
+
|
12
|
+
// Add a resize event to table headers
|
13
|
+
ts.addHeaderResizeEvent = function(table, disable, settings) {
|
14
|
+
table = $(table)[0]; // make sure we're using a dom element
|
15
|
+
var headers,
|
16
|
+
defaults = {
|
17
|
+
timer : 250
|
18
|
+
},
|
19
|
+
options = $.extend({}, defaults, settings),
|
20
|
+
c = table.config,
|
21
|
+
wo = c.widgetOptions,
|
22
|
+
checkSizes = function(triggerEvent) {
|
23
|
+
wo.resize_flag = true;
|
24
|
+
headers = [];
|
25
|
+
c.$headers.each(function() {
|
26
|
+
var $header = $(this),
|
27
|
+
sizes = $header.data('savedSizes') || [0,0], // fixes #394
|
28
|
+
width = this.offsetWidth,
|
29
|
+
height = this.offsetHeight;
|
30
|
+
if (width !== sizes[0] || height !== sizes[1]) {
|
31
|
+
$header.data('savedSizes', [ width, height ]);
|
32
|
+
headers.push(this);
|
33
|
+
}
|
34
|
+
});
|
35
|
+
if (headers.length && triggerEvent !== false) {
|
36
|
+
c.$table.trigger('resize', [ headers ]);
|
37
|
+
}
|
38
|
+
wo.resize_flag = false;
|
39
|
+
};
|
40
|
+
checkSizes(false);
|
41
|
+
clearInterval(wo.resize_timer);
|
42
|
+
if (disable) {
|
43
|
+
wo.resize_flag = false;
|
44
|
+
return false;
|
45
|
+
}
|
46
|
+
wo.resize_timer = setInterval(function() {
|
47
|
+
if (wo.resize_flag) { return; }
|
48
|
+
checkSizes();
|
49
|
+
}, options.timer);
|
50
|
+
};
|
51
|
+
|
52
|
+
// Sticky headers based on this awesome article:
|
53
|
+
// http://css-tricks.com/13465-persistent-headers/
|
54
|
+
// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech
|
55
|
+
// **************************
|
56
|
+
ts.addWidget({
|
57
|
+
id: "stickyHeaders",
|
58
|
+
priority: 60, // sticky widget must be initialized after the filter widget!
|
59
|
+
options: {
|
60
|
+
stickyHeaders : '', // extra class name added to the sticky header row
|
61
|
+
stickyHeaders_attachTo : null, // jQuery selector or object to attach sticky header to
|
62
|
+
stickyHeaders_xScroll : null, // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
|
63
|
+
stickyHeaders_yScroll : null, // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
|
64
|
+
stickyHeaders_offset : 0, // number or jquery selector targeting the position:fixed element
|
65
|
+
stickyHeaders_filteredToTop: true, // scroll table top into view after filtering
|
66
|
+
stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists
|
67
|
+
stickyHeaders_addResizeEvent : true, // trigger "resize" event on headers
|
68
|
+
stickyHeaders_includeCaption : true, // if false and a caption exist, it won't be included in the sticky header
|
69
|
+
stickyHeaders_zIndex : 2 // The zIndex of the stickyHeaders, allows the user to adjust this to their needs
|
70
|
+
},
|
71
|
+
format: function(table, c, wo) {
|
72
|
+
// filter widget doesn't initialize on an empty table. Fixes #449
|
73
|
+
if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) {
|
74
|
+
return;
|
75
|
+
}
|
76
|
+
var $table = c.$table,
|
77
|
+
$attach = $(wo.stickyHeaders_attachTo),
|
78
|
+
namespace = c.namespace + 'stickyheaders ',
|
79
|
+
// element to watch for the scroll event
|
80
|
+
$yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window),
|
81
|
+
$xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window),
|
82
|
+
$thead = $table.children('thead:first'),
|
83
|
+
$header = $thead.children('tr').not('.sticky-false').children(),
|
84
|
+
$tfoot = $table.children('tfoot'),
|
85
|
+
$stickyOffset = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : '',
|
86
|
+
stickyOffset = $attach.length ? 0 : $stickyOffset.length ?
|
87
|
+
$stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0,
|
88
|
+
// is this table nested? If so, find parent sticky header wrapper (div, not table)
|
89
|
+
$nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ?
|
90
|
+
$table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [],
|
91
|
+
nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0,
|
92
|
+
// clone table, then wrap to make sticky header
|
93
|
+
$stickyTable = wo.$sticky = $table.clone()
|
94
|
+
.addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders)
|
95
|
+
.wrap('<div class="' + ts.css.stickyWrap + '">'),
|
96
|
+
$stickyWrap = $stickyTable.parent().css({
|
97
|
+
position : $attach.length ? 'absolute' : 'fixed',
|
98
|
+
padding : parseInt( $stickyTable.parent().parent().css('padding-left'), 10 ),
|
99
|
+
top : stickyOffset + nestedStickyTop,
|
100
|
+
left : 0,
|
101
|
+
visibility : 'hidden',
|
102
|
+
zIndex : wo.stickyHeaders_zIndex || 2
|
103
|
+
}),
|
104
|
+
$stickyThead = $stickyTable.children('thead:first'),
|
105
|
+
$stickyCells,
|
106
|
+
laststate = '',
|
107
|
+
spacing = 0,
|
108
|
+
setWidth = function($orig, $clone){
|
109
|
+
$orig.filter(':visible').each(function(i) {
|
110
|
+
var width, border,
|
111
|
+
$cell = $clone.filter(':visible').eq(i),
|
112
|
+
$this = $(this);
|
113
|
+
// code from https://github.com/jmosbech/StickyTableHeaders
|
114
|
+
if ($this.css('box-sizing') === 'border-box') {
|
115
|
+
width = $this.outerWidth();
|
116
|
+
} else {
|
117
|
+
if ($cell.css('border-collapse') === 'collapse') {
|
118
|
+
if (window.getComputedStyle) {
|
119
|
+
width = parseFloat( window.getComputedStyle(this, null).width );
|
120
|
+
} else {
|
121
|
+
// ie8 only
|
122
|
+
border = parseFloat( $this.css('border-width') );
|
123
|
+
width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border;
|
124
|
+
}
|
125
|
+
} else {
|
126
|
+
width = $this.width();
|
127
|
+
}
|
128
|
+
}
|
129
|
+
$cell.css({
|
130
|
+
'min-width': width,
|
131
|
+
'max-width': width
|
132
|
+
});
|
133
|
+
});
|
134
|
+
},
|
135
|
+
resizeHeader = function() {
|
136
|
+
stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0;
|
137
|
+
spacing = 0;
|
138
|
+
$stickyWrap.css({
|
139
|
+
left : $attach.length ? parseInt($attach.css('padding-left'), 10) || 0 :
|
140
|
+
$table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing,
|
141
|
+
width: $table.outerWidth()
|
142
|
+
});
|
143
|
+
setWidth( $table, $stickyTable );
|
144
|
+
setWidth( $header, $stickyCells );
|
145
|
+
};
|
146
|
+
// save stickyTable element to config
|
147
|
+
// it is also saved to wo.$sticky
|
148
|
+
if (c.$extraTables && c.$extraTables.length) {
|
149
|
+
c.$extraTables.add($stickyTable);
|
150
|
+
} else {
|
151
|
+
c.$extraTables = $stickyTable;
|
152
|
+
}
|
153
|
+
// fix clone ID, if it exists - fixes #271
|
154
|
+
if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.stickyHeaders_cloneId; }
|
155
|
+
// clear out cloned table, except for sticky header
|
156
|
+
// include caption & filter row (fixes #126 & #249) - don't remove cells to get correct cell indexing
|
157
|
+
$stickyTable.find('thead:gt(0), tr.sticky-false').hide();
|
158
|
+
$stickyTable.find('tbody, tfoot').remove();
|
159
|
+
$stickyTable.find('caption').toggle(wo.stickyHeaders_includeCaption);
|
160
|
+
// issue #172 - find td/th in sticky header
|
161
|
+
$stickyCells = $stickyThead.children().children();
|
162
|
+
$stickyTable.css({ height:0, width:0, margin: 0 });
|
163
|
+
// remove resizable block
|
164
|
+
$stickyCells.find('.' + ts.css.resizer).remove();
|
165
|
+
// update sticky header class names to match real header after sorting
|
166
|
+
$table
|
167
|
+
.addClass('hasStickyHeaders')
|
168
|
+
.bind('pagerComplete' + namespace, function() {
|
169
|
+
resizeHeader();
|
170
|
+
});
|
171
|
+
|
172
|
+
ts.bindEvents(table, $stickyThead.children().children('.tablesorter-header'));
|
173
|
+
|
174
|
+
// add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned.
|
175
|
+
$table.after( $stickyWrap );
|
176
|
+
|
177
|
+
// onRenderHeader is defined, we need to do something about it (fixes #641)
|
178
|
+
if (c.onRenderHeader) {
|
179
|
+
$stickyThead.children('tr').children().each(function(index){
|
180
|
+
// send second parameter
|
181
|
+
c.onRenderHeader.apply( $(this), [ index, c, $stickyTable ] );
|
182
|
+
});
|
183
|
+
}
|
184
|
+
|
185
|
+
// make it sticky!
|
186
|
+
$xScroll.add($yScroll)
|
187
|
+
.unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') )
|
188
|
+
.bind('scroll resize '.split(' ').join( namespace ), function(event) {
|
189
|
+
if (!$table.is(':visible')) { return; } // fixes #278
|
190
|
+
// Detect nested tables - fixes #724
|
191
|
+
nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
|
192
|
+
var prefix = 'tablesorter-sticky-',
|
193
|
+
offset = $table.offset(),
|
194
|
+
yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3
|
195
|
+
xWindow = $.isWindow( $xScroll[0] ),
|
196
|
+
// scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
|
197
|
+
scrollTop = ( $attach.length ? ( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
|
198
|
+
tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)),
|
199
|
+
isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
|
200
|
+
cssSettings = { visibility : isVisible };
|
201
|
+
|
202
|
+
if ($attach.length) {
|
203
|
+
cssSettings.top = yWindow ? scrollTop : $attach.scrollTop();
|
204
|
+
}
|
205
|
+
if (xWindow) {
|
206
|
+
// adjust when scrolling horizontally - fixes issue #143
|
207
|
+
cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing;
|
208
|
+
}
|
209
|
+
if ($nestedSticky.length) {
|
210
|
+
cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop;
|
211
|
+
}
|
212
|
+
$stickyWrap
|
213
|
+
.removeClass(prefix + 'visible ' + prefix + 'hidden')
|
214
|
+
.addClass(prefix + isVisible)
|
215
|
+
.css(cssSettings);
|
216
|
+
if (isVisible !== laststate || event.type === 'resize') {
|
217
|
+
// make sure the column widths match
|
218
|
+
resizeHeader();
|
219
|
+
laststate = isVisible;
|
220
|
+
}
|
221
|
+
});
|
222
|
+
if (wo.stickyHeaders_addResizeEvent) {
|
223
|
+
ts.addHeaderResizeEvent(table);
|
224
|
+
}
|
225
|
+
|
226
|
+
// look for filter widget
|
227
|
+
if ($table.hasClass('hasFilters') && wo.filter_columnFilters) {
|
228
|
+
// scroll table into view after filtering, if sticky header is active - #482
|
229
|
+
$table.bind('filterEnd' + namespace, function() {
|
230
|
+
// $(':focus') needs jQuery 1.6+
|
231
|
+
var $td = $(document.activeElement).closest('td'),
|
232
|
+
column = $td.parent().children().index($td);
|
233
|
+
// only scroll if sticky header is active
|
234
|
+
if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) {
|
235
|
+
// scroll to original table (not sticky clone)
|
236
|
+
window.scrollTo(0, $table.position().top);
|
237
|
+
// give same input/select focus; check if c.$filters exists; fixes #594
|
238
|
+
if (column >= 0 && c.$filters) {
|
239
|
+
c.$filters.eq(column).find('a, select, input').filter(':visible').focus();
|
240
|
+
}
|
241
|
+
}
|
242
|
+
});
|
243
|
+
ts.filter.bindSearch( $table, $stickyCells.find('.' + ts.css.filter) );
|
244
|
+
// support hideFilters
|
245
|
+
if (wo.filter_hideFilters) {
|
246
|
+
ts.filter.hideFilters($stickyTable, c);
|
247
|
+
}
|
248
|
+
}
|
249
|
+
|
250
|
+
$table.trigger('stickyHeadersInit');
|
251
|
+
|
252
|
+
},
|
253
|
+
remove: function(table, c, wo) {
|
254
|
+
var namespace = c.namespace + 'stickyheaders ';
|
255
|
+
c.$table
|
256
|
+
.removeClass('hasStickyHeaders')
|
257
|
+
.unbind( ('pagerComplete filterEnd '.split(' ').join(namespace)).replace(/\s+/g, ' ') )
|
258
|
+
.next('.' + ts.css.stickyWrap).remove();
|
259
|
+
if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table
|
260
|
+
$(window)
|
261
|
+
.add(wo.stickyHeaders_xScroll)
|
262
|
+
.add(wo.stickyHeaders_yScroll)
|
263
|
+
.add(wo.stickyHeaders_attachTo)
|
264
|
+
.unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') );
|
265
|
+
ts.addHeaderResizeEvent(table, false);
|
266
|
+
}
|
267
|
+
});
|
268
|
+
|
269
|
+
})(jQuery, window);
|