jquery-tablesorter 1.10.2 → 1.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.markdown +6 -3
- data/Rakefile +30 -16
- data/lib/jquery-tablesorter/version.rb +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter/extras/jquery.quicksearch.js +191 -0
- data/vendor/assets/javascripts/jquery-tablesorter/extras/semver-mod.js +1026 -0
- data/vendor/assets/javascripts/jquery-tablesorter/extras/semver.js +1011 -0
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +2 -2
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date-iso8601.js +34 -0
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date-month.js +33 -0
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date-two-digit-year.js +74 -0
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date-weekday.js +33 -0
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date.js +36 -0
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-feet-inch-fraction.js +63 -0
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-file-type.js +73 -0
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-ignore-articles.js +47 -0
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-input-select.js +86 -0
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-ipv6.js +76 -0
- data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-metric.js +77 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-build-table.js +441 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-columnSelector.js +291 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-cssStickyHeaders.js +67 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-editable.js +89 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-grouping.js +183 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-pager.js +834 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-repeatheaders.js +50 -0
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-scroller.js +241 -0
- metadata +24 -2
@@ -0,0 +1,291 @@
|
|
1
|
+
/* Column Selector/Responsive table widget (beta) for TableSorter 12/17/2013 (v2.15.0)
|
2
|
+
* Requires tablesorter v2.8+ and jQuery 1.7+
|
3
|
+
* by Justin Hallett & Rob Garrison
|
4
|
+
*/
|
5
|
+
/*jshint browser:true, jquery:true, unused:false */
|
6
|
+
/*global jQuery: false */
|
7
|
+
;(function($){
|
8
|
+
"use strict";
|
9
|
+
|
10
|
+
var ts = $.tablesorter,
|
11
|
+
namespace = '.tscolsel',
|
12
|
+
tsColSel = ts.columnSelector = {
|
13
|
+
|
14
|
+
queryAll : '@media only all { [columns] { display: none; } }',
|
15
|
+
queryBreak : '@media screen and (min-width: [size]) { [columns] { display: table-cell; } }',
|
16
|
+
|
17
|
+
init: function(table, c, wo) {
|
18
|
+
var $t, colSel;
|
19
|
+
|
20
|
+
// abort if no input is contained within the layout
|
21
|
+
$t = $(wo.columnSelector_layout);
|
22
|
+
if (!$t.find('input').add( $t.filter('input') ).length) {
|
23
|
+
if (c.debug) {
|
24
|
+
ts.log('*** ERROR: Column Selector aborting, no input found in the layout! ***');
|
25
|
+
}
|
26
|
+
return;
|
27
|
+
}
|
28
|
+
|
29
|
+
// unique table class name
|
30
|
+
c.tableId = 'tablesorter' + new Date().getTime();
|
31
|
+
c.$table.addClass( c.tableId );
|
32
|
+
|
33
|
+
// build column selector/state array
|
34
|
+
colSel = c.selector = { $container : $(wo.columnSelector_container || '<div>') };
|
35
|
+
tsColSel.setupSelector(table, c, wo);
|
36
|
+
|
37
|
+
if (wo.columnSelector_mediaquery) {
|
38
|
+
tsColSel.setupBreakpoints(c, wo);
|
39
|
+
}
|
40
|
+
|
41
|
+
if (colSel.$container.length) {
|
42
|
+
colSel.$style = $('<style></style>').prop('disabled', true).appendTo('head');
|
43
|
+
tsColSel.updateCols(c, wo);
|
44
|
+
}
|
45
|
+
|
46
|
+
},
|
47
|
+
|
48
|
+
setupSelector: function(table, c, wo) {
|
49
|
+
var name,
|
50
|
+
colSel = c.selector,
|
51
|
+
$container = colSel.$container,
|
52
|
+
// get stored column states
|
53
|
+
saved = wo.columnSelector_saveColumns && ts.storage ? ts.storage( table, 'tablesorter-columnSelector' ) : [];
|
54
|
+
|
55
|
+
// initial states
|
56
|
+
colSel.states = [];
|
57
|
+
colSel.$column = [];
|
58
|
+
colSel.$wrapper = [];
|
59
|
+
colSel.$checkbox = [];
|
60
|
+
// populate the selector container
|
61
|
+
c.$table.children('thead').find('tr:first th', table).each(function() {
|
62
|
+
var $this = $(this),
|
63
|
+
// if no data-priority is assigned, default to 1, but don't remove it from the selector list
|
64
|
+
priority = $this.attr(wo.columnSelector_priority) || 1,
|
65
|
+
colId = $this.attr('data-column');
|
66
|
+
|
67
|
+
// if this column not hidable at all
|
68
|
+
// include getData check (includes "columnSelector-false" class, data attribute, etc)
|
69
|
+
if ( isNaN(priority) && priority.length > 0 || ts.getData(this, c.headers[colId], 'columnSelector') == 'false' ||
|
70
|
+
( wo.columnSelector_columns[colId] && wo.columnSelector_columns[colId] === 'disable') ) {
|
71
|
+
return true; // goto next
|
72
|
+
}
|
73
|
+
|
74
|
+
// set default state
|
75
|
+
colSel.states[colId] = saved && typeof(saved[colId]) !== 'undefined' ?
|
76
|
+
saved[colId] : typeof(wo.columnSelector_columns[colId]) !== 'undefined' ? wo.columnSelector_columns[colId] : true;
|
77
|
+
colSel.$column[colId] = $(this);
|
78
|
+
|
79
|
+
// set default col title
|
80
|
+
name = $this.attr(wo.columnSelector_name) || $this.text();
|
81
|
+
|
82
|
+
if ($container.length) {
|
83
|
+
colSel.$wrapper[colId] = $(wo.columnSelector_layout.replace(/\{name\}/g, name)).appendTo($container);
|
84
|
+
colSel.$checkbox[colId] = colSel.$wrapper[colId]
|
85
|
+
// input may not be wrapped within the layout template
|
86
|
+
.find('input').add( colSel.$wrapper[colId].filter('input') )
|
87
|
+
.attr('data-column', colId)
|
88
|
+
.prop('checked', colSel.states[colId])
|
89
|
+
.bind('change', function(){
|
90
|
+
colSel.states[colId] = this.checked;
|
91
|
+
tsColSel.updateCols(c, wo);
|
92
|
+
}).change();
|
93
|
+
}
|
94
|
+
});
|
95
|
+
|
96
|
+
},
|
97
|
+
|
98
|
+
setupBreakpoints: function(c, wo){
|
99
|
+
var $auto, colSel = c.selector;
|
100
|
+
|
101
|
+
// add responsive breakpoints
|
102
|
+
if (wo.columnSelector_mediaquery) {
|
103
|
+
// used by window resize function
|
104
|
+
colSel.lastIndex = -1;
|
105
|
+
wo.columnSelector_breakpoints.sort();
|
106
|
+
colSel.$breakpoints = $('<style></style>').prop('disabled', true).appendTo('head');
|
107
|
+
tsColSel.updateBreakpoints(c, wo);
|
108
|
+
c.$table.unbind('updateAll' + namespace).bind('updateAll' + namespace, function(){
|
109
|
+
tsColSel.updateBreakpoints(c, wo);
|
110
|
+
tsColSel.updateCols(c, wo);
|
111
|
+
});
|
112
|
+
}
|
113
|
+
|
114
|
+
if (colSel.$container.length) {
|
115
|
+
// Add media queries toggle
|
116
|
+
if (wo.columnSelector_mediaquery && wo.columnSelector_mediaquery) {
|
117
|
+
$auto = $( wo.columnSelector_layout.replace(/\{name\}/g, wo.columnSelector_mediaqueryName) ).prependTo(colSel.$container);
|
118
|
+
$auto
|
119
|
+
// needed in case the input in the layout is not wrapped
|
120
|
+
.find('input').add( $auto.filter('input') )
|
121
|
+
.attr('data-column', 'auto')
|
122
|
+
.prop('checked', wo.columnSelector_mediaqueryState)
|
123
|
+
.bind('change', function(){
|
124
|
+
wo.columnSelector_mediaqueryState = this.checked;
|
125
|
+
$.each( colSel.$checkbox, function(i, $cb){
|
126
|
+
if ($cb) {
|
127
|
+
$cb[0].disabled = wo.columnSelector_mediaqueryState;
|
128
|
+
colSel.$wrapper[i].toggleClass('disabled', wo.columnSelector_mediaqueryState);
|
129
|
+
}
|
130
|
+
});
|
131
|
+
tsColSel.updateBreakpoints(c, wo);
|
132
|
+
tsColSel.updateCols(c, wo);
|
133
|
+
// copy the column selector to a popup/tooltip
|
134
|
+
if (c.selector.$popup) {
|
135
|
+
c.selector.$popup.find('.tablesorter-column-selector')
|
136
|
+
.html( colSel.$container.html() )
|
137
|
+
.find('input').each(function(){
|
138
|
+
var indx = $(this).attr('data-column')
|
139
|
+
$(this).prop( 'checked', indx === 'auto' ? wo.columnSelector_mediaqueryState : colSel.states[indx] )
|
140
|
+
});
|
141
|
+
}
|
142
|
+
}).change();
|
143
|
+
}
|
144
|
+
// Add a bind on update to re-run col setup
|
145
|
+
c.$table.unbind('update' + namespace).bind('update' + namespace, function() {
|
146
|
+
tsColSel.updateCols(c, wo);
|
147
|
+
});
|
148
|
+
}
|
149
|
+
},
|
150
|
+
|
151
|
+
updateBreakpoints: function(c, wo) {
|
152
|
+
var priority, column, breaks,
|
153
|
+
colSel = c.selector,
|
154
|
+
prefix = '.' + c.tableId,
|
155
|
+
mediaAll = [],
|
156
|
+
breakpts = '';
|
157
|
+
if (wo.columnSelector_mediaquery && !wo.columnSelector_mediaqueryState) {
|
158
|
+
colSel.$breakpoints.prop('disabled', true);
|
159
|
+
colSel.$style.prop('disabled', false);
|
160
|
+
return;
|
161
|
+
}
|
162
|
+
|
163
|
+
// only 6 breakpoints (same as jQuery Mobile)
|
164
|
+
for (priority = 0; priority < 6; priority++){
|
165
|
+
/*jshint loopfunc:true */
|
166
|
+
breaks = [];
|
167
|
+
c.$headers.filter('[' + wo.columnSelector_priority + '=' + (priority + 1) + ']').each(function(){
|
168
|
+
column = parseInt($(this).attr('data-column'), 10) + 1;
|
169
|
+
breaks.push(prefix + ' tr th:nth-child(' + column + ')');
|
170
|
+
breaks.push(prefix + ' tr td:nth-child(' + column + ')');
|
171
|
+
});
|
172
|
+
if (breaks.length) {
|
173
|
+
mediaAll = mediaAll.concat( breaks );
|
174
|
+
breakpts += tsColSel.queryBreak
|
175
|
+
.replace(/\[size\]/g, wo.columnSelector_breakpoints[priority])
|
176
|
+
.replace(/\[columns\]/g, breaks.join(','));
|
177
|
+
}
|
178
|
+
}
|
179
|
+
if (colSel.$style) {
|
180
|
+
colSel.$style.prop('disabled', true);
|
181
|
+
}
|
182
|
+
colSel.$breakpoints
|
183
|
+
.prop('disabled', false)
|
184
|
+
.html( tsColSel.queryAll.replace(/\[columns\]/g, mediaAll.join(',')) + breakpts );
|
185
|
+
},
|
186
|
+
|
187
|
+
updateCols: function(c, wo) {
|
188
|
+
if (wo.columnSelector_mediaquery && wo.columnSelector_mediaqueryState) {
|
189
|
+
return;
|
190
|
+
}
|
191
|
+
var column,
|
192
|
+
styles = [],
|
193
|
+
prefix = '.' + c.tableId;
|
194
|
+
c.selector.$container.find('input[data-column]').filter('[data-column!="auto"]').each(function(){
|
195
|
+
if (!this.checked) {
|
196
|
+
column = parseInt( $(this).attr('data-column'), 10 ) + 1;
|
197
|
+
styles.push(prefix + ' tr th:nth-child(' + column + ')');
|
198
|
+
styles.push(prefix + ' tr td:nth-child(' + column + ')');
|
199
|
+
}
|
200
|
+
});
|
201
|
+
if (wo.columnSelector_mediaquery){
|
202
|
+
c.selector.$breakpoints.prop('disabled', true);
|
203
|
+
}
|
204
|
+
if (c.selector.$style) {
|
205
|
+
c.selector.$style.prop('disabled', false).html( styles.length ? styles.join(',') + ' { display: none; }' : '' );
|
206
|
+
}
|
207
|
+
if (wo.columnSelector_saveColumns && ts.storage) {
|
208
|
+
ts.storage( c.$table[0], 'tablesorter-columnSelector', c.selector.states );
|
209
|
+
}
|
210
|
+
},
|
211
|
+
|
212
|
+
attachTo : function(table, elm) {
|
213
|
+
var colSel, wo, indx,
|
214
|
+
table = $(table)[0],
|
215
|
+
c = table.config,
|
216
|
+
$popup = $(elm);
|
217
|
+
if ($popup.length && c) {
|
218
|
+
if (!$popup.find('.tablesorter-column-selector').length) {
|
219
|
+
// add a wrapper to add the selector into, in case the popup has other content
|
220
|
+
$popup.append('<span class="tablesorter-column-selector"></span>');
|
221
|
+
}
|
222
|
+
colSel = c.selector;
|
223
|
+
wo = c.widgetOptions;
|
224
|
+
$popup.find('.tablesorter-column-selector')
|
225
|
+
.html( colSel.$container.html() )
|
226
|
+
.find('input').each(function(){
|
227
|
+
var indx = $(this).attr('data-column');
|
228
|
+
$(this).prop( 'checked', indx === 'auto' ? wo.columnSelector_mediaqueryState : colSel.states[indx] )
|
229
|
+
});
|
230
|
+
colSel.$popup = $popup.on('change', 'input', function(){
|
231
|
+
// data input
|
232
|
+
indx = $(this).attr('data-column');
|
233
|
+
// update original popup
|
234
|
+
colSel.$container.find('input[data-column="' + indx + '"]')
|
235
|
+
.prop('checked', this.checked)
|
236
|
+
.trigger('change');
|
237
|
+
});
|
238
|
+
}
|
239
|
+
}
|
240
|
+
|
241
|
+
};
|
242
|
+
|
243
|
+
ts.addWidget({
|
244
|
+
id: "columnSelector",
|
245
|
+
priority: 10,
|
246
|
+
options: {
|
247
|
+
// target the column selector markup
|
248
|
+
columnSelector_container : null,
|
249
|
+
// column status, true = display, false = hide
|
250
|
+
// disable = do not display on list
|
251
|
+
columnSelector_columns : {},
|
252
|
+
// remember selected columns
|
253
|
+
columnSelector_saveColumns: true,
|
254
|
+
|
255
|
+
// container layout
|
256
|
+
columnSelector_layout : '<label><input type="checkbox">{name}</label>',
|
257
|
+
// data attribute containing column name to use in the selector container
|
258
|
+
columnSelector_name : 'data-selector-name',
|
259
|
+
|
260
|
+
/* Responsive Media Query settings */
|
261
|
+
// enable/disable mediaquery breakpoints
|
262
|
+
columnSelector_mediaquery: true,
|
263
|
+
// toggle checkbox name
|
264
|
+
columnSelector_mediaqueryName: 'Auto: ',
|
265
|
+
// breakpoints checkbox initial setting
|
266
|
+
columnSelector_mediaqueryState: true,
|
267
|
+
// responsive table hides columns with priority 1-6 at these breakpoints
|
268
|
+
// see http://view.jquerymobile.com/1.3.2/dist/demos/widgets/table-column-toggle/#Applyingapresetbreakpoint
|
269
|
+
// *** set to false to disable ***
|
270
|
+
columnSelector_breakpoints : [ '20em', '30em', '40em', '50em', '60em', '70em' ],
|
271
|
+
// data attribute containing column priority
|
272
|
+
// duplicates how jQuery mobile uses priorities:
|
273
|
+
// http://view.jquerymobile.com/1.3.2/dist/demos/widgets/table-column-toggle/
|
274
|
+
columnSelector_priority : 'data-priority'
|
275
|
+
|
276
|
+
},
|
277
|
+
init: function(table, thisWidget, c, wo) {
|
278
|
+
tsColSel.init(table, c, wo);
|
279
|
+
},
|
280
|
+
remove: function(table, c){
|
281
|
+
var csel = c.selector;
|
282
|
+
csel.$container.empty();
|
283
|
+
csel.$popup.empty();
|
284
|
+
csel.$style.remove();
|
285
|
+
csel.$breakpoints.remove();
|
286
|
+
c.$table.unbind('updateAll' + namespace + ',update' + namespace);
|
287
|
+
}
|
288
|
+
|
289
|
+
});
|
290
|
+
|
291
|
+
})(jQuery);
|
@@ -0,0 +1,67 @@
|
|
1
|
+
/*! tablesorter CSS Sticky Headers widget - updated 12/17/2013 (v2.15.0)
|
2
|
+
* Requires a modern browser, tablesorter v2.8+
|
3
|
+
*/
|
4
|
+
/*global jQuery: false, unused:false */
|
5
|
+
;(function($){
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
$.tablesorter.addWidget({
|
9
|
+
id: "cssStickyHeaders",
|
10
|
+
priority: 10,
|
11
|
+
options: {
|
12
|
+
cssStickyHeaders_offset : 0,
|
13
|
+
cssStickyHeaders_addCaption : false,
|
14
|
+
cssStickyHeaders_attachTo : null,
|
15
|
+
cssStickyHeaders_zIndex : 10
|
16
|
+
},
|
17
|
+
init : function(table, thisWidget, c, wo) {
|
18
|
+
var $attach = $(wo.cssStickyHeaders_attachTo),
|
19
|
+
namespace = '.cssstickyheader',
|
20
|
+
$thead = c.$table.children('thead'),
|
21
|
+
$caption = c.$table.find('caption'),
|
22
|
+
$win = $attach.length ? $attach : $(window);
|
23
|
+
$win.bind('scroll resize '.split(' ').join(namespace + ' '), function() {
|
24
|
+
var top = $attach.length ? $attach.offset().top : $win.scrollTop(),
|
25
|
+
// add caption height; include table padding top & border-spacing or text may be above the fold (jQuery UI themes)
|
26
|
+
// border-spacing needed in Firefox, but not webkit... not sure if I should account for that
|
27
|
+
captionTop = wo.cssStickyHeaders_addCaption ? $caption.outerHeight(true) +
|
28
|
+
(parseInt(c.$table.css('padding-top'), 10) || 0) + (parseInt(c.$table.css('border-spacing'), 10) || 0) : 0,
|
29
|
+
bottom = c.$table.height() - $thead.height() - (c.$table.find('tfoot').height() || 0) - captionTop,
|
30
|
+
deltaY = top - $thead.offset().top + (parseInt(c.$table.css('border-top-width'), 10) || 0) +
|
31
|
+
(wo.cssStickyHeaders_offset || 0) + captionTop,
|
32
|
+
finalY = (deltaY > 0 && deltaY <= bottom ? deltaY : 0),
|
33
|
+
// IE can only transform header cells - fixes #447 thanks to @gakreol!
|
34
|
+
$cells = $thead.children().children();
|
35
|
+
if (wo.cssStickyHeaders_addCaption) {
|
36
|
+
$cells = $cells.add($caption);
|
37
|
+
}
|
38
|
+
$cells.css({
|
39
|
+
"position" : "relative",
|
40
|
+
"z-index" : wo.cssStickyHeaders_zIndex,
|
41
|
+
"transform" : finalY === 0 ? "" : "translate(0px," + finalY + "px)",
|
42
|
+
"-ms-transform" : finalY === 0 ? "" : "translate(0px," + finalY + "px)",
|
43
|
+
"-webkit-transform" : finalY === 0 ? "" : "translate(0px," + finalY + "px)"
|
44
|
+
});
|
45
|
+
});
|
46
|
+
c.$table.bind('filterEnd', function() {
|
47
|
+
// scroll top of table into view
|
48
|
+
window.scrollTo(0, c.$table.position().top);
|
49
|
+
});
|
50
|
+
|
51
|
+
},
|
52
|
+
remove: function(table, c, wo){
|
53
|
+
var namespace = '.cssstickyheader';
|
54
|
+
$(window).unbind('scroll resize '.split(' ').join(namespace + ' '));
|
55
|
+
c.$table
|
56
|
+
.unbind('update updateAll '.split(' ').join(namespace + ' '))
|
57
|
+
.children('thead, caption').css({
|
58
|
+
"position" : "",
|
59
|
+
"z-index" : "",
|
60
|
+
"transform" : "",
|
61
|
+
"-ms-transform" : "",
|
62
|
+
"-webkit-transform" : ""
|
63
|
+
});
|
64
|
+
}
|
65
|
+
});
|
66
|
+
|
67
|
+
})(jQuery);
|
@@ -0,0 +1,89 @@
|
|
1
|
+
/*! tablesorter Editable Content widget - updated 1/24/2014 (core v2.15.0)
|
2
|
+
* Requires tablesorter v2.8+ and jQuery 1.7+
|
3
|
+
* by Rob Garrison
|
4
|
+
*/
|
5
|
+
/*jshint browser:true, jquery:true, unused:false */
|
6
|
+
/*global jQuery: false */
|
7
|
+
;(function($){
|
8
|
+
"use strict";
|
9
|
+
|
10
|
+
$.tablesorter.addWidget({
|
11
|
+
id: 'editable',
|
12
|
+
options : {
|
13
|
+
editable_columns : [],
|
14
|
+
editable_enterToAccept : true,
|
15
|
+
editable_autoResort : false,
|
16
|
+
editable_noEdit : 'no-edit',
|
17
|
+
editable_editComplete : 'editComplete'
|
18
|
+
},
|
19
|
+
init: function(table, thisWidget, c, wo){
|
20
|
+
if (!wo.editable_columns.length) { return; }
|
21
|
+
var indx, tmp, $t, cols = [];
|
22
|
+
if (wo.editable_columns.indexOf('-') >= 0) {
|
23
|
+
// editable_columns can contain a range string (i.e. "2-4" )
|
24
|
+
tmp = wo.editable_columns.split('-');
|
25
|
+
indx = parseInt(tmp[0],10) || 0;
|
26
|
+
tmp = parseInt(tmp[1],10) || (c.columns - 1);
|
27
|
+
if (tmp > c.columns) { tmp = c.columns - 1; }
|
28
|
+
for (; indx <= tmp; indx++) {
|
29
|
+
cols.push('td:nth-child(' + (indx + 1) + ')');
|
30
|
+
}
|
31
|
+
} else if ($.isArray(wo.editable_columns)) {
|
32
|
+
$.each(wo.editable_columns, function(i, col){
|
33
|
+
cols.push('td:nth-child(' + (col + 1) + ')');
|
34
|
+
});
|
35
|
+
}
|
36
|
+
// IE does not allow making TR/TH/TD cells directly editable (issue #404)
|
37
|
+
// so add a div or span inside ( it's faster than using wrapInner() )
|
38
|
+
c.$tbodies.find( cols.join(',') ).not('.' + wo.editable_noEdit).each(function(){
|
39
|
+
// test for children, if they exist, then make the children editable
|
40
|
+
$t = $(this);
|
41
|
+
( $t.children().length ? $t.children() : $t ).prop('contenteditable', true);
|
42
|
+
});
|
43
|
+
c.$tbodies
|
44
|
+
.on('mouseleave.tseditable', function(){
|
45
|
+
if (c.$table.data('contentFocused')) {
|
46
|
+
$(':focus').trigger('blur');
|
47
|
+
}
|
48
|
+
})
|
49
|
+
.on('focus.tseditable', '[contenteditable]', function(){
|
50
|
+
c.$table.data('contentFocused', true);
|
51
|
+
var $this = $(this), v = $this.html();
|
52
|
+
if (wo.editable_enterToAccept) {
|
53
|
+
// prevent enter from adding into the content
|
54
|
+
$this.on('keydown.tseditable', function(e){
|
55
|
+
if (e.which === 13) {
|
56
|
+
e.preventDefault();
|
57
|
+
}
|
58
|
+
});
|
59
|
+
}
|
60
|
+
$this.data({ before : v, original: v });
|
61
|
+
})
|
62
|
+
.on('blur focusout keyup '.split(' ').join('.tseditable '), '[contenteditable]', function(e){
|
63
|
+
if (!c.$table.data('contentFocused')) { return; }
|
64
|
+
var $this = $(e.target), t;
|
65
|
+
if (e.which === 27) {
|
66
|
+
// user cancelled
|
67
|
+
$this.html( $this.data('original') ).trigger('blur.tseditable');
|
68
|
+
c.$table.data('contentFocused', false);
|
69
|
+
return false;
|
70
|
+
}
|
71
|
+
t = e.type !== 'keyup' || (wo.editable_enterToAccept && e.which === 13);
|
72
|
+
// change if new or user hits enter (if option set)
|
73
|
+
if ($this.data('before') !== $this.html() || t) {
|
74
|
+
$this.data('before', $this.html()).trigger('change');
|
75
|
+
if (t) {
|
76
|
+
c.$table
|
77
|
+
.data('contentFocused', false)
|
78
|
+
.trigger('updateCell', [ $this.closest('td'), wo.editable_autoResort, function(table){
|
79
|
+
$this.trigger( wo.editable_editComplete );
|
80
|
+
c.$table.trigger('applyWidgets');
|
81
|
+
} ]);
|
82
|
+
$this.trigger('blur.tseditable');
|
83
|
+
}
|
84
|
+
}
|
85
|
+
});
|
86
|
+
}
|
87
|
+
});
|
88
|
+
|
89
|
+
})(jQuery);
|
@@ -0,0 +1,183 @@
|
|
1
|
+
/*! tablesorter Grouping widget - updated 12/18/2013 (core v2.15.0)
|
2
|
+
* Requires tablesorter v2.8+ and jQuery 1.7+
|
3
|
+
* by Rob Garrison
|
4
|
+
*/
|
5
|
+
/*jshint browser:true, jquery:true, unused:false */
|
6
|
+
/*global jQuery: false */
|
7
|
+
;(function($){
|
8
|
+
"use strict";
|
9
|
+
var ts = $.tablesorter;
|
10
|
+
|
11
|
+
ts.grouping = {
|
12
|
+
|
13
|
+
types : {
|
14
|
+
number : function(c, $column, txt, num, group){
|
15
|
+
var value, word;
|
16
|
+
if (num > 1 && txt !== '') {
|
17
|
+
if ($column.hasClass(ts.css.sortAsc)) {
|
18
|
+
value = Math.floor(parseFloat(txt)/num) * num;
|
19
|
+
return value > parseFloat(group || 0) ? value : parseFloat(group || 0);
|
20
|
+
} else {
|
21
|
+
value = Math.ceil(parseFloat(txt)/num) * num;
|
22
|
+
return value < parseFloat(group || num) - value ? parseFloat(group || num) - value : value;
|
23
|
+
}
|
24
|
+
} else {
|
25
|
+
word = (txt + '').match(/\d+/g);
|
26
|
+
return word && word.length >= num ? word[num - 1] : txt || '';
|
27
|
+
}
|
28
|
+
},
|
29
|
+
separator : function(c, $column, txt, num){
|
30
|
+
var word = (txt + '').split(c.widgetOptions.group_separator);
|
31
|
+
return $.trim(word && num > 0 && word.length >= num ? word[(num || 1) - 1] : '');
|
32
|
+
},
|
33
|
+
word : function(c, $column, txt, num){
|
34
|
+
var word = (txt + ' ').match(/\w+/g);
|
35
|
+
return word && word.length >= num ? word[num - 1] : txt || '';
|
36
|
+
},
|
37
|
+
letter : function(c, $column, txt, num){
|
38
|
+
return txt ? (txt + ' ').substring(0, num) : '';
|
39
|
+
},
|
40
|
+
date : function(c, $column, txt, part, group){
|
41
|
+
var wo = c.widgetOptions,
|
42
|
+
time = new Date(txt || ''),
|
43
|
+
hours = time.getHours();
|
44
|
+
return part === 'year' ? time.getFullYear() :
|
45
|
+
part === 'month' ? wo.group_months[time.getMonth()] :
|
46
|
+
part === 'day' ? wo.group_months[time.getMonth()] + ' ' + time.getDate() :
|
47
|
+
part === 'week' ? wo.group_week[time.getDay()] :
|
48
|
+
part === 'time' ? ('00' + (hours > 12 ? hours - 12 : hours === 0 ? hours + 12 : hours)).slice(-2) + ':' +
|
49
|
+
('00' + time.getMinutes()).slice(-2) + ' ' + ('00' + wo.group_time[hours >= 12 ? 1 : 0]).slice(-2) :
|
50
|
+
wo.group_dateString(time);
|
51
|
+
}
|
52
|
+
},
|
53
|
+
|
54
|
+
update : function(table, c, wo){
|
55
|
+
if ($.isEmptyObject(c.cache)) { return; }
|
56
|
+
var rowIndex, tbodyIndex, currentGroup, $rows, groupClass, grouping, time, cache,
|
57
|
+
lang = wo.grouping_language,
|
58
|
+
group = '',
|
59
|
+
column = c.sortList[0] ? c.sortList[0][0] : -1;
|
60
|
+
c.$table
|
61
|
+
.find('tr.group-hidden').removeClass('group-hidden').end()
|
62
|
+
.find('tr.group-header').remove();
|
63
|
+
if (wo.group_collapsible) {
|
64
|
+
// clear pager saved spacer height (in case the rows are collapsed)
|
65
|
+
c.$table.data('pagerSavedHeight', 0);
|
66
|
+
}
|
67
|
+
if (column >= 0 && !c.$headers.filter('[data-column="' + column + '"]:last').hasClass('group-false')) {
|
68
|
+
if (c.debug){ time = new Date(); }
|
69
|
+
for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++) {
|
70
|
+
cache = c.cache[tbodyIndex].normalized;
|
71
|
+
group = ''; // clear grouping across tbodies
|
72
|
+
$rows = c.$tbodies.eq(tbodyIndex).children('tr').not('.' + c.cssChildRow);
|
73
|
+
if (wo.group_collapsed && wo.group_collapsible) {
|
74
|
+
$rows.addClass('group-hidden');
|
75
|
+
}
|
76
|
+
for (rowIndex = 0; rowIndex < $rows.length; rowIndex++) {
|
77
|
+
if ( $rows.eq(rowIndex).is(':visible') ) {
|
78
|
+
// group class finds "group-{word/separator/letter/number/date/false}-{optional:#/year/month/day/week/time}"
|
79
|
+
groupClass = (c.$headers.filter('[data-column="' + column + '"]:last').attr('class') || '').match(/(group-\w+(-\w+)?)/g);
|
80
|
+
// grouping = [ 'group', '{word/separator/letter/number/date/false}', '{#/year/month/day/week/time}' ]
|
81
|
+
grouping = groupClass ? groupClass[0].split('-') : ['','letter',1]; // default to letter 1
|
82
|
+
// fixes #438
|
83
|
+
if (ts.grouping.types[grouping[1]]) {
|
84
|
+
currentGroup = cache[rowIndex] ?
|
85
|
+
ts.grouping.types[grouping[1]]( c, c.$headers.filter('[data-column="' + column + '"]:last'), cache[rowIndex][column], /date/.test(groupClass) ?
|
86
|
+
grouping[2] : parseInt(grouping[2] || 1, 10) || 1, group, lang ) : currentGroup;
|
87
|
+
if (group !== currentGroup) {
|
88
|
+
group = currentGroup;
|
89
|
+
// show range if number > 1
|
90
|
+
if (grouping[1] === 'number' && grouping[2] > 1 && currentGroup !== '') {
|
91
|
+
currentGroup += ' - ' + (parseInt(currentGroup, 10) +
|
92
|
+
((parseInt(grouping[2],10) - 1) * (c.$headers.filter('[data-column="' + column + '"]:last').hasClass(ts.css.sortAsc) ? 1 : -1)));
|
93
|
+
}
|
94
|
+
if ($.isFunction(wo.group_formatter)) {
|
95
|
+
currentGroup = wo.group_formatter((currentGroup || '').toString(), column, table, c, wo) || currentGroup;
|
96
|
+
}
|
97
|
+
$rows.eq(rowIndex).before('<tr class="group-header ' + c.selectorRemove.slice(1) +
|
98
|
+
(wo.group_collapsed && wo.group_collapsible ? ' collapsed' : '') + '" unselectable="on"><td colspan="' +
|
99
|
+
c.columns + '">' + (wo.group_collapsible ? '<i/>' : '') + '<span class="group-name">' +
|
100
|
+
currentGroup + '</span><span class="group-count"></span></td></tr>');
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
$rows = c.$table.find('tr.group-header').bind('selectstart', false);
|
107
|
+
if (wo.group_count || $.isFunction(wo.group_callback)) {
|
108
|
+
$rows.each(function(){
|
109
|
+
var $rows,
|
110
|
+
$row = $(this),
|
111
|
+
$label = $row.find('.group-count');
|
112
|
+
if ($label.length) {
|
113
|
+
$rows = $row.nextUntil('tr.group-header').filter(':visible');
|
114
|
+
if (wo.group_count) {
|
115
|
+
$label.html( wo.group_count.replace(/\{num\}/g, $rows.length) );
|
116
|
+
}
|
117
|
+
if ($.isFunction(wo.group_callback)) {
|
118
|
+
wo.group_callback($row.find('td'), $rows, column, table);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
});
|
122
|
+
}
|
123
|
+
c.$table.trigger(wo.group_complete);
|
124
|
+
if (c.debug) {
|
125
|
+
$.tablesorter.benchmark("Applying groups widget: ", time);
|
126
|
+
}
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
};
|
131
|
+
|
132
|
+
ts.addWidget({
|
133
|
+
id: 'group',
|
134
|
+
priority: 100,
|
135
|
+
options: {
|
136
|
+
group_collapsible : true, // make the group header clickable and collapse the rows below it.
|
137
|
+
group_collapsed : false, // start with all groups collapsed
|
138
|
+
group_count : ' ({num})', // if not false, the "{num}" string is replaced with the number of rows in the group
|
139
|
+
group_separator : '-', // group name separator; used when group-separator-# class is used.
|
140
|
+
group_formatter : null, // function(txt, column, table, c, wo) { return txt; }
|
141
|
+
group_callback : null, // function($cell, $rows, column, table){}, callback allowing modification of the group header labels
|
142
|
+
group_complete : 'groupingComplete', // event triggered on the table when the grouping widget has finished work
|
143
|
+
|
144
|
+
// change these default date names based on your language preferences
|
145
|
+
group_months : [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ],
|
146
|
+
group_week : [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ],
|
147
|
+
group_time : [ 'AM', 'PM' ],
|
148
|
+
// this function is used when "group-date" is set to create the date string
|
149
|
+
// you can just return date, date.toLocaleString(), date.toLocaleDateString() or d.toLocaleTimeString()
|
150
|
+
// reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Conversion_getter
|
151
|
+
group_dateString : function(date) { return date.toLocaleString(); }
|
152
|
+
},
|
153
|
+
init: function(table, thisWidget, c, wo){
|
154
|
+
if (wo.group_collapsible) {
|
155
|
+
// .on() requires jQuery 1.7+
|
156
|
+
c.$table.on('click toggleGroup', 'tr.group-header', function(event){
|
157
|
+
event.stopPropagation();
|
158
|
+
var $this = $(this);
|
159
|
+
// use shift-click to toggle ALL groups
|
160
|
+
if (event.type === 'click' && event.shiftKey) {
|
161
|
+
$this.siblings('.group-header').trigger('toggleGroup');
|
162
|
+
}
|
163
|
+
$this.toggleClass('collapsed');
|
164
|
+
// nextUntil requires jQuery 1.4+
|
165
|
+
$this.nextUntil('tr.group-header').toggleClass('group-hidden', $this.hasClass('collapsed') );
|
166
|
+
});
|
167
|
+
}
|
168
|
+
c.$table.on('pagerChange', function(){
|
169
|
+
ts.grouping.update(table, c, wo);
|
170
|
+
});
|
171
|
+
},
|
172
|
+
format: function(table, c, wo) {
|
173
|
+
ts.grouping.update(table, c, wo);
|
174
|
+
},
|
175
|
+
remove : function(table, c, wo){
|
176
|
+
c.$table
|
177
|
+
.off('click', 'tr.group-header')
|
178
|
+
.find('.group-hidden').removeClass('group-hidden').end()
|
179
|
+
.find('tr.group-header').remove();
|
180
|
+
}
|
181
|
+
});
|
182
|
+
|
183
|
+
})(jQuery);
|