jquery-tablesorter 1.16.5 → 1.17.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/jquery-tablesorter/version.rb +1 -1
  4. data/vendor/assets/javascripts/jquery-tablesorter/addons/pager/jquery.tablesorter.pager.js +38 -27
  5. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.combined.js +1104 -839
  6. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +167 -123
  7. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets.js +938 -717
  8. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date.js +5 -5
  9. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-globalize.js +46 -0
  10. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-input-select.js +96 -72
  11. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-named-numbers.js +6 -5
  12. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-network.js +26 -17
  13. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-columns.js +1 -1
  14. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-editable.js +95 -42
  15. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-filter.js +921 -700
  16. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-grouping.js +5 -3
  17. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-math.js +22 -20
  18. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-output.js +7 -5
  19. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-pager.js +40 -29
  20. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-resizable.js +6 -6
  21. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-saveSort.js +1 -1
  22. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-scroller.js +53 -31
  23. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-stickyHeaders.js +1 -1
  24. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-storage.js +1 -1
  25. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-uitheme.js +1 -1
  26. data/vendor/assets/stylesheets/jquery-tablesorter/theme.black-ice.css +2 -1
  27. data/vendor/assets/stylesheets/jquery-tablesorter/theme.blue.css +2 -1
  28. data/vendor/assets/stylesheets/jquery-tablesorter/theme.bootstrap.css +2 -1
  29. data/vendor/assets/stylesheets/jquery-tablesorter/theme.bootstrap_2.css +8 -6
  30. data/vendor/assets/stylesheets/jquery-tablesorter/theme.dark.css +2 -1
  31. data/vendor/assets/stylesheets/jquery-tablesorter/theme.default.css +1 -1
  32. metadata +3 -2
@@ -2,12 +2,12 @@
2
2
  /* Extract dates using popular natural language date parsers */
3
3
  /*jshint jquery:true */
4
4
  ;(function($){
5
- "use strict";
5
+ 'use strict';
6
6
 
7
7
  /*! Sugar (http://sugarjs.com/dates#comparing_dates) */
8
8
  /* demo: http://jsfiddle.net/Mottie/abkNM/4163/ */
9
9
  $.tablesorter.addParser({
10
- id: "sugar",
10
+ id: 'sugar',
11
11
  is: function() {
12
12
  return false;
13
13
  },
@@ -15,13 +15,13 @@
15
15
  var date = Date.create ? Date.create(s) : s ? new Date(s) : s;
16
16
  return date instanceof Date && isFinite(date) ? date.getTime() : s;
17
17
  },
18
- type: "numeric"
18
+ type: 'numeric'
19
19
  });
20
20
 
21
21
  /*! Datejs (http://www.datejs.com/) */
22
22
  /* demo: http://jsfiddle.net/Mottie/abkNM/4164/ */
23
23
  $.tablesorter.addParser({
24
- id: "datejs",
24
+ id: 'datejs',
25
25
  is: function() {
26
26
  return false;
27
27
  },
@@ -29,7 +29,7 @@
29
29
  var date = Date.parse ? Date.parse(s) : s ? new Date(s) : s;
30
30
  return date instanceof Date && isFinite(date) ? date.getTime() : s;
31
31
  },
32
- type: "numeric"
32
+ type: 'numeric'
33
33
  });
34
34
 
35
35
  })(jQuery);
@@ -0,0 +1,46 @@
1
+ /*! Parser: jQuery Globalize - updated 5/17/2015 (v2.22.0) */
2
+ /* Extract localized data using jQuery's Globalize parsers; set
3
+ Globalize.locale( 'xx' ) prior to initializing tablesorter! */
4
+ /*jshint jquery:true */
5
+ ;( function( $ ) {
6
+ 'use strict';
7
+
8
+ /*! jQuery Globalize date parser (https://github.com/jquery/globalize#date-module) */
9
+ /* demo: http://jsfiddle.net/Mottie/0j18Lw8r/ */
10
+ $.tablesorter.addParser({
11
+ id: 'globalize-date',
12
+ is: function () {
13
+ return false;
14
+ },
15
+ format: function ( str, table, cell, cellIndex ) {
16
+ var c = table.config,
17
+ // add options to 'config.globalize' for all columns --> globalize : { skeleton: 'GyMMMd' }
18
+ // or per column by using the column index --> globalize : { 0 : { datetime: 'medium' } }
19
+ options = c.globalize && ( c.globalize[ cellIndex ] || c.globalize ) || {},
20
+ date = Globalize && Globalize.dateParser ? Globalize.dateParser( options )( str ) :
21
+ str ? new Date( str ) : str;
22
+ return date instanceof Date && isFinite( date ) ? date.getTime() : str;
23
+ },
24
+ type: 'numeric'
25
+ });
26
+
27
+ /*! jQuery Globalize number parser (https://github.com/jquery/globalize#number-module) */
28
+ /* demo: http://jsfiddle.net/Mottie/0j18Lw8r/ */
29
+ $.tablesorter.addParser({
30
+ id: 'globalize-number',
31
+ is: function () {
32
+ return false;
33
+ },
34
+ format: function ( str, table, cell, cellIndex ) {
35
+ var c = table.config,
36
+ // add options to 'config.globalize' for all columns --> globalize : { skeleton: 'GyMMMd' }
37
+ // or per column by using the column index --> globalize : { 0 : { datetime: 'medium' } }
38
+ options = c.globalize && ( c.globalize[ cellIndex ] || c.globalize ) || {},
39
+ num = Globalize && Globalize.numberParser ? Globalize.numberParser( options )( str ) :
40
+ str ? $.tablesorter.formatFloat( ( str || '' ).replace( /[^\w,. \-()]/g, '' ), table ) : str;
41
+ return str && typeof num === 'number' ? num : str;
42
+ },
43
+ type: 'numeric'
44
+ });
45
+
46
+ })( jQuery );
@@ -1,12 +1,12 @@
1
- /*! Parser: input & select - updated 3/26/2015 (v2.21.3) *//*
1
+ /*! Parser: input & select - updated 5/17/2015 (v2.22.0) *//*
2
2
  * for jQuery 1.7+ & tablesorter 2.7.11+
3
3
  * Demo: http://mottie.github.com/tablesorter/docs/example-widget-grouping.html
4
4
  */
5
5
  /*jshint browser: true, jquery:true, unused:false */
6
- ;(function($){
7
- "use strict";
6
+ ;( function( $ ) {
7
+ 'use strict';
8
8
 
9
- var updateServer = function(event, $table, $input){
9
+ var updateServer = function( event, $table, $input ) {
10
10
  // do something here to update your server, if needed
11
11
  // event = change event object
12
12
  // $table = jQuery object of the table that was just updated
@@ -14,140 +14,164 @@
14
14
  };
15
15
 
16
16
  // Custom parser for parsing input values
17
- // updated dynamically using the "change" function below
17
+ // updated dynamically using the 'change' function below
18
18
  $.tablesorter.addParser({
19
- id: "inputs",
20
- is: function(){
19
+ id : 'inputs',
20
+ is : function() {
21
21
  return false;
22
22
  },
23
- format: function(s, table, cell) {
24
- return $(cell).find('input').val() || s;
23
+ format : function( txt, table, cell ) {
24
+ var $input = $( cell ).find( 'input' );
25
+ return $input.length ? $input.val() : txt;
25
26
  },
26
27
  parsed : true, // filter widget flag
27
- type: "text"
28
+ type : 'text'
29
+ });
30
+
31
+ $.tablesorter.addParser({
32
+ id : 'inputs-numeric',
33
+ is : function() {
34
+ return false;
35
+ },
36
+ format : function( txt, table, cell ) {
37
+ var $input = $( cell ).find( 'input' );
38
+ var val = $input.length ? $input.val() : txt,
39
+ num = $.tablesorter.formatFloat( ( val || '' ).replace( /[^\w,. \-()]/g, '' ), table );
40
+ return txt && typeof num === 'number' ? num :
41
+ txt ? $.trim( txt && table.config.ignoreCase ? txt.toLocaleLowerCase() : txt ) : txt;
42
+ },
43
+ parsed : true, // filter widget flag
44
+ type : 'numeric'
28
45
  });
29
46
 
30
47
  // Custom parser for including checkbox status if using the grouping widget
31
- // updated dynamically using the "change" function below
48
+ // updated dynamically using the 'change' function below
32
49
  $.tablesorter.addParser({
33
- id: "checkbox",
34
- is: function(){
50
+ id : 'checkbox',
51
+ is : function() {
35
52
  return false;
36
53
  },
37
- format: function(s, table, cell, cellIndex) {
38
- var $c = $(cell),
54
+ format : function( txt, table, cell, cellIndex ) {
55
+ var $cell = $( cell ),
39
56
  wo = table.config.widgetOptions,
40
57
  // returning plain language here because this is what is shown in the
41
58
  // group headers - change it as desired
42
- txt = wo.group_checkbox ? wo.group_checkbox : [ 'checked', 'unchecked' ],
43
- $input = $c.find('input[type="checkbox"]'),
44
- isChecked = $input.length ? $input[0].checked : '';
59
+ status = wo.group_checkbox ? wo.group_checkbox : [ 'checked', 'unchecked' ],
60
+ $input = $cell.find( 'input[type="checkbox"]' ),
61
+ isChecked = $input.length ? $input[ 0 ].checked : '';
45
62
  // adding class to row, indicating that a checkbox is checked; includes
46
63
  // a column index in case more than one checkbox happens to be in a row
47
- $c.closest('tr').toggleClass('checked-' + cellIndex, isChecked);
48
- return $input.length ? txt[ isChecked ? 0 : 1 ] : s;
64
+ $cell.closest( 'tr' ).toggleClass( 'checked checked-' + cellIndex, isChecked );
65
+ return $input.length ? status[ isChecked ? 0 : 1 ] : txt;
49
66
  },
50
67
  parsed : true, // filter widget flag
51
- type: "text"
68
+ type : 'text'
52
69
  });
53
70
 
54
71
  // Custom parser which returns the currently selected options
55
- // updated dynamically using the "change" function below
72
+ // updated dynamically using the 'change' function below
56
73
  $.tablesorter.addParser({
57
- id: "select",
58
- is: function(){
74
+ id : 'select',
75
+ is : function() {
59
76
  return false;
60
77
  },
61
- format: function(s, table, cell) {
62
- return $(cell).find('select').val() || s;
78
+ format : function( txt, table, cell ) {
79
+ var $select = $( cell ).find( 'select' );
80
+ return $select.length ? $select.val() : txt;
63
81
  },
64
82
  parsed : true, // filter widget flag
65
- type: "text"
83
+ type : 'text'
66
84
  });
67
85
 
68
86
  // Select parser to get the selected text
69
87
  $.tablesorter.addParser({
70
- id: "select-text",
71
- is: function(){
88
+ id : 'select-text',
89
+ is : function() {
72
90
  return false;
73
91
  },
74
- format: function(s, table, cell) {
75
- var $s = $(cell).find('select');
76
- return $s.length ? $s.find('option:selected').text() || '' : s;
92
+ format : function( txt, table, cell ) {
93
+ var $select = $( cell ).find( 'select' );
94
+ return $select.length ? $select.find( 'option:selected' ).text() || '' : txt;
77
95
  },
78
96
  parsed : true, // filter widget flag
79
- type: "text"
97
+ type : 'text'
80
98
  });
81
99
 
82
100
  // Custom parser for parsing textarea values
83
- // updated dynamically using the "change" function below
101
+ // updated dynamically using the 'change' function below
84
102
  $.tablesorter.addParser({
85
- id: "textarea",
86
- is: function(){
103
+ id : 'textarea',
104
+ is : function() {
87
105
  return false;
88
106
  },
89
- format: function(s, table, cell) {
90
- return $(cell).find('textarea').val() || s;
107
+ format : function( txt, table, cell ) {
108
+ var $textarea = $( cell ).find( 'textarea' );
109
+ return $textarea.length ? $textarea.val() : txt;
91
110
  },
92
111
  parsed : true, // filter widget flag
93
- type: "text"
112
+ type : 'text'
94
113
  });
95
114
 
96
115
  // update select and all input types in the tablesorter cache when the change event fires.
97
116
  // This method only works with jQuery 1.7+
98
117
  // you can change it to use delegate (v1.4.3+) or live (v1.3+) as desired
99
118
  // if this code interferes somehow, target the specific table $('#mytable'), instead of $('table')
100
- $(function(){
101
- $('table').on('tablesorter-initialized', function(){
102
- var restoreValue = function(isTbody){
119
+ $( function() {
120
+ $( 'table' ).on( 'tablesorter-initialized updateComplete', function() {
121
+ var namespace = '.parser-forms',
122
+ restoreValue = function( isTbody ) {
103
123
  // make sure we restore original values (trigger blur)
104
124
  // isTbody is needed to prevent the select from closing in IE
105
125
  // see https://connect.microsoft.com/IE/feedbackdetail/view/962618/
106
- if (isTbody) {
107
- $(':focus').blur();
126
+ if ( isTbody ) {
127
+ $( ':focus' ).blur();
108
128
  }
109
129
  return;
110
130
  };
111
131
  // bind to .tablesorter (default class name)
112
- $(this).children('tbody')
113
- .on('mouseleave', function(e){
114
- restoreValue(e.target.nodeName === 'TBODY');
132
+ $( this ).children( 'tbody' )
133
+ .off( namespace )
134
+ .on( 'mouseleave' + namespace, function( event ) {
135
+ restoreValue( event.target.nodeName === 'TBODY' );
115
136
  })
116
- .on('focus', 'select, input, textarea', function(){
117
- $(this).data('ts-original-value', this.value);
137
+ .on( 'focus' + namespace, 'select, input, textarea', function() {
138
+ $( this ).data( 'ts-original-value', this.value );
118
139
  })
119
- .on('blur', 'input, textarea', function(){
140
+ .on( 'blur' + namespace, 'input, textarea', function() {
120
141
  // restore input value;
121
- // "change" is triggered before "blur" so this doesn't replace the new update with the original
122
- this.value = $(this).data('ts-original-value');
142
+ // 'change' is triggered before 'blur' so this doesn't replace the new update with the original
143
+ this.value = $( this ).data( 'ts-original-value' );
123
144
  })
124
- .on('change keyup', 'select, input, textarea', function(e){
125
- if ( e.which === 27 ) {
145
+ .on( 'change keyup '.split( ' ' ).join( namespace + ' ' ), 'select, input, textarea', function( event ) {
146
+ if ( event.which === 27 ) {
126
147
  // escape: restore original value
127
- this.value = $(this).data('ts-original-value');
148
+ this.value = $( this ).data( 'ts-original-value' );
128
149
  return;
129
150
  }
130
151
  // Update cell cache using... select: change, input: enter or textarea: alt + enter
131
- if ( ( e.type === 'change' ) ||
132
- ( e.type === 'keyup' && e.which === 13 && ( e.target.nodeName === 'INPUT' || e.target.nodeName === 'TEXTAREA' && e.altKey ) ) ) {
152
+ if ( event.type === 'change' ||
153
+ ( event.type === 'keyup' && event.which === 13 &&
154
+ ( event.target.nodeName === 'INPUT' || event.target.nodeName === 'TEXTAREA' && event.altKey ) ) ) {
133
155
  var undef,
134
- $tar = $(e.target),
135
- $cell = $tar.closest('td'),
136
- $table = $cell.closest('table'),
137
- indx = $cell[0].cellIndex,
138
- c = $table[0].config || false,
139
- $hdr = c && c.$headers && c.$headers.eq(indx);
140
- // abort if not a tablesorter table, or
141
- // don't use updateCell if column is set to "sorter-false" and "filter-false", or column is set to "parser-false"
142
- if ( !c || ( $hdr && $hdr.length && ( $hdr.hasClass('parser-false') || ( $hdr.hasClass('sorter-false') && $hdr.hasClass('filter-false') ) ) ) ) {
143
- return restoreValue();
156
+ $target = $( event.target ),
157
+ $cell = $target.closest( 'td' ),
158
+ $table = $cell.closest( 'table' ),
159
+ indx = $cell[ 0 ].cellIndex,
160
+ c = $table[ 0 ].config || false,
161
+ $hdr = c && c.$headerIndexed && c.$headerIndexed[ indx ] || [],
162
+ val = $target.val();
163
+ // abort if not a tablesorter table, or don't use updateCell if column is set
164
+ // to 'sorter-false' and 'filter-false', or column is set to 'parser-false'
165
+ if ( $hdr.length && ( $hdr.hasClass( 'parser-false' ) ||
166
+ ( $hdr.hasClass( 'sorter-false' ) && $hdr.hasClass( 'filter-false' ) ) ) ) {
167
+ return;
144
168
  }
145
169
  // ignore change event if nothing changed
146
- if ($tar.val() !== $tar.data('ts-original-value') || e.target.type === 'checkbox') {
147
- $tar.data('ts-original-value', $tar.val());
170
+ if ( val !== $target.data( 'ts-original-value' ) || event.target.type === 'checkbox' ) {
171
+ $target.data( 'ts-original-value', val );
148
172
  // pass undefined resort value so it falls back to config.resort setting
149
- $table.trigger('updateCell', [ $tar.closest('td'), undef, function(){
150
- updateServer(e, $table, $tar);
173
+ $table.trigger( 'updateCell', [ $cell, undef, function() {
174
+ updateServer( event, $table, $target );
151
175
  } ]);
152
176
  }
153
177
  }
@@ -155,4 +179,4 @@
155
179
  });
156
180
  });
157
181
 
158
- })(jQuery);
182
+ })( jQuery );
@@ -81,12 +81,13 @@
81
81
  },
82
82
  result, group,
83
83
  negativeRegex = new RegExp('(' + named.negative.join('|') + ')'),
84
- calc = function ( word, table ) {
85
- var num = named.numbers.hasOwnProperty( word ) ? named.numbers[ word ] : null,
84
+ calc = function ( rawWord, table ) {
85
+ // remove extra characters that might be next to the word
86
+ var word = rawWord.replace( /[,."']/g, '' ),
87
+ // formatFloat will deal with the commas & decimals in the number format
88
+ num = $.tablesorter.formatFloat( rawWord || '', table ),
86
89
  power = named.powers.hasOwnProperty( word ) ? named.powers[ word ] : null;
87
- if ( !num && !isNaN( word ) ) {
88
- num = $.tablesorter.formatFloat( word || '', table );
89
- }
90
+ num = typeof num === 'number' ? num : named.numbers.hasOwnProperty( word ) ? named.numbers[ word ] : null;
90
91
  if ( num !== null ) {
91
92
  group += num;
92
93
  } else if ( word === named.hundred ) {
@@ -1,8 +1,8 @@
1
- /*! Parser: network - updated 10/26/2014 (v2.18.0) */
1
+ /*! Parser: network - updated 5/17/2015 (v2.22.0) */
2
2
  /* IPv4, IPv6 and MAC Addresses */
3
3
  /*global jQuery: false */
4
4
  ;(function($){
5
- "use strict";
5
+ 'use strict';
6
6
 
7
7
  var ts = $.tablesorter,
8
8
  ipv4Format,
@@ -10,8 +10,8 @@
10
10
 
11
11
  /*! IPv6 Address parser (WIP) *//*
12
12
  * IPv6 Address (ffff:0000:0000:0000:0000:0000:0000:0000)
13
- * needs to support short versions like "::8" or "1:2::7:8"
14
- * and "::00:192.168.10.184" (embedded IPv4 address)
13
+ * needs to support short versions like '::8' or '1:2::7:8'
14
+ * and '::00:192.168.10.184' (embedded IPv4 address)
15
15
  * see http://www.intermapper.com/support/tools/IPV6-Validator.aspx
16
16
  */
17
17
  $.extend( ts.regex, {}, {
@@ -93,7 +93,7 @@
93
93
  };
94
94
 
95
95
  /*! Parser: ipv4Address (a.k.a. ipAddress) */
96
- // duplicate "ipAddress" as "ipv4Address" (to maintain backwards compatility)
96
+ // duplicate 'ipAddress' as 'ipv4Address' (to maintain backwards compatility)
97
97
  ts.addParser({
98
98
  id: 'ipAddress',
99
99
  is: ipv4Is,
@@ -108,21 +108,30 @@
108
108
  });
109
109
 
110
110
  /*! Parser: MAC address */
111
+ /* MAC examples: 12:34:56:78:9A:BC, 1234.5678.9ABC, 12-34-56-78-9A-BC, and 123456789ABC
112
+ */
111
113
  ts.addParser({
112
- id: 'MAC',
113
- is: function(s) {
114
- return ts.regex.ipv6Validate.test(s);
114
+ id : 'MAC',
115
+ is : function( str ) {
116
+ return false;
115
117
  },
116
- format: function(s) {
117
- var t = '',
118
- val = s.replace(/[:.-]/g, '').match(/\w{2}/g);
119
- $.each(val, function(i, v){
120
- t += ( '000' + parseInt(v, 16) ).slice(-3);
121
- });
122
- return t;
118
+ format : function( str ) {
119
+ var indx, len,
120
+ mac = '',
121
+ val = ( str || '' ).replace( /[:.-]/g, '' ).match( /\w{2}/g );
122
+ if ( val ) {
123
+ // not assuming all mac addresses in the column will end up with six
124
+ // groups of two to process, so it's not actually validating the address
125
+ len = val.length;
126
+ for ( indx = 0; indx < len; indx++ ) {
127
+ mac += ( '000' + parseInt( val[ indx ], 16 ) ).slice( -3 );
128
+ }
129
+ return mac;
130
+ }
131
+ return str;
123
132
  },
124
133
  // uses natural sort hex compare
125
- type: 'numeric'
134
+ type : 'numeric'
126
135
  });
127
136
 
128
- })(jQuery);
137
+ })( jQuery );
@@ -1,7 +1,7 @@
1
1
  /*! Widget: columns */
2
2
  ;(function ($) {
3
3
  'use strict';
4
- var ts = $.tablesorter = $.tablesorter || {};
4
+ var ts = $.tablesorter || {};
5
5
 
6
6
  ts.addWidget({
7
7
  id: "columns",
@@ -1,4 +1,4 @@
1
- /*! Widget: editable - updated 2/9/2015 (v2.19.1) *//*
1
+ /*! Widget: editable - updated 5/17/2015 (v2.22.0) *//*
2
2
  * Requires tablesorter v2.8+ and jQuery 1.7+
3
3
  * by Rob Garrison
4
4
  */
@@ -8,10 +8,13 @@
8
8
  'use strict';
9
9
 
10
10
  var tse = $.tablesorter.editable = {
11
+ namespace : '.tseditable',
12
+ // last edited class name
13
+ lastEdited: 'tseditable-last-edited-cell',
11
14
 
12
15
  editComplete: function( c, wo, $cell, refocus ) {
13
16
  $cell
14
- .removeClass( 'tseditable-last-edited-cell' )
17
+ .removeClass( tse.lastEdited )
15
18
  .trigger( wo.editable_editComplete, [ c ] );
16
19
  // restore focus last cell after updating
17
20
  if ( refocus ) {
@@ -25,16 +28,23 @@ var tse = $.tablesorter.editable = {
25
28
  setTimeout( function() {
26
29
  // select all text in contenteditable
27
30
  // see http://stackoverflow.com/a/6150060/145346
28
- var sel, range = document.createRange();
29
- range.selectNodeContents( cell );
30
- sel = window.getSelection();
31
- sel.removeAllRanges();
32
- sel.addRange( range );
31
+ var range, selection;
32
+ if ( document.body.createTextRange ) {
33
+ range = document.body.createTextRange();
34
+ range.moveToElementText( cell );
35
+ range.select();
36
+ } else if ( window.getSelection ) {
37
+ selection = window.getSelection();
38
+ range = document.createRange();
39
+ range.selectNodeContents( cell );
40
+ selection.removeAllRanges();
41
+ selection.addRange( range );
42
+ }
33
43
  }, 100 );
34
44
  },
35
45
 
36
- update: function( c, wo ) {
37
- var indx, tmp, $t,
46
+ getColumns : function( c, wo ) {
47
+ var indx, tmp,
38
48
  colIndex = [],
39
49
  cols = [];
40
50
  if ( !wo.editable_columnsArray && $.type( wo.editable_columns ) === 'string' && wo.editable_columns.indexOf( '-' ) >= 0 ) {
@@ -61,22 +71,33 @@ var tse = $.tablesorter.editable = {
61
71
  wo.editable_columnsArray = colIndex;
62
72
  wo.editable_columnsArray.sort(function(a,b){ return a - b; });
63
73
  }
64
- tmp = $( '<div>' ).wrapInner( wo.editable_wrapContent ).children().length || $.isFunction( wo.editable_wrapContent );
74
+ return cols;
75
+ },
76
+
77
+ update: function( c, wo ) {
78
+ var $t,
79
+ tmp = $( '<div>' ).wrapInner( wo.editable_wrapContent ).children().length || $.isFunction( wo.editable_wrapContent ),
80
+ cols = tse.getColumns( c, wo ).join( ',' );
81
+
82
+ // turn off contenteditable to allow dynamically setting the wo.editable_noEdit
83
+ // class on table cells - see issue #900
84
+ c.$tbodies.find( cols ).find( '[contenteditable]' ).prop( 'contenteditable', false );
85
+
65
86
  // IE does not allow making TR/TH/TD cells directly editable ( issue #404 )
66
87
  // so add a div or span inside ( it's faster than using wrapInner() )
67
- c.$tbodies.find( cols.join( ',' ) ).not( '.' + wo.editable_noEdit ).each( function() {
88
+ c.$tbodies.find( cols ).not( '.' + wo.editable_noEdit ).each( function() {
68
89
  // test for children, if they exist, then make the children editable
69
90
  $t = $( this );
70
91
 
71
- if ( tmp && $t.children().length === 0 ) {
92
+ if ( tmp && $t.children( 'div, span' ).length === 0 ) {
72
93
  $t.wrapInner( wo.editable_wrapContent );
73
94
  }
74
- if ( $t.children().length ) {
75
- // make all children content editable
76
- $t.children().not( '.' + wo.editable_noEdit ).each( function() {
95
+ if ( $t.children( 'div, span' ).length ) {
96
+ // make div/span children content editable
97
+ $t.children( 'div, span' ).not( '.' + wo.editable_noEdit ).each( function() {
77
98
  var $this = $( this );
78
99
  if ( wo.editable_trimContent ) {
79
- $this.text( function( i, txt ) {
100
+ $this.html( function( i, txt ) {
80
101
  return $.trim( txt );
81
102
  });
82
103
  }
@@ -84,7 +105,7 @@ var tse = $.tablesorter.editable = {
84
105
  });
85
106
  } else {
86
107
  if ( wo.editable_trimContent ) {
87
- $t.text( function( i, txt ) {
108
+ $t.html( function( i, txt ) {
88
109
  return $.trim( txt );
89
110
  });
90
111
  }
@@ -94,36 +115,45 @@ var tse = $.tablesorter.editable = {
94
115
  },
95
116
 
96
117
  bindEvents: function( c, wo ) {
118
+ var namespace = tse.namespace;
97
119
  c.$table
98
- .off( ( 'updateComplete pagerComplete '.split( ' ' ).join( '.tseditable ' ) ).replace( /\s+/g, ' ' ) )
99
- .on( 'updateComplete pagerComplete '.split( ' ' ).join( '.tseditable ' ), function() {
120
+ .off( ( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' ) )
121
+ .on( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ), function() {
100
122
  tse.update( c, c.widgetOptions );
101
- });
102
-
103
- c.$tbodies
104
- .off( ( 'mouseleave focus blur focusout keydown '.split( ' ' ).join( '.tseditable ' ) ).replace( /\s+/g, ' ' ) )
105
- .on( 'mouseleave.tseditable', function() {
123
+ })
124
+ // prevent sort initialized by user click on the header from changing the row indexing before
125
+ // updateCell can finish processing the change
126
+ .children( 'thead' )
127
+ .add( $( c.namespace + '_extra_table' ).children( 'thead' ) )
128
+ .off( 'mouseenter' + namespace )
129
+ .on( 'mouseenter' + namespace, function() {
106
130
  if ( c.$table.data( 'contentFocused' ) ) {
107
131
  // change to 'true' instead of element to allow focusout to process
108
132
  c.$table.data( 'contentFocused', true );
109
133
  $( ':focus' ).trigger( 'focusout' );
110
134
  }
111
- })
112
- .on( 'focus.tseditable', '[contenteditable]', function( e ) {
135
+ });
136
+
137
+ c.$tbodies
138
+ .off( ( 'focus blur focusout keydown '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' ) )
139
+ .on( 'focus' + namespace, '[contenteditable]', function( e ) {
113
140
  clearTimeout( $( this ).data( 'timer' ) );
114
141
  c.$table.data( 'contentFocused', e.target );
115
142
  var $this = $( this ),
116
143
  selAll = wo.editable_selectAll,
117
144
  column = $this.closest( 'td' ).index(),
118
- txt = $.trim( $this.text() );
119
- if ( wo.editable_enterToAccept ) {
120
- // prevent enter from adding into the content
121
- $this.on( 'keydown.tseditable', function( e ){
122
- if ( e.which === 13 ) {
145
+ txt = $this.html();
146
+ if ( wo.editable_trimContent ) {
147
+ txt = $.trim( txt );
148
+ }
149
+ // prevent enter from adding into the content
150
+ $this
151
+ .off( 'keydown' + namespace )
152
+ .on( 'keydown' + namespace, function( e ){
153
+ if ( wo.editable_enterToAccept && e.which === 13 ) {
123
154
  e.preventDefault();
124
155
  }
125
156
  });
126
- }
127
157
  $this.data({ before : txt, original: txt });
128
158
 
129
159
  if ( typeof wo.editable_focused === 'function' ) {
@@ -140,16 +170,19 @@ var tse = $.tablesorter.editable = {
140
170
  }
141
171
  }
142
172
  })
143
- .on( 'blur focusout keydown '.split( ' ' ).join( '.tseditable ' ), '[contenteditable]', function( e ) {
173
+ .on( 'blur focusout keydown '.split( ' ' ).join( namespace + ' ' ), '[contenteditable]', function( e ) {
144
174
  if ( !c.$table.data( 'contentFocused' ) ) { return; }
145
175
  var t, validate,
146
176
  valid = false,
147
177
  $this = $( e.target ),
148
- txt = $.trim( $this.text() ),
178
+ txt = $this.html(),
149
179
  column = $this.closest( 'td' ).index();
180
+ if ( wo.editable_trimContent ) {
181
+ txt = $.trim( txt );
182
+ }
150
183
  if ( e.which === 27 ) {
151
184
  // user cancelled
152
- $this.html( $.trim( $this.data( 'original' ) ) ).trigger( 'blur.tseditable' );
185
+ $this.html( $this.data( 'original' ) ).trigger( 'blur' + namespace );
153
186
  c.$table.data( 'contentFocused', false );
154
187
  return false;
155
188
  }
@@ -168,10 +201,10 @@ var tse = $.tablesorter.editable = {
168
201
  }
169
202
 
170
203
  if ( t && valid !== false ) {
171
- c.$table.find( '.tseditable-last-edited-cell' ).removeClass( 'tseditable-last-edited-cell' );
204
+ c.$table.find( '.' + tse.lastEdited ).removeClass( tse.lastEdited );
172
205
  $this
173
- .addClass( 'tseditable-last-edited-cell' )
174
- .html( $.trim( valid ) )
206
+ .addClass( tse.lastEdited )
207
+ .html( valid )
175
208
  .data( 'before', valid )
176
209
  .data( 'original', valid )
177
210
  .trigger( 'change' );
@@ -179,11 +212,11 @@ var tse = $.tablesorter.editable = {
179
212
  if ( wo.editable_autoResort ) {
180
213
  setTimeout( function() {
181
214
  c.$table.trigger( 'sorton', [ c.sortList, function() {
182
- tse.editComplete( c, wo, c.$table.find( '.tseditable-last-edited-cell' ), true );
215
+ tse.editComplete( c, wo, c.$table.find( '.' + tse.lastEdited ), true );
183
216
  }, true ] );
184
217
  }, 10 );
185
218
  } else {
186
- tse.editComplete( c, wo, c.$table.find( '.tseditable-last-edited-cell' ) );
219
+ tse.editComplete( c, wo, c.$table.find( '.' + tse.lastEdited ) );
187
220
  }
188
221
  } ] );
189
222
  return false;
@@ -192,13 +225,28 @@ var tse = $.tablesorter.editable = {
192
225
  clearTimeout( $this.data( 'timer' ) );
193
226
  $this.data( 'timer', setTimeout( function() {
194
227
  if ( $.isFunction( wo.editable_blur ) ) {
195
- wo.editable_blur( $.trim( $this.text() ), column, $this );
228
+ txt = $this.html();
229
+ wo.editable_blur( wo.editable_trimContent ? $.trim( txt ) : txt, column, $this );
196
230
  }
197
231
  }, 100 ) );
198
232
  // restore original content on blur
199
- $this.html( $.trim( $this.data( 'original' ) ) );
233
+ $this.html( $this.data( 'original' ) );
200
234
  }
201
235
  });
236
+ },
237
+ destroy : function( c, wo ) {
238
+ var namespace = tse.namespace,
239
+ cols = tse.getColumns( c, wo ),
240
+
241
+ tmp = ( 'updateComplete pagerComplete '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' );
242
+ c.$table.off( tmp );
243
+
244
+ tmp = ( 'focus blur focusout keydown '.split( ' ' ).join( namespace + ' ' ) ).replace( /\s+/g, ' ' );
245
+ c.$tbodies
246
+ .off( tmp )
247
+ .find( cols.join( ',' ) )
248
+ .find( '[contenteditable]' )
249
+ .prop( 'contenteditable', false );
202
250
  }
203
251
 
204
252
  };
@@ -223,6 +271,11 @@ var tse = $.tablesorter.editable = {
223
271
  if ( !wo.editable_columns.length ) { return; }
224
272
  tse.update( c, wo );
225
273
  tse.bindEvents( c, wo );
274
+ },
275
+ remove : function( table, c, wo, refreshing ) {
276
+ if ( !refreshing ) {
277
+ tse.destroy( c, wo ) ;
278
+ }
226
279
  }
227
280
  });
228
281