jquery-tablesorter 1.10.10 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,272 @@
1
+ /* Output widget (beta) for TableSorter 4/14/2014 (v2.16.0)
2
+ * Requires tablesorter v2.8+ and jQuery 1.7+
3
+ * Modified from:
4
+ * HTML Table to CSV: http://www.kunalbabre.com/projects/table2CSV.php (License unknown?)
5
+ * Download-File-JS: https://github.com/PixelsCommander/Download-File-JS (http://www.apache.org/licenses/LICENSE-2.0)
6
+ */
7
+ /*jshint browser:true, jquery:true, unused:false */
8
+ /*global jQuery: false */
9
+ ;(function($){
10
+ "use strict";
11
+
12
+ var ts = $.tablesorter,
13
+
14
+ output = ts.output = {
15
+
16
+ event : 'outputTable',
17
+
18
+ // wrap line breaks & tabs in quotes
19
+ regexQuote : /([\n\t]|<[^<]+>)/, // test
20
+ regexBR : /(<br([\s\/])?>|\n)/g, // replace
21
+ regexIMG : /<img[^>]+alt\s*=\s*['"]([^'"]+)['"][^>]*>/i, // match
22
+ regexHTML : /<[^<]+>/g, // replace
23
+
24
+ replaceCR : '\\n',
25
+ replaceTab : '\\t',
26
+
27
+ popupTitle : 'Output',
28
+ popupStyle : 'width:100%;height:100%;', // for textarea
29
+ message : 'Your device does not support downloading. Please try again in desktop browser.',
30
+
31
+ init : function(c) {
32
+ c.$table
33
+ .off(output.event)
34
+ .on(output.event, function(){
35
+ // explicitly use table.config.widgetOptions because we want
36
+ // the most up-to-date values; not the "wo" from initialization
37
+ output.process(c, c.widgetOptions);
38
+ });
39
+ },
40
+
41
+ processRow: function(c, $rows, isHeader, isJSON) {
42
+ var $this, row, col, rowlen, collen, txt,
43
+ wo = c.widgetOptions,
44
+ tmpRow = [],
45
+ addSpanIndex = isHeader && isJSON && wo.output_headerRows && $.isFunction(wo.output_callbackJSON),
46
+ rowIndex = 0,
47
+ cellIndex = 0;
48
+ $rows.each(function(rowIndex) {
49
+ if (!tmpRow[rowIndex]) { tmpRow[rowIndex] = []; }
50
+ cellIndex = 0;
51
+ $(this).children().each(function(){
52
+ $this = $(this);
53
+ // process rowspans
54
+ if ($this.filter('[rowspan]').length) {
55
+ rowlen = parseInt( $this.attr('rowspan'), 10) - 1;
56
+ txt = output.formatData( wo, $this.attr(wo.output_dataAttrib) || $this.html(), isHeader );
57
+ for (row = 1; row <= rowlen; row++) {
58
+ if (!tmpRow[rowIndex + row]) { tmpRow[rowIndex + row] = []; }
59
+ tmpRow[rowIndex + row][cellIndex] = txt;
60
+ }
61
+ }
62
+ // process colspans
63
+ if ($this.filter('[colspan]').length) {
64
+ collen = parseInt( $this.attr('colspan'), 10) - 1;
65
+ txt = output.formatData( wo, $this.attr(wo.output_dataAttrib) || $this.html(), isHeader );
66
+ for (col = 1; col <= collen; col++) {
67
+ // if we're processing the header & making JSON, the header names need to be unique
68
+ if ($this.filter('[rowspan]').length) {
69
+ rowlen = parseInt( $this.attr('rowspan'), 10);
70
+ for (row = 0; row < rowlen; row++) {
71
+ if (!tmpRow[rowIndex + row]) { tmpRow[rowIndex + row] = []; }
72
+ tmpRow[rowIndex + row][cellIndex + col] = addSpanIndex ?
73
+ wo.output_callbackJSON($this, txt, cellIndex + col) || txt + '(' + (cellIndex + col) + ')' : txt;
74
+ }
75
+ } else {
76
+ tmpRow[rowIndex][cellIndex + col] = addSpanIndex ?
77
+ wo.output_callbackJSON($this, txt, cellIndex + col) || txt + '(' + (cellIndex + col) + ')' : txt;
78
+ }
79
+ }
80
+ }
81
+
82
+ // don't include hidden columns
83
+ if ( $this.css('display') !== 'none' ) {
84
+ // skip column if already defined
85
+ while (tmpRow[rowIndex][cellIndex]) { cellIndex++; }
86
+ tmpRow[rowIndex][cellIndex] = tmpRow[rowIndex][cellIndex] ||
87
+ output.formatData( wo, $this.attr(wo.output_dataAttrib) || $this.html(), isHeader );
88
+ cellIndex++;
89
+ }
90
+ });
91
+ });
92
+ return tmpRow;
93
+ },
94
+
95
+ process : function(c, wo) {
96
+ var mydata, $this, $rows, headers, csvData, len,
97
+ hasStringify = window.JSON && JSON.hasOwnProperty('stringify'),
98
+ indx = 0,
99
+ tmpData = (wo.output_separator || ',').toLowerCase(),
100
+ outputJSON = tmpData === 'json',
101
+ outputArray = tmpData === 'array',
102
+ separator = outputJSON || outputArray ? ',' : wo.output_separator,
103
+ $el = c.$table;
104
+ // regex to look for the set separator or HTML
105
+ wo.output_regex = new RegExp('(' + (/\\/.test(separator) ? '\\' : '' ) + separator + ')' );
106
+
107
+ // get header cells
108
+ $this = $el.find('thead tr:visible').not('.' + (ts.css.filterRow || 'tablesorter-filter-row') );
109
+ headers = output.processRow(c, $this, true, outputJSON);
110
+
111
+ // all tbody rows
112
+ $rows = $el.children('tbody').children('tr');
113
+ // get (f)iltered, (v)isible or all rows (look for the first letter only)
114
+ $rows = /f/.test(wo.output_saveRows) ? $rows.not('.' + (wo.filter_filteredRow || 'filtered') ) :
115
+ /v/.test(wo.output_saveRows) ? $rows.filter(':visible') : $rows;
116
+
117
+ // process to array of arrays
118
+ csvData = output.processRow(c, $rows);
119
+ len = headers.length;
120
+
121
+ if (outputJSON) {
122
+ tmpData = [];
123
+ $.each( csvData, function(indx, val){
124
+ // multiple header rows & output_headerRows = true, pick the last row...
125
+ tmpData.push( output.row2Hash( headers[ (len > 1 && wo.output_headerRows) ? indx % len : len - 1], val ) );
126
+ });
127
+ // requires JSON stringify; if it doesn't exist, the output will show [object Object],... in the output window
128
+ mydata = hasStringify ? JSON.stringify(tmpData) : tmpData;
129
+ } else {
130
+ tmpData = output.row2CSV(wo, wo.output_headerRows ? headers : [ headers[ (len > 1 && wo.output_headerRows) ? indx % len : len - 1] ], outputArray)
131
+ .concat( output.row2CSV(wo, csvData, outputArray) );
132
+ // stringify the array; if stringify doesn't exist the array will be flattened
133
+ mydata = outputArray && hasStringify ? JSON.stringify(tmpData) : tmpData.join('\n');
134
+ }
135
+
136
+ // callback; if true returned, continue processing
137
+ if (!wo.output_callback(mydata)) { return; }
138
+
139
+ if ( /p/.test( (wo.output_delivery || '').toLowerCase() ) ) {
140
+ output.popup(mydata, wo.output_popupStyle, outputJSON || outputArray);
141
+ } else {
142
+ output.download(wo, mydata);
143
+ }
144
+
145
+ }, // end process
146
+
147
+ row2CSV : function(wo, tmpRow, outputArray) {
148
+ var tmp, rowIndex,
149
+ csvData = [],
150
+ rowLen = tmpRow.length;
151
+ for (rowIndex = 0; rowIndex < rowLen; rowIndex++) {
152
+ // remove any blank rows
153
+ tmp = tmpRow[rowIndex].join('').replace(/\"/g,'');
154
+ if (tmpRow[rowIndex].length > 0 && tmp !== '') {
155
+ csvData[csvData.length] = outputArray ? tmpRow[rowIndex] : tmpRow[rowIndex].join(wo.output_separator);
156
+ }
157
+ }
158
+ return csvData;
159
+ },
160
+
161
+ row2Hash : function(keys, values) {
162
+ var json = {};
163
+ $.each(values, function(indx, val) {
164
+ if ( indx < keys.length ) {
165
+ json[ keys[indx] ] = val;
166
+ }
167
+ });
168
+ return json;
169
+ },
170
+
171
+ formatData : function(wo, input, isHeader) {
172
+ var txt,
173
+ quotes = (wo.output_separator || ',').toLowerCase(),
174
+ separator = quotes === 'json' || quotes === 'array',
175
+ // replace " with “ if undefined
176
+ result = input.replace(/\"/g, wo.output_replaceQuote || '\u201c');
177
+ // replace line breaks with \\n & tabs with \\t
178
+ result = result.replace(output.regexBR, output.replaceCR).replace(/\t/g, output.replaceTab);
179
+ // extract img alt text
180
+ txt = result.match(output.regexIMG);
181
+ if (!wo.output_includeHTML && txt !== null) {
182
+ result = txt[1];
183
+ }
184
+ // replace/remove html
185
+ result = wo.output_includeHTML && !isHeader ? result : result.replace(output.regexHTML, '');
186
+ result = wo.output_trimSpaces || isHeader ? $.trim(result) : result;
187
+ // JSON & array outputs don't need quotes
188
+ quotes = separator ? false : wo.output_wrapQuotes || wo.output_regex.test(result) || output.regexQuote.test(result);
189
+ return quotes ? '"' + result + '"' : result;
190
+ },
191
+
192
+ popup : function(data, style, wrap) {
193
+ var generator = window.open('', output.popupTitle, style);
194
+ generator.document.write(
195
+ '<html><head><title>' + output.popupTitle + '</title></head><body>' +
196
+ '<textarea wrap="' + (wrap ? 'on' : 'off') + '" style="' + output.popupStyle + '">' + data + '\n</textarea>' +
197
+ '</body></html>'
198
+ );
199
+ generator.document.close();
200
+ generator.focus();
201
+ // select all text and focus within the textarea in the popup
202
+ // $(generator.document).find('textarea').select().focus();
203
+ return true;
204
+ },
205
+
206
+ // modified from https://github.com/PixelsCommander/Download-File-JS
207
+ download : function (wo, data){
208
+ var e, link,
209
+ processedData = 'data:text/csv;charset=utf8,' + encodeURIComponent(data);
210
+
211
+ // iOS devices do not support downloading. We have to inform user about this.
212
+ if (/(iP)/g.test(navigator.userAgent)) {
213
+ alert(output.message);
214
+ return false;
215
+ }
216
+ // If in Chrome or Safari - download via virtual link click
217
+ if ( /(chrome|safari)/.test(navigator.userAgent.toLowerCase()) ) {
218
+ // Creating new link node.
219
+ link = document.createElement('a');
220
+ link.href = processedData;
221
+ link.download = wo.output_saveFileName;
222
+ // Dispatching click event.
223
+ if (document.createEvent) {
224
+ e = document.createEvent('MouseEvents');
225
+ e.initEvent('click', true, true);
226
+ link.dispatchEvent(e);
227
+ return true;
228
+ }
229
+ }
230
+ // Force file download (whether supported by server).
231
+ processedData += '?download';
232
+ window.open(processedData, '_self');
233
+ return true;
234
+ },
235
+
236
+ remove : function(c) {
237
+ c.$table.off(output.event);
238
+ }
239
+
240
+ };
241
+
242
+ ts.addWidget({
243
+ id: "output",
244
+ options: {
245
+ output_separator : ',', // set to "json", "array" or any separator
246
+ output_dataAttrib : 'data-name', // header attrib containing modified header name
247
+ output_headerRows : false, // if true, include multiple header rows (JSON only)
248
+ output_delivery : 'popup', // popup, download
249
+ output_saveRows : 'filtered', // all, visible or filtered
250
+ output_replaceQuote : '\u201c;', // left double quote
251
+ output_includeHTML : false,
252
+ output_trimSpaces : true,
253
+ output_wrapQuotes : false,
254
+ output_popupStyle : 'width=500,height=300',
255
+ output_saveFileName : 'mytable.csv',
256
+ // callback executed when processing completes
257
+ // return true to continue download/output
258
+ // return false to stop delivery & do something else with the data
259
+ output_callback : function(data){ return true; },
260
+ // JSON callback executed when a colspan is encountered in the header
261
+ output_callbackJSON : function($cell, txt, cellIndex) { return txt + '(' + (cellIndex + col) + ')'; }
262
+ },
263
+ init: function(table, thisWidget, c) {
264
+ output.init(c);
265
+ },
266
+ remove: function(table, c){
267
+ output.remove(c);
268
+ }
269
+
270
+ });
271
+
272
+ })(jQuery);
@@ -1,4 +1,4 @@
1
- /* Pager widget (beta) for TableSorter 4/10/2014 (v2.15.14) */
1
+ /* Pager widget (beta) for TableSorter 4/23/2014 (v2.16.0) */
2
2
  /*jshint browser:true, jquery:true, unused:false */
3
3
  ;(function($){
4
4
  "use strict";
@@ -19,6 +19,10 @@ ts.addWidget({
19
19
  // starting page of the pager (zero based index)
20
20
  pager_startPage: 0,
21
21
 
22
+ // reset pager after filtering; set to desired page #
23
+ // set to false to not change page at filter start
24
+ pager_pageReset: 0,
25
+
22
26
  // Number of visible rows
23
27
  pager_size: 10,
24
28
 
@@ -164,6 +168,10 @@ tsp = ts.pager = {
164
168
  p.size = ( isNaN(t.size) ? p.size : t.size ) || 10;
165
169
  $.data(table, 'pagerLastSize', p.size);
166
170
  }
171
+
172
+ // skipped rows
173
+ p.regexRows = new RegExp('(' + (wo.filter_filteredRow || 'filtered') + '|' + c.selectorRemove.substring(1) + '|' + c.cssChildRow + ')');
174
+
167
175
  // clear initialized flag
168
176
  p.initialized = false;
169
177
  // before initialization event
@@ -210,13 +218,17 @@ tsp = ts.pager = {
210
218
  .unbind('filterStart filterEnd sortEnd disable enable destroy update updateRows updateAll addRows pageSize '.split(' ').join('.pager '))
211
219
  .bind('filterStart.pager', function(e, filters) {
212
220
  p.currentFilters = filters;
213
- p.page = 0; // fixes #456
221
+ // don't change page is filters are the same (pager updating, etc)
222
+ if (wo.pager_pageReset !== false && (c.lastCombinedFilter || '') !== (filters || []).join('')) {
223
+ p.page = wo.pager_pageReset; // fixes #456 & #565
224
+ }
214
225
  })
215
226
  // update pager after filter widget completes
216
227
  .bind('filterEnd.pager sortEnd.pager', function() {
217
228
  if (p.initialized) {
218
- tsp.moveToPage(table, p, false);
229
+ // update page display first, so we update p.filteredPages
219
230
  tsp.updatePageDisplay(table, c, false);
231
+ tsp.moveToPage(table, p, false);
220
232
  tsp.fixHeight(table, c);
221
233
  }
222
234
  })
@@ -315,17 +327,25 @@ tsp = ts.pager = {
315
327
  },
316
328
 
317
329
  updatePageDisplay: function(table, c, completed) {
318
- var i, pg, s, out,
330
+ var i, pg, s, out, regex,
319
331
  wo = c.widgetOptions,
320
332
  p = c.pager,
321
333
  f = c.$table.hasClass('hasFilters') && !wo.pager_ajaxUrl,
322
- t = (c.widgetOptions && c.widgetOptions.filter_filteredRow || 'filtered') + ',' + c.selectorRemove +
323
- (wo.pager_countChildRows ? '' : ',.' + c.cssChildRow),
334
+ t = [],
324
335
  sz = p.size || 10; // don't allow dividing by zero
336
+ t = [ wo && wo.filter_filteredRow || 'filtered', c.selectorRemove ];
337
+ if (wo.pager_countChildRows) { t.push(c.cssChildRow); }
338
+ regex = new RegExp( '(' + t.join('|') + ')' );
325
339
  p.$size.add(p.$goto).removeClass(wo.pager_css.disabled).removeAttr('disabled').attr('aria-disabled', 'false');
326
340
  p.totalPages = Math.ceil( p.totalRows / sz ); // needed for "pageSize" method
327
- p.filteredRows = (f) ? c.$tbodies.eq(0).children('tr').not('.' + t).length : p.totalRows;
328
- p.filteredPages = (f) ? Math.ceil( p.filteredRows / sz ) || 1 : p.totalPages;
341
+ p.filteredRows = (f) ? 0 : p.totalRows;
342
+ p.filteredPages = p.totalPages;
343
+ if (f) {
344
+ $.each(c.cache[0].normalized, function(i, el) {
345
+ p.filteredRows += p.regexRows.test(el[c.columns].$row[0].className) ? 0 : 1;
346
+ });
347
+ p.filteredPages = Math.ceil( p.filteredRows / sz ) || 0;
348
+ }
329
349
  if ( Math.min( p.totalPages, p.filteredPages ) >= 0 ) {
330
350
  t = (p.size * p.page > p.filteredRows);
331
351
  p.startRow = (t) ? 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1);
@@ -579,9 +599,9 @@ tsp = ts.pager = {
579
599
  }
580
600
  tsp.renderAjax(data, table, c);
581
601
  $doc.unbind('ajaxError.pager');
582
- if (typeof p.oldAjaxSuccess === 'function') {
583
- p.oldAjaxSuccess(data);
584
- }
602
+ if (typeof p.oldAjaxSuccess === 'function') {
603
+ p.oldAjaxSuccess(data);
604
+ }
585
605
  };
586
606
  if (c.debug) {
587
607
  ts.log('ajax initialized', wo.pager_ajaxObject);
@@ -632,13 +652,14 @@ tsp = ts.pager = {
632
652
  },
633
653
 
634
654
  renderTable: function(table, rows) {
635
- var i, $tb,
655
+ var $tb, index, count, added,
636
656
  c = table.config,
637
657
  p = c.pager,
638
658
  wo = c.widgetOptions,
659
+ f = c.$table.hasClass('hasFilters'),
639
660
  l = rows && rows.length || 0, // rows may be undefined
640
661
  s = ( p.page * p.size ),
641
- e = ( s + p.size );
662
+ e = p.size;
642
663
  if ( l < 1 ) { return; } // empty table, abort!
643
664
  if ( p.page >= p.totalPages ) {
644
665
  // lets not render the table more than once
@@ -650,13 +671,22 @@ tsp = ts.pager = {
650
671
  if ( !wo.pager_removeRows ) {
651
672
  tsp.hideRows(table, c);
652
673
  } else {
653
- if ( e > rows.length ) {
654
- e = rows.length;
655
- }
656
674
  ts.clearTableBody(table);
657
675
  $tb = ts.processTbody(table, c.$tbodies.eq(0), true);
658
- for ( i = s; i < e; i++ ) {
659
- $tb.append(rows[i]);
676
+ // not filtered, start from the calculated starting point (s)
677
+ // if filtered, start from zero
678
+ index = f ? 0 : s;
679
+ count = f ? 0 : s;
680
+ added = 0;
681
+ while (added < e && index < rows.length) {
682
+ if (!f || !/filtered/.test(rows[index][0].className)){
683
+ count++;
684
+ if (count > s && added <= e) {
685
+ added++;
686
+ $tb.append(rows[index]);
687
+ }
688
+ }
689
+ index++;
660
690
  }
661
691
  ts.processTbody(table, $tb, false);
662
692
  }
@@ -785,6 +815,7 @@ tsp = ts.pager = {
785
815
  p.$container.hide(); // hide pager
786
816
  c.appender = null; // remove pager appender function
787
817
  p.initialized = false;
818
+ delete table.config.rowsCopy;
788
819
  c.$table.unbind('destroy.pager sortEnd.pager filterEnd.pager enable.pager disable.pager');
789
820
  if (ts.storage) {
790
821
  ts.storage(table, c.widgetOptions.pager_storageKey, '');
@@ -0,0 +1,179 @@
1
+ /* table reflow widget (beta) for TableSorter 3/22/2014 (v2.16.0)
2
+ * Requires tablesorter v2.8+ and jQuery 1.7+
3
+ * Also, this widget requires the following default css (modify as desired)
4
+
5
+ / * REQUIRED CSS: change your reflow breakpoint here (35em below) * /
6
+ @media ( max-width: 35em ) {
7
+ .ui-table-reflow td,
8
+ .ui-table-reflow th {
9
+ -webkit-box-sizing: border-box;
10
+ -moz-box-sizing: border-box;
11
+ box-sizing: border-box;
12
+ float: right;
13
+ / * if not using the stickyHeaders widget (not the css3 version)
14
+ * the "!important" flag, and "height: auto" can be removed * /
15
+ width: 100% !important;
16
+ height: auto !important;
17
+ }
18
+ / * reflow widget * /
19
+ .ui-table-reflow tbody td[data-title]:before {
20
+ color: #469;
21
+ font-size: .9em;
22
+ content: attr(data-title);
23
+ float: left;
24
+ width: 50%;
25
+ white-space: pre-wrap;
26
+ text-align: bottom;
27
+ display: inline-block;
28
+ }
29
+ / * reflow2 widget * /
30
+ table.ui-table-reflow .ui-table-cell-label.ui-table-cell-label-top {
31
+ display: block;
32
+ padding: .4em 0;
33
+ margin: .4em 0;
34
+ text-transform: uppercase;
35
+ font-size: .9em;
36
+ font-weight: 400;
37
+ }
38
+ table.ui-table-reflow .ui-table-cell-label {
39
+ padding: .4em;
40
+ min-width: 30%;
41
+ display: inline-block;
42
+ margin: -.4em 1em -.4em -.4em;
43
+ }
44
+ }
45
+ .ui-table-reflow .ui-table-cell-label {
46
+ display: none;
47
+ }
48
+
49
+ */
50
+ /*jshint browser:true, jquery:true, unused:false */
51
+ /*global jQuery: false */
52
+ ;(function($){
53
+ "use strict";
54
+
55
+ var ts = $.tablesorter,
56
+
57
+ tablereflow = {
58
+ // simple reflow
59
+ // add data-attribute to each cell which shows when media query is active
60
+ // this widget DOES NOT WORK on a table with multiple thead rows
61
+ init : function(table, c, wo) {
62
+ var $this,
63
+ title = wo.reflow_dataAttrib,
64
+ header = wo.reflow_headerAttrib,
65
+ headers = [];
66
+ c.$table
67
+ .addClass(wo.reflow_className)
68
+ .off('refresh.tsreflow updateComplete.tsreflow2')
69
+ // emulate jQuery Mobile refresh
70
+ // https://api.jquerymobile.com/table-reflow/#method-refresh
71
+ .on('refresh.tsreflow updateComplete.tsreflow2', function(){
72
+ tablereflow.init(table, c, wo);
73
+ });
74
+ c.$headers.each(function(){
75
+ $this = $(this);
76
+ headers.push( $this.attr(header) || $this.text() );
77
+ });
78
+ c.$tbodies.children().each(function(){
79
+ $(this).children().each(function(i){
80
+ $(this).attr(title, headers[i]);
81
+ });
82
+ });
83
+ },
84
+ init2: function(table, c, wo) {
85
+ var $this, $tbody, i, $hdr, txt, len,
86
+ cols = c.columns,
87
+ header = wo.reflow2_headerAttrib,
88
+ headers = [];
89
+ c.$table
90
+ .addClass(wo.reflow2_className)
91
+ .off('refresh.tsreflow2 updateComplete.tsreflow2')
92
+ // emulate jQuery Mobile refresh
93
+ // https://api.jquerymobile.com/table-reflow/#method-refresh
94
+ .on('refresh.tsreflow2 updateComplete.tsreflow2', function(){
95
+ tablereflow.init2(table, c, wo);
96
+ });
97
+
98
+ // add <b> to every table cell with thead cell contents
99
+ for (i = 0; i < cols; i++) {
100
+ $hdr = c.$headers.filter('[data-column="' + i + '"]');
101
+ if ($hdr.length > 1) {
102
+ txt = [];
103
+ $hdr.each(function(){
104
+ $this = $(this);
105
+ if (!$this.hasClass(wo.reflow2_classIgnore)) {
106
+ txt.push( $this.attr(header) || $this.text() );
107
+ }
108
+ });
109
+ } else {
110
+ txt = [ $hdr.attr(header) || $hdr.text() ];
111
+ }
112
+ headers.push( txt );
113
+ }
114
+ // include "remove-me" class so these additional elements are removed before updating
115
+ txt = '<b class="' + c.selectorRemove.slice(1) + ' ' + wo.reflow2_labelClass;
116
+ c.$tbodies.children().each(function(){
117
+ $tbody = ts.processTbody(table, $(this), true);
118
+ $tbody.children().each(function(j){
119
+ $this = $(this);
120
+ len = headers[j].length
121
+ i = len - 1;
122
+ while (i >= 0) {
123
+ $this.prepend(txt + (i === 0 && len > 1 ? ' ' + wo.reflow2_labelTop : '') + '">' + headers[j][i] + '</b>');
124
+ i--;
125
+ }
126
+ });
127
+ ts.processTbody(table, $tbody, false);
128
+ });
129
+ },
130
+ remove : function(table, c, wo) {
131
+ c.$table.removeClass(wo.reflow_className);
132
+ },
133
+ remove2 : function(table, c, wo) {
134
+ c.$table.removeClass(wo.reflow2_className);
135
+ }
136
+ };
137
+
138
+ ts.addWidget({
139
+ id: "reflow",
140
+ options: {
141
+ // class name added to make it responsive (class name within media query)
142
+ reflow_className : 'ui-table-reflow',
143
+ // header attribute containing modified header name
144
+ reflow_headerAttrib : 'data-name',
145
+ // data attribute added to each tbody cell
146
+ reflow_dataAttrib : 'data-title'
147
+ },
148
+ init: function(table, thisWidget, c, wo) {
149
+ tablereflow.init(table, c, wo);
150
+ },
151
+ remove: function(table, c, wo){
152
+ tablereflow.remove(table, c, wo);
153
+ }
154
+ });
155
+
156
+ ts.addWidget({
157
+ id: "reflow2",
158
+ options: {
159
+ // class name added to make it responsive (class name within media query)
160
+ reflow2_className : 'ui-table-reflow',
161
+ // ignore header cell content with this class name
162
+ reflow2_classIgnore : 'ui-table-reflow-ignore',
163
+ // header attribute containing modified header name
164
+ reflow2_headerAttrib : 'data-name',
165
+ // class name applied to thead labels
166
+ reflow2_labelClass : 'ui-table-cell-label',
167
+ // class name applied to first row thead label
168
+ reflow2_labelTop : 'ui-table-cell-label-top'
169
+ },
170
+ init: function(table, thisWidget, c, wo) {
171
+ tablereflow.init2(table, c, wo);
172
+ },
173
+ remove: function(table, c, wo){
174
+ tablereflow.remove2(table, c, wo);
175
+ }
176
+ });
177
+
178
+
179
+ })(jQuery);