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.
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);