jquery-tablesorter 1.10.2 → 1.10.3
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|