jquery-tablesorter 1.16.5 → 1.17.0

Sign up to get free protection for your applications and to get access to all the features.
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