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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/README.markdown +6 -3
  3. data/Rakefile +30 -16
  4. data/lib/jquery-tablesorter/version.rb +1 -1
  5. data/vendor/assets/javascripts/jquery-tablesorter/extras/jquery.quicksearch.js +191 -0
  6. data/vendor/assets/javascripts/jquery-tablesorter/extras/semver-mod.js +1026 -0
  7. data/vendor/assets/javascripts/jquery-tablesorter/extras/semver.js +1011 -0
  8. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +2 -2
  9. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date-iso8601.js +34 -0
  10. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date-month.js +33 -0
  11. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date-two-digit-year.js +74 -0
  12. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date-weekday.js +33 -0
  13. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date.js +36 -0
  14. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-feet-inch-fraction.js +63 -0
  15. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-file-type.js +73 -0
  16. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-ignore-articles.js +47 -0
  17. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-input-select.js +86 -0
  18. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-ipv6.js +76 -0
  19. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-metric.js +77 -0
  20. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-build-table.js +441 -0
  21. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-columnSelector.js +291 -0
  22. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-cssStickyHeaders.js +67 -0
  23. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-editable.js +89 -0
  24. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-grouping.js +183 -0
  25. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-pager.js +834 -0
  26. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-repeatheaders.js +50 -0
  27. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-scroller.js +241 -0
  28. metadata +24 -2
@@ -0,0 +1,76 @@
1
+ /*! IPv6 Address parser (WIP)
2
+ * IPv6 Address (ffff:0000:0000:0000:0000:0000:0000:0000)
3
+ * needs to support short versions like "::8" or "1:2::7:8"
4
+ * and "::00:192.168.10.184" (embedded IPv4 address)
5
+ * see http://www.intermapper.com/support/tools/IPV6-Validator.aspx
6
+ */
7
+ /*global jQuery: false */
8
+ ;(function($){
9
+ "use strict";
10
+
11
+ var ts = $.tablesorter;
12
+
13
+ $.extend( ts.regex, {}, {
14
+ ipv4Validate : /((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})/,
15
+ ipv4Extract : /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/,
16
+
17
+ // simplified regex from http://www.intermapper.com/support/tools/IPV6-Validator.aspx
18
+ // (specifically from http://download.dartware.com/thirdparty/ipv6validator.js)
19
+ ipv6Validate : /^\s*((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/i
20
+ });
21
+
22
+ ts.addParser({
23
+ id: "ipv6Address",
24
+ is: function(s) {
25
+ return ts.regex.ipv6Validate.test(s);
26
+ },
27
+ format: function(address, table) {
28
+ // code modified from http://forrst.com/posts/JS_Expand_Abbreviated_IPv6_Addresses-1OR
29
+ var i, t, sides, groups, groupsPresent,
30
+ hex = table ? (typeof table === "boolean" ? table : table && table.config.ipv6HexFormat || false) : false,
31
+ fullAddress = '',
32
+ expandedAddress = '',
33
+ validGroupCount = 8,
34
+ validGroupSize = 4;
35
+ // remove any extra spaces
36
+ address = address.replace(/\s*/g, '');
37
+ // look for embedded ipv4
38
+ if (ts.regex.ipv4Validate.test(address)) {
39
+ groups = address.match(ts.regex.ipv4Extract);
40
+ t = '';
41
+ for (i = 1; i < groups.length; i++){
42
+ t += ('00' + (parseInt(groups[i], 10).toString(16)) ).slice(-2) + ( i === 2 ? ':' : '' );
43
+ }
44
+ address = address.replace( ts.regex.ipv4Extract, t );
45
+ }
46
+
47
+ if (address.indexOf("::") == -1) {
48
+ // All eight groups are present
49
+ fullAddress = address;
50
+ } else {
51
+ // Consecutive groups of zeroes have been collapsed with "::".
52
+ sides = address.split("::");
53
+ groupsPresent = 0;
54
+ for (i = 0; i < sides.length; i++) {
55
+ groupsPresent += sides[i].split(":").length;
56
+ }
57
+ fullAddress += sides[0] + ":";
58
+ for (i = 0; i < validGroupCount - groupsPresent; i++) {
59
+ fullAddress += "0000:";
60
+ }
61
+ fullAddress += sides[1];
62
+ }
63
+ groups = fullAddress.split(":");
64
+ for (i = 0; i < validGroupCount; i++) {
65
+ // it's fastest & easiest for tablesorter to sort decimal values (vs hex)
66
+ groups[i] = hex ? ('0000' + groups[i]).slice(-4) :
67
+ ('00000' + (parseInt(groups[i], 16) || 0)).slice(-5);
68
+ expandedAddress += ( i != validGroupCount-1) ? groups[i] + ':' : groups[i];
69
+ }
70
+ return hex ? expandedAddress : expandedAddress.replace(/:/g, '');
71
+ },
72
+ // uses natural sort hex compare
73
+ type: "numeric"
74
+ });
75
+
76
+ })(jQuery);
@@ -0,0 +1,77 @@
1
+ /*! Metric parser
2
+ * Demo: http://jsfiddle.net/Mottie/abkNM/382/
3
+ * Set the metric name in the header (defaults to "m|meter"), e.g.
4
+ * <th data-metric-name="b|byte">HDD Size</th>
5
+ * <th data-metric-name="m|meter">Distance</th>
6
+ */
7
+ /*jshint jquery:true */
8
+ ;(function($){
9
+ "use strict";
10
+
11
+ var prefixes = {
12
+ // "prefix" : [ base 10, base 2 ]
13
+ // skipping IEEE 1541 defined prefixes: kibibyte, mebibyte, etc, for now.
14
+ "Y|Yotta|yotta" : [ 1e24, Math.pow(1024, 8) ], // 1024^8
15
+ "Z|Zetta|zetta" : [ 1e21, Math.pow(1024, 7) ], // 1024^7
16
+ "E|Exa|exa" : [ 1e18, Math.pow(1024, 6) ], // 1024^6
17
+ "P|Peta|peta" : [ 1e15, Math.pow(1024, 5) ], // 1024^5
18
+ "T|Tera|tera" : [ 1e12, Math.pow(1024, 4) ], // 1024^4
19
+ "G|Giga|giga" : [ 1e9, Math.pow(1024, 3) ], // 1024^3
20
+ "M|Mega|mega" : [ 1e6, Math.pow(1024, 2) ], // 1024^2
21
+ "k|Kilo|kilo" : [ 1e3, 1024 ], // 1024
22
+ // prefixes below here are rarely, if ever, used in binary
23
+ "h|hecto" : [ 1e2, 1e2 ],
24
+ "da|deka" : [ 1e1, 1e1 ],
25
+ "d|deci" : [ 1e-1, 1e-1 ],
26
+ "c|centi" : [ 1e-2, 1e-2],
27
+ "m|milli" : [ 1e-3, 1e-3 ],
28
+ "µ|micro" : [ 1e-6, 1e-6 ],
29
+ "n|nano" : [ 1e-9, 1e-9 ],
30
+ "p|pico" : [ 1e-12, 1e-12 ],
31
+ "f|femto" : [ 1e-15, 1e-15 ],
32
+ "a|atto" : [ 1e-18, 1e-18 ],
33
+ "z|zepto" : [ 1e-21, 1e-21 ],
34
+ "y|yocto" : [ 1e-24, 1e-24 ]
35
+ },
36
+ // the \\d+ will not catch digits with spaces, commas or decimals; so use the value from n instead
37
+ RegLong = "(\\d+)(\\s+)?([Zz]etta|[Ee]xa|[Pp]eta|[Tt]era|[Gg]iga|[Mm]ega|kilo|hecto|deka|deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto)(",
38
+ RegAbbr = "(\\d+)(\\s+)?(Z|E|P|T|G|M|k|h|da|d|c|m|µ|n|p|f|a|z|y)(";
39
+
40
+ $.tablesorter.addParser({
41
+ id: 'metric',
42
+ is: function() {
43
+ return false;
44
+ },
45
+ format: function(s, table, cell, cellIndex) {
46
+ var v = 'm|meter',
47
+ b, t,
48
+ // process number here to get a numerical format (us or eu)
49
+ n = $.tablesorter.formatFloat(s.replace(/[^\w,. \-()]/g, ""), table),
50
+ $t = table.config.$headers.filter('[data-column="' + cellIndex + '"]'),
51
+ m = $t.data('metric');
52
+ if (!m) {
53
+ // stored values
54
+ t = ($t.attr('data-metric-name') || v).split('|');
55
+ m = [ t[1] || t[0].substring(1), t[0] ];
56
+ m[2] = new RegExp(RegLong + m[0] + "|" + m[1] + ")");
57
+ m[3] = new RegExp(RegAbbr + m[1] + ")");
58
+ $t.data('metric', m);
59
+ }
60
+ // find match to full name or abbreviation
61
+ t = s.match(m[2]) || s.match(m[3]);
62
+ if (t) {
63
+ for (v in prefixes) {
64
+ if (t[3].match(v)) {
65
+ // exception when using binary prefix
66
+ // change base for binary use
67
+ b = /^[b|bit|byte|o|octet]/.test(t[4]) ? 1 : 0;
68
+ return n * prefixes[v][b];
69
+ }
70
+ }
71
+ }
72
+ return n;
73
+ },
74
+ type: 'numeric'
75
+ });
76
+
77
+ })(jQuery);
@@ -0,0 +1,441 @@
1
+ /*! Build Table widget * by Rob Garrison */
2
+ /*jshint browser:true, jquery:true, unused:false */
3
+ /*global jQuery: false */
4
+ ;(function($){
5
+ "use strict";
6
+ var ts = $.tablesorter = $.tablesorter || {},
7
+
8
+ // build a table from data (requires existing <table> tag)
9
+ // data.header contains an array of header titles
10
+ // data.rows contains an array of rows which contains an array of cells
11
+ bt = ts.buildTable = function(tar, c){
12
+ // add table if one doesn't exist
13
+ var $tbl = tar.tagName === 'TABLE' ? $(tar) : $('<table>').appendTo(tar),
14
+ table = $tbl[0],
15
+ wo = c.widgetOptions = $.extend( true, {}, bt.defaults, c.widgetOptions ),
16
+ p = wo.build_processing,
17
+ typ = wo.build_type,
18
+ d = wo.build_source || c.data,
19
+
20
+ // determine type: html, json, array, csv, object
21
+ runType = function(d){
22
+ var t = $.type(d),
23
+ jq = d instanceof jQuery;
24
+ // run any processing if set
25
+ if ( typeof p === 'function' ) { d = p(d, wo); }
26
+ // store processed data in table.config.data
27
+ c.data = d;
28
+ // String (html or unprocessed json) or jQuery object
29
+ if ( jq || t === 'string' ) {
30
+ // look for </tr> closing tag, then we have an HTML string
31
+ if ( jq || /<\s*\/tr\s*>/.test(d) ) {
32
+ return bt.html( table, d, wo );
33
+ }
34
+ try {
35
+ d = $.parseJSON(d);
36
+ if (d) {
37
+ // valid JSON!
38
+ return bt.object( table, d, wo );
39
+ }
40
+ } catch(ignore) {}
41
+ // fall through in case it's a csv string
42
+ }
43
+ // Array
44
+ if (t === 'array' || t === 'string' || typ === 'array' || typ === 'csv') {
45
+ // build table using an array (csv & array combined script)
46
+ return bt.csv( table, d, wo );
47
+ }
48
+ // if we got here, it's an object, or nothing
49
+ return bt.object( table, d, wo );
50
+ };
51
+
52
+ // store config
53
+ table.config = c;
54
+
55
+ // even if wo.build_type is undefined, we can try to figure out the type
56
+ if ( !ts.buildTable.hasOwnProperty(typ) && typ !== '' ) {
57
+ if (c.debug) { ts.log('aborting build table widget, incorrect build type'); }
58
+ return false;
59
+ }
60
+
61
+ if ( d instanceof jQuery ) {
62
+ // get data from within a jQuery object (csv)
63
+ runType( $.trim( d.html() ) );
64
+ } else if ( d && ( d.hasOwnProperty('url') || typ === 'json' ) ) {
65
+ // load data via ajax
66
+ $.ajax( wo.build_source )
67
+ .done(function(data) {
68
+ runType(data);
69
+ })
70
+ .fail(function( jqXHR, textStatus, errorThrown) {
71
+ if (c.debug) { ts.log('aborting build table widget, failed ajax load'); }
72
+ $tbl.html('<tr><td class="error">' + jqXHR.status + ' ' + textStatus + '</td></tr>');
73
+ });
74
+ } else {
75
+ runType(d);
76
+ }
77
+ };
78
+
79
+ bt.defaults = {
80
+ // *** build widget core ***
81
+ build_type : '', // array, csv, object, json, html
82
+ build_source : '', // array, object, jQuery Object or ajaxObject { url: '', dataType: 'json' },
83
+ build_processing : null, // function that returns a useable build_type (e.g. string to array)
84
+ build_complete : 'tablesorter-build-complete', // triggered event when build completes
85
+
86
+ // *** CSV & Array ***
87
+ build_headers : {
88
+ rows : 1, // Number of header rows from the csv
89
+ classes : [], // Header classes to apply to cells
90
+ text : [], // Header cell text
91
+ widths : [] // set header cell widths (set in colgroup)
92
+ },
93
+ build_footers : {
94
+ rows : 1, // Number of header rows from the csv
95
+ classes : [], // Footer classes to apply to cells
96
+ text : [] // Footer cell text
97
+ },
98
+ build_numbers : {
99
+ addColumn : false, // include row numbering column?
100
+ sortable : false // make column sortable?
101
+ },
102
+
103
+ // *** CSV only options ***
104
+ build_csvStartLine : 0, // line within the csv to start adding to table
105
+ build_csvSeparator : ",", // csv separator
106
+
107
+ // *** build object options ***
108
+ build_objectRowKey : 'rows', // object key containing table rows
109
+ build_objectCellKey : 'cells', // object key containing table cells (within the rows object)
110
+ build_objectHeaderKey : 'headers', // object key containing table headers
111
+ build_objectFooterKey : 'footers' // object key containing table footers
112
+ };
113
+
114
+ bt.build = {
115
+ colgroup : function(widths) {
116
+ var t = '';
117
+ // add colgroup if widths set
118
+ if (widths && widths.length) {
119
+ t += '<colgroup>';
120
+ $.each(widths, function(i, w){
121
+ t += '<col' + ( w ? ' style="width:' + w + '"' : '' ) + '>';
122
+ });
123
+ t += '</colgroup>';
124
+ }
125
+ return t;
126
+ },
127
+ // d = cell data; typ = 'th' or 'td'; first = save widths from first header row only
128
+ cell : function(d, wo, typ, col, first){
129
+ var j, $td,
130
+ $col = first ? $('<col>') : '',
131
+ cls = wo.build_headers.classes,
132
+ cw = wo.build_headers.widths;
133
+ // d is just an array
134
+ if (/string|number/.test(typeof d)) {
135
+ // add classes from options, but not text
136
+ $td = $('<' + typ + (cls && cls[col] ? ' class="' + cls[col] + '"' : '') + '>' + d + '</' + typ + '>');
137
+ // get widths from options (only from first row)
138
+ if (first && cw && cw[col]) {
139
+ $col.width(cw[col] || '');
140
+ }
141
+ } else {
142
+ // assume we have an object
143
+ $td = $('<' + typ + '>');
144
+ for (j in d) {
145
+ if (d.hasOwnProperty(j)){
146
+ if (j === 'text' || j === 'html') {
147
+ $td[j]( d[j] );
148
+ } else if (first && j === 'width') {
149
+ // set column width, but only from first row
150
+ $col.width(d[j] || '');
151
+ } else {
152
+ $td.attr(j, d[j]);
153
+ }
154
+ }
155
+ }
156
+ }
157
+ return [ $td, $col ];
158
+ },
159
+ // h1 = header text from data
160
+ header : function(h1, wo){
161
+ var h2 = wo.build_headers.text,
162
+ cls = wo.build_headers.classes,
163
+ t = '<tr>' + (wo.build_numbers.addColumn ? '<th' + (wo.build_numbers.sortable ? '' :
164
+ ' class="sorter-false"') + '>' + wo.build_numbers.addColumn + '</th>' : '');
165
+ $.each(h1, function(i, h) {
166
+ t += '<th' + (cls && cls[i] ? ' class="' + cls[i] + '"' : '') + '>' +
167
+ (h2 && h2[i] ? h2[i] : h) + '</th>';
168
+ });
169
+ return t + '</tr>';
170
+ },
171
+ rows : function(items, txt, c, wo, num, ftr){
172
+ var h = (ftr ? 'th' : 'td'),
173
+ t = '<tr>' + (wo.build_numbers.addColumn ? '<' + h + '>' + (ftr ? '' : num) + '</' + h + '>' : '');
174
+ $.each(items, function(i, item) {
175
+ t += '<' + (ftr ? h + (c && c[i] ? ' class="' + c[i] + '"' : '') : h) + '>' +
176
+ (ftr && txt && txt.length && txt[i] ? txt[i] : item) + '</' + h + '>';
177
+ });
178
+ return t + '</tr>';
179
+ }
180
+ };
181
+
182
+ bt.buildComplete = function(table, wo){
183
+ $(table).trigger(wo.build_complete);
184
+ ts.setup(table, table.config);
185
+ };
186
+
187
+ /* ==== Array example ====
188
+ [
189
+ [ "header1", "header2", ... "headerN" ],
190
+ [ "row1cell1", "row1cell2", ... "row1cellN" ],
191
+ [ "row2cell1", "row2cell2", ... "row2cellN" ],
192
+ ...
193
+ [ "rowNcell1", "rowNcell2", ... "rowNcellN" ]
194
+ ]
195
+ */
196
+ bt.array = function(table, data, wo) {
197
+ return bt.csv(table, data, wo);
198
+ };
199
+
200
+ /* ==== CSV example ====
201
+ ID, Name, Age, Date
202
+ A42b, Parker, 28, "Jul 6, 2006 8:14 AM"
203
+ A255, Hood, 33, "Dec 10, 2002 5:14 AM"
204
+ A33, Kent, 18, "Jan 12, 2003 11:14 AM"
205
+ A1, Franklin, 45, "Jan 18, 2001 9:12 AM"
206
+ A102, Evans, 22, "Jan 18, 2007 9:12 AM"
207
+ A42a, Everet, 22, "Jan 18, 2007 9:12 AM"
208
+ ID, Name, Age, Date
209
+ */
210
+ // Adapted & modified from csvToTable.js by Steve Sobel
211
+ // MIT license: https://code.google.com/p/jquerycsvtotable/
212
+ bt.csv = function(table, data, wo) {
213
+ var c, h,
214
+ csv = wo.build_type === 'csv' || typeof data === 'string',
215
+ $t = $(table),
216
+ lines = csv ? data.replace('\r','').split('\n') : data,
217
+ len = lines.length,
218
+ printedLines = 0,
219
+ infooter = false,
220
+ r = wo.build_headers.rows + (csv ? wo.build_csvStartLine : 0),
221
+ f = wo.build_footers.rows,
222
+ headerCount = 0,
223
+ error = '',
224
+ items,
225
+ tableHTML = bt.build.colgroup( wo.build_headers.widths ) + '<thead>';
226
+
227
+ $.each(lines, function(n, line) {
228
+ if ( n >= len - f ) { infooter = true; }
229
+ // build header
230
+ if ( (csv ? n >= wo.build_csvStartLine : true) && ( n < r ) ) {
231
+ h = csv ? bt.splitCSV( line, wo.build_csvSeparator ) : line;
232
+ headerCount = h.length;
233
+ tableHTML += bt.build.header(h, wo);
234
+ } else if ( n >= r ) {
235
+ // build tbody & tfoot rows
236
+ if (n === r) {
237
+ tableHTML += '</thead><tbody>';
238
+ }
239
+ items = csv ? bt.splitCSV( line, wo.build_csvSeparator ) : line;
240
+ if (infooter && f > 0) {
241
+ tableHTML += (n === len - f ? '</tbody><tfoot>' : '') +
242
+ (n === len ? '</tfoot>' : '');
243
+ }
244
+ if (items.length > 1) {
245
+ printedLines++;
246
+ if ( items.length !== headerCount ) {
247
+ error += 'error on line ' + n + ': Item count (' + items.length +
248
+ ') does not match header count (' + headerCount + ') \n';
249
+ }
250
+ c = infooter ? wo.build_footers.classes : '';
251
+ tableHTML += bt.build.rows(items, wo.build_footers.text, c, wo, printedLines, infooter);
252
+ }
253
+ }
254
+ });
255
+ tableHTML += (f > 0 ? '' : '</tbody>');
256
+ if (error) {
257
+ $t.html(error);
258
+ } else {
259
+ $t.html(tableHTML);
260
+ bt.buildComplete(table, wo);
261
+ }
262
+ };
263
+
264
+ // CSV Parser by Brian Huisman (http://www.greywyvern.com/?post=258)
265
+ bt.splitCSV = function(str, sep) {
266
+ var x, tl,
267
+ thisCSV = $.trim(str).split(sep = sep || ",");
268
+ for ( x = thisCSV.length - 1; x >= 0; x-- ) {
269
+ if ( thisCSV[x].replace(/\"\s+$/, '"').charAt(thisCSV[x].length - 1) === '"' ) {
270
+ if ( (tl = thisCSV[x].replace(/^\s+\"/, '"')).length > 1 && tl.charAt(0) === '"' ) {
271
+ thisCSV[x] = thisCSV[x].replace(/^\s*"|"\s*$/g, '').replace(/""/g, '"');
272
+ } else if (x) {
273
+ thisCSV.splice(x - 1, 2, [thisCSV[x - 1], thisCSV[x]].join(sep));
274
+ } else {
275
+ thisCSV = thisCSV.shift().split(sep).concat(thisCSV);
276
+ }
277
+ } else {
278
+ thisCSV[x].replace(/""/g, '"');
279
+ }
280
+ }
281
+ return thisCSV;
282
+ };
283
+
284
+ // data may be a jQuery object after processing
285
+ bt.html = function(table, data, wo) {
286
+ var $t = $(table);
287
+ if ( data instanceof jQuery ) {
288
+ $t.empty().append(data);
289
+ } else {
290
+ $t.html(data);
291
+ }
292
+ bt.buildComplete(table, wo);
293
+ };
294
+
295
+ /* ==== Object example ====
296
+ data : {
297
+ headers : [
298
+ [
299
+ { text: 'First Name', class: 'fname', width: '20%' }, // row 1 cell 1
300
+ 'Last Name',
301
+ { text: 'Age', class: 'age', 'data-sorter' : false },
302
+ 'Total',
303
+ { text: 'Discount', class : 'sorter-false' },
304
+ { text: 'Date', class : 'date' } // row 1 cell 6
305
+ ]
306
+ ],
307
+ footers : 'clone', // clone headers or assign array like headers
308
+ rows : [
309
+ // TBODY 1
310
+ [ 'Peter', 'Parker', 28, '$9.99', '20%', 'Jul 6, 2006 8:14 AM' ], // row 1
311
+ [ 'John', 'Hood', 33, '$19.99', '25%', 'Dec 10, 2002 5:14 AM' ], // row 2
312
+ [ 'Clark', 'Kent', 18, '$15.89', '44%', 'Jan 12, 2003 11:14 AM' ], // row 3
313
+
314
+ // TBODY 2
315
+ { newTbody: true, class: 'tablesorter-infoOnly' },
316
+ { cells : [ { text: 'Info Row', colSpan: 6 } ] }, // row 4
317
+
318
+ // TBODY 3
319
+ { newTbody: true },
320
+ [ 'Bruce', 'Evans', 22, '$13.19', '11%', 'Jan 18, 2007 9:12 AM' ], // row 5
321
+ [ 'Brice', 'Almighty', 45, '$153.19', '44%', 'Jan 18, 2001 9:12 AM' ], // row 6
322
+
323
+ { class: 'specialRow', // row 7
324
+ cells: [
325
+ { text: 'Fred', class: 'fname' },
326
+ { text: 'Smith', class: 'lname' },
327
+ { text: 18, class: 'age', 'data-info': 'fake ID!, he is really 16' },
328
+ { text: '$22.44', class: 'total' },
329
+ { text: '8%', class: 'discount' },
330
+ { text: 'Aug 20, 2012 10:15 AM', class: 'date' }
331
+ ],
332
+ 'data-info' : 'This row likes turtles'
333
+ }
334
+ ]
335
+ }
336
+ */
337
+ bt.object = function(table, data, wo) {
338
+ // "rows"
339
+ var j, l, t, $c, $t, $tb, $tr,
340
+ c = table.config,
341
+ kh = wo.build_objectHeaderKey,
342
+ kr = wo.build_objectRowKey,
343
+ h = data.hasOwnProperty(kh) && !$.isEmptyObject(data.kh) ? data.kh : data.hasOwnProperty('headers') ? data.headers : false,
344
+ r = data.hasOwnProperty(kr) && !$.isEmptyObject(data.kr) ? data.kr : data.hasOwnProperty('rows') ? data.rows : false;
345
+
346
+ if (!h || !r || h.length === 0 || r.length === 0) {
347
+ if (c.debug) { ts.log('aborting build table widget, missing data for object build'); }
348
+ return false;
349
+ }
350
+
351
+ $c = $('<colgroup>');
352
+ $t = $('<table><thead/></table>');
353
+
354
+ // Build thead
355
+ // h = [ ['headerRow1Cell1', 'headerRow1Cell2', ... 'headerRow1CellN' ], ['headerRow2Cell1', ... ] ]
356
+ // or h = [ [ { text: 'firstCell', class: 'fc', width: '20%' }, ..., { text: 'last Cell' } ], [ /* second row */ ] ]
357
+ $.each(h, function(i, d){
358
+ $tr = $('<tr>').appendTo( $t.find('thead') );
359
+ l = d.length; // header row
360
+ for ( j = 0; j < l; j++ ) {
361
+ // cell(cellData, widgetOptions, 'th', first row)
362
+ t = bt.build.cell(d[j], wo, 'th', j, i === 0);
363
+ if (t[0] && t[0].length) { t[0].appendTo( $tr ); } // add cell
364
+ if (i === 0 && t[1]) { t[1].appendTo( $c ); } // add col to colgroup
365
+ }
366
+ });
367
+ if ($c.find('col[style]').length) {
368
+ // add colgroup if it contains col elements
369
+ $t.prepend( $c );
370
+ }
371
+
372
+ $tb = $('<tbody>');
373
+ // Build tbody
374
+ $.each(r, function(i, d){
375
+ t = $.type(d) === 'object';
376
+ // add new tbody
377
+ if (t && d.newTbody) {
378
+ $tb = $('<tbody>').appendTo( $t );
379
+ for (j in d) {
380
+ if (d.hasOwnProperty(j) && j !== 'newTbody'){
381
+ $tb.attr(j, d[j]);
382
+ }
383
+ }
384
+ } else {
385
+ if (i === 0) {
386
+ // add tbody, if the first item in the object isn't a call for a new tbody
387
+ $tb.appendTo( $t );
388
+ }
389
+
390
+ $tr = $('<tr>').appendTo( $tb );
391
+ if (t) {
392
+ // row defined by object
393
+ for (j in d) {
394
+ if (d.hasOwnProperty(j) && j !== wo.build_objectCellKey){
395
+ $tr.attr(j, d[j]);
396
+ }
397
+ }
398
+ if (d.hasOwnProperty(wo.build_objectCellKey)) {
399
+ // cells contains each cell info
400
+ d = d.cells;
401
+ }
402
+ }
403
+
404
+ l = d.length;
405
+ for ( j = 0; j < l; j++ ) {
406
+ // cell(cellData, widgetOptions, 'td')
407
+ $c = bt.build.cell(d[j], wo, 'td', j);
408
+ if ($c[0] && $c[0].length) { $c[0].appendTo( $tr ); } // add cell
409
+ }
410
+ }
411
+ });
412
+
413
+ // add footer
414
+ if (data.hasOwnProperty(wo.build_objectFooterKey)) {
415
+ t = data[wo.build_objectFooterKey];
416
+ if (t === 'clone') {
417
+ $c = $t.find('thead').html();
418
+ $t.append('<tfoot>' + $c + '</tfoot>');
419
+ } else {
420
+ $c = $('<tfoot>').appendTo( $t );
421
+ $.each(t, function(i, d) {
422
+ $tr = $('<tr>').appendTo( $c );
423
+ l = d.length; // footer cells
424
+ for ( j = 0; j < l; j++ ) {
425
+ // cell(cellData, widgetOptions, 'th')
426
+ $tb = bt.build.cell(d[j], wo, 'th', j);
427
+ if ($tb[0] && $tb[0].length) { $tb[0].appendTo( $tr ); } // add cell
428
+ }
429
+ });
430
+ }
431
+ }
432
+
433
+ $(table).html( $t.html() );
434
+ bt.buildComplete(table, wo);
435
+ };
436
+
437
+ bt.ajax = bt.json = function(table, data, wo) {
438
+ return bt.object(table, data, wo);
439
+ };
440
+
441
+ })(jQuery);