jquery-tablesorter 1.13.4 → 1.14.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +2 -2
  4. data/lib/jquery-tablesorter/version.rb +1 -1
  5. data/vendor/assets/images/jquery-tablesorter/dragtable-handle.png +0 -0
  6. data/vendor/assets/images/jquery-tablesorter/dragtable-handle.svg +7 -0
  7. data/vendor/assets/javascripts/jquery-tablesorter/addons/pager/jquery.tablesorter.pager.js +58 -32
  8. data/vendor/assets/javascripts/jquery-tablesorter/extras/jquery.dragtable.mod.js +605 -0
  9. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +161 -81
  10. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets-filter-formatter-select2.js +41 -30
  11. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets.js +151 -96
  12. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-duration.js +32 -5
  13. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-input-select.js +21 -26
  14. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-alignChar.js +5 -4
  15. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-build-table.js +2 -2
  16. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-chart.js +276 -0
  17. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-columnSelector.js +64 -32
  18. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-cssStickyHeaders.js +3 -2
  19. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-editable.js +11 -5
  20. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-formatter.js +70 -0
  21. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-math.js +13 -6
  22. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-output.js +7 -3
  23. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-pager.js +70 -41
  24. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-print.js +2 -2
  25. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-reflow.js +4 -3
  26. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-repeatheaders.js +14 -12
  27. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-scroller.js +68 -26
  28. data/vendor/assets/stylesheets/jquery-tablesorter/dragtable.mod.css +64 -0
  29. data/vendor/assets/stylesheets/jquery-tablesorter/theme.black-ice.css +3 -0
  30. data/vendor/assets/stylesheets/jquery-tablesorter/theme.blue.css +3 -0
  31. data/vendor/assets/stylesheets/jquery-tablesorter/theme.bootstrap.css +3 -0
  32. data/vendor/assets/stylesheets/jquery-tablesorter/theme.bootstrap_2.css +3 -0
  33. data/vendor/assets/stylesheets/jquery-tablesorter/theme.dark.css +3 -0
  34. data/vendor/assets/stylesheets/jquery-tablesorter/theme.default.css +3 -0
  35. data/vendor/assets/stylesheets/jquery-tablesorter/theme.dropbox.css +3 -0
  36. data/vendor/assets/stylesheets/jquery-tablesorter/theme.green.css +3 -0
  37. data/vendor/assets/stylesheets/jquery-tablesorter/theme.grey.css +3 -0
  38. data/vendor/assets/stylesheets/jquery-tablesorter/theme.ice.css +3 -0
  39. data/vendor/assets/stylesheets/jquery-tablesorter/theme.jui.css +3 -0
  40. data/vendor/assets/stylesheets/jquery-tablesorter/theme.metro-dark.css +3 -0
  41. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fbc77e5c7eae0e53eeabee85b7bc2383ee47f418
4
- data.tar.gz: fc1cc344b8642f999e4787d8c82e4d93c6f73f30
3
+ metadata.gz: 6dfe913d87203537e4c01799330730a0a5d07c76
4
+ data.tar.gz: 4372b67de0d2b979cdd67be82de133141e02bb70
5
5
  SHA512:
6
- metadata.gz: db3c65d13f8da77d1cdd84f9c40d6e3460317d7f59f3a30a3c6042f7366d0bc2606c2b4fcb94030164e8490251d592764c6664523b5e0cf6e4eb65fb34e6d46f
7
- data.tar.gz: 0cd1b23750074956747fba1febbbcbe0d1084bcef6218d67d96723e65c6aeb28959ed198d016984a32f6667b7e57040e8ddce8b8531c7f63aa40dfc2de8a1b95
6
+ metadata.gz: 6ac07021042d37ed4bceca7f05ebd40b086ee7f5437fbc8de5dfd97bf81bb546c52818a6be7d8a674beaa35d7629a3e61970621db28db57bf8c758676249831d
7
+ data.tar.gz: 7cbe44694d1091fc8a2a1c9666280ee4ea2580a414fb9bbb3b08adccfd660da3f07cbc0b88b0c9cd54f2a7d14e20c1d4afd1db790bcc047cc5012fd37f1a7b86
@@ -1,4 +1,4 @@
1
- Copyright 2014 Jun Lin, Erik-B. Ernst
1
+ Copyright 2015 Jun Lin, Erik-B. Ernst
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Simple integration of jquery-tablesorter into the asset pipeline.
6
6
 
7
- Current tablesorter version: 2.18.4 (12/22/2014), [documentation]
7
+ Current tablesorter version: 2.19.0 (2/7/2015), [documentation]
8
8
 
9
9
  Any issue associated with the js/css files, please report to [Mottie's fork].
10
10
 
@@ -26,7 +26,7 @@ Or install it yourself as:
26
26
 
27
27
  Rails 3.1 and higher (tested up to 4.2)
28
28
 
29
- Tested with ruby 1.9.3 - 2.1.5
29
+ Tested with ruby 1.9.3 - 2.2.0
30
30
 
31
31
  ## Usage
32
32
 
@@ -1,3 +1,3 @@
1
1
  module JqueryTablesorter
2
- VERSION = '1.13.4'
2
+ VERSION = '1.14.0'
3
3
  end
@@ -0,0 +1,7 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="2" height="13">
2
+ <rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="2"/>
3
+ <rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="4"/>
4
+ <rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="6"/>
5
+ <rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="8"/>
6
+ <rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="10"/>
7
+ </svg>
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * tablesorter (FORK) pager plugin
3
- * updated 12/22/2014 (v2.18.4)
3
+ * updated 2/7/2015 (v2.19.0)
4
4
  */
5
5
  /*jshint browser:true, jquery:true, unused:false */
6
6
  ;(function($) {
@@ -114,7 +114,10 @@
114
114
 
115
115
  };
116
116
 
117
- var $this = this,
117
+ var pagerEvents = 'filterInit filterStart filterEnd sortEnd disable enable destroy updateComplete ' +
118
+ 'pageSize pageSet pageAndSize pagerUpdate ',
119
+
120
+ $this = this,
118
121
 
119
122
  // hide arrows at extremes
120
123
  pagerArrows = function(p, disable) {
@@ -132,15 +135,18 @@
132
135
  },
133
136
 
134
137
  calcFilters = function(table, p) {
135
- var c = table.config,
138
+ var tbodyIndex,
139
+ c = table.config,
136
140
  hasFilters = c.$table.hasClass('hasFilters');
137
141
  if (hasFilters && !p.ajaxUrl) {
138
142
  if ($.isEmptyObject(c.cache)) {
139
143
  // delayInit: true so nothing is in the cache
140
144
  p.filteredRows = p.totalRows = c.$tbodies.eq(0).children('tr').not( p.countChildRows ? '' : '.' + c.cssChildRow ).length;
141
145
  } else {
146
+ // just in case the pager tbody isn't the first tbody
147
+ tbodyIndex = c.$table.children('tbody').index( c.$tbodies.eq(0) );
142
148
  p.filteredRows = 0;
143
- $.each(c.cache[0].normalized, function(i, el) {
149
+ $.each(c.cache[tbodyIndex].normalized, function(i, el) {
144
150
  p.filteredRows += p.regexRows.test(el[c.columns].$row[0].className) ? 0 : 1;
145
151
  });
146
152
  }
@@ -153,7 +159,7 @@
153
159
  if ( p.initializing ) { return; }
154
160
  var s, t, $out,
155
161
  c = table.config,
156
- sz = p.size || 10; // don't allow dividing by zero
162
+ sz = p.size || p.settings.size || 10; // don't allow dividing by zero
157
163
  if (p.countChildRows) { t.push(c.cssChildRow); }
158
164
  p.totalPages = Math.ceil( p.totalRows / sz ); // needed for "pageSize" method
159
165
  c.totalRows = p.totalRows;
@@ -162,8 +168,8 @@
162
168
  p.filteredPages = Math.ceil( p.filteredRows / sz ) || 0;
163
169
  if ( Math.min( p.totalPages, p.filteredPages ) >= 0 ) {
164
170
  t = (p.size * p.page > p.filteredRows) && completed;
165
- p.startRow = (t) ? 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1);
166
- p.page = (t) ? 0 : p.page;
171
+ p.page = (t) ? p.pageReset || 0 : p.page;
172
+ p.startRow = (t) ? p.size * p.page + 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1);
167
173
  p.endRow = Math.min( p.filteredRows, p.totalRows, p.size * ( p.page + 1 ) );
168
174
  $out = p.$container.find(p.cssPageDisplay);
169
175
  // form the output string (can now get a new output string from the server)
@@ -187,16 +193,16 @@
187
193
  }
188
194
  return extra.length > 1 && data && data[extra[0]] ? data[extra[0]][extra[1]] : p[str] || (data ? data[str] : deflt) || deflt;
189
195
  });
196
+ if ( p.$goto.length ) {
197
+ t = '';
198
+ $.each(buildPageSelect(p), function(i, opt){
199
+ t += '<option value="' + opt + '">' + opt + '</option>';
200
+ });
201
+ // innerHTML doesn't work in IE9 - http://support2.microsoft.com/kb/276228
202
+ p.$goto.html(t).val( p.page + 1 );
203
+ }
190
204
  if ($out.length) {
191
205
  $out[ ($out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
192
- if ( p.$goto.length ) {
193
- t = '';
194
- $.each(buildPageSelect(p), function(i, opt){
195
- t += '<option value="' + opt + '">' + opt + '</option>';
196
- });
197
- // innerHTML doesn't work in IE9 - http://support2.microsoft.com/kb/276228
198
- p.$goto.html(t).val( p.page + 1 );
199
- }
200
206
  // rebind startRow/page inputs
201
207
  $out.find('.ts-startRow, .ts-page').unbind('change').bind('change', function(){
202
208
  var v = $(this).val(),
@@ -319,7 +325,9 @@
319
325
  s = ( p.page * p.size ),
320
326
  e = s + p.size,
321
327
  f = c.widgetOptions && c.widgetOptions.filter_filteredRow || 'filtered',
328
+ last = 0, // for cache indexing
322
329
  j = 0; // size counter
330
+ p.cacheIndex = [];
323
331
  for ( i = 0; i < l; i++ ){
324
332
  if ( !rows[i].className.match(f) ) {
325
333
  if (j === s && rows[i].className.match(c.cssChildRow)) {
@@ -327,6 +335,10 @@
327
335
  rows[i].style.display = 'none';
328
336
  } else {
329
337
  rows[i].style.display = ( j >= s && j < e ) ? '' : 'none';
338
+ if (last !== j && j >= s && j < e) {
339
+ p.cacheIndex.push(i);
340
+ last = j;
341
+ }
330
342
  // don't count child rows
331
343
  j += rows[i].className.match(c.cssChildRow + '|' + c.selectorRemove.slice(1)) && !p.countChildRows ? 0 : 1;
332
344
  if ( j === e && rows[i].style.display !== 'none' && rows[i].className.match(ts.css.cssHasChild) ) {
@@ -345,7 +357,7 @@
345
357
  },
346
358
 
347
359
  hideRowsSetup = function(table, p){
348
- p.size = parseInt( p.$size.val(), 10 ) || p.size;
360
+ p.size = parseInt( p.$size.val(), 10 ) || p.size || p.settings.size || 10;
349
361
  $.data(table, 'pagerLastSize', p.size);
350
362
  pagerArrows(p);
351
363
  if ( !p.removeRows ) {
@@ -457,11 +469,11 @@
457
469
  }
458
470
  // make sure last pager settings are saved, prevents multiple server side calls with
459
471
  // the same parameters
460
- p.totalPages = Math.ceil( p.totalRows / ( p.size || 10 ) );
472
+ p.totalPages = Math.ceil( p.totalRows / ( p.size || p.settings.size || 10 ) );
461
473
  p.last.totalRows = p.totalRows;
462
474
  p.last.currentFilters = p.currentFilters;
463
475
  p.last.sortList = (c.sortList || []).join(',');
464
- updatePageDisplay(table, p, true);
476
+ updatePageDisplay(table, p, false);
465
477
  $t.trigger('updateCache', [function(){
466
478
  if (p.initialized) {
467
479
  // apply widgets after table has rendered & after a delay to prevent
@@ -470,6 +482,7 @@
470
482
  $t
471
483
  .trigger('applyWidgets')
472
484
  .trigger('pagerChange', p);
485
+ updatePageDisplay(table, p, true);
473
486
  }, 0);
474
487
  }
475
488
  }]);
@@ -580,6 +593,7 @@
580
593
  // lets not render the table more than once
581
594
  moveToLastPage(table, p);
582
595
  }
596
+ p.cacheIndex = [];
583
597
  p.isDisabled = false; // needed because sorting will change the page and re-enable the pager
584
598
  if (p.initialized) { $t.trigger('pagerChange', p); }
585
599
 
@@ -598,6 +612,7 @@
598
612
  count++;
599
613
  if (count > s && added <= e) {
600
614
  added++;
615
+ p.cacheIndex.push(index);
601
616
  $tb.append(rows[index]);
602
617
  }
603
618
  }
@@ -644,7 +659,8 @@
644
659
  c.$table.trigger('updateCache', [ function(){
645
660
  var i,
646
661
  rows = [],
647
- n = table.config.cache[0].normalized;
662
+ tbodyIndex = c.$table.children('tbody').index( c.$tbodies.eq(0) ),
663
+ n = table.config.cache[tbodyIndex].normalized;
648
664
  p.totalRows = n.length;
649
665
  for (i = 0; i < p.totalRows; i++) {
650
666
  rows.push(n[i][c.columns].$row);
@@ -711,7 +727,7 @@
711
727
  },
712
728
 
713
729
  setPageSize = function(table, size, p) {
714
- p.size = size || p.size || 10;
730
+ p.size = size || p.size || p.settings.size || 10;
715
731
  p.$size.val(p.size);
716
732
  $.data(table, 'pagerLastPage', p.page);
717
733
  $.data(table, 'pagerLastSize', p.size);
@@ -752,7 +768,7 @@
752
768
  table.config.appender = null; // remove pager appender function
753
769
  p.initialized = false;
754
770
  delete table.config.rowsCopy;
755
- $(table).unbind('filterInit filterStart filterEnd sortEnd disable enable destroy updateComplete pageSize pageSet '.split(' ').join('.pager '));
771
+ $(table).unbind(pagerEvents.split(' ').join('.pager '));
756
772
  if (ts.storage) {
757
773
  ts.storage(table, p.storageKey, '');
758
774
  }
@@ -767,7 +783,7 @@
767
783
  .attr('aria-disabled', 'false');
768
784
  p.isDisabled = false;
769
785
  p.page = $.data(table, 'pagerLastPage') || p.page || 0;
770
- p.size = $.data(table, 'pagerLastSize') || parseInt(p.$size.find('option[selected]').val(), 10) || p.size || 10;
786
+ p.size = $.data(table, 'pagerLastSize') || parseInt(p.$size.find('option[selected]').val(), 10) || p.size || p.settings.size || 10;
771
787
  p.$size.val(p.size); // set page size
772
788
  p.totalPages = Math.ceil( Math.min( p.totalRows, p.filteredRows ) / p.size );
773
789
  // if table id exists, include page display with aria info
@@ -793,7 +809,7 @@
793
809
  if ( !p.ajax ) {
794
810
  c.rowsCopy = rows;
795
811
  p.totalRows = p.countChildRows ? c.$tbodies.eq(0).children('tr').length : rows.length;
796
- p.size = $.data(table, 'pagerLastSize') || p.size || 10;
812
+ p.size = $.data(table, 'pagerLastSize') || p.size || p.settings.size || 10;
797
813
  p.totalPages = Math.ceil( p.totalRows / p.size );
798
814
  renderTable(table, rows, p);
799
815
  // update display here in case all rows are removed
@@ -813,6 +829,8 @@
813
829
  $t = c.$table,
814
830
  // added in case the pager is reinitialized after being destroyed.
815
831
  pager = p.$container = $(p.container).addClass('tablesorter-pager').show();
832
+ // save a copy of the original settings
833
+ p.settings = $.extend( true, {}, $.tablesorterPager.defaults, settings );
816
834
  if (c.debug) {
817
835
  ts.log('Pager initializing');
818
836
  }
@@ -822,7 +840,7 @@
822
840
  if (p.savePages && ts.storage) {
823
841
  t = ts.storage(table, p.storageKey) || {}; // fixes #387
824
842
  p.page = isNaN(t.page) ? p.page : t.page;
825
- p.size = ( isNaN(t.size) ? p.size : t.size ) || 10;
843
+ p.size = ( isNaN(t.size) ? p.size : t.size ) || p.settings.size || 10;
826
844
  $.data(table, 'pagerLastSize', p.size);
827
845
  }
828
846
 
@@ -830,9 +848,9 @@
830
848
  p.regexRows = new RegExp('(' + (wo.filter_filteredRow || 'filtered') + '|' + c.selectorRemove.slice(1) + '|' + c.cssChildRow + ')');
831
849
 
832
850
  $t
833
- .unbind('filterInit filterStart filterEnd sortEnd disable enable destroy updateComplete pageSize pageSet '.split(' ').join('.pager '))
834
- .bind('filterInit.pager filterStart.pager', function(e) {
835
- p.currentFilters = c.$table.data('lastSearch');
851
+ .unbind(pagerEvents.split(' ').join('.pager '))
852
+ .bind('filterInit.pager filterStart.pager', function(e, filters) {
853
+ p.currentFilters = $.isArray(filters) ? filters : c.$table.data('lastSearch');
836
854
  // don't change page if filters are the same (pager updating, etc)
837
855
  if (e.type === 'filterStart' && p.pageReset !== false && (c.lastCombinedFilter || '') !== (p.currentFilters || []).join('')) {
838
856
  p.page = p.pageReset; // fixes #456 & #565
@@ -881,18 +899,26 @@
881
899
  changeHeight(table, p);
882
900
  updatePageDisplay(table, p, true);
883
901
  })
884
- .bind('pageSize.pager', function(e,v){
902
+ .bind('pageSize.pager refreshComplete.pager', function(e,v){
885
903
  e.stopPropagation();
886
- setPageSize(table, parseInt(v, 10) || 10, p);
904
+ setPageSize(table, parseInt(v, 10) || p.settings.size || 10, p);
887
905
  hideRows(table, p);
888
906
  updatePageDisplay(table, p, false);
889
- if (p.$size.length) { p.$size.val(p.size); } // twice?
890
907
  })
891
- .bind('pageSet.pager', function(e,v){
908
+ .bind('pageSet.pager pagerUpdate.pager', function(e,v){
892
909
  e.stopPropagation();
893
910
  p.page = (parseInt(v, 10) || 1) - 1;
894
- if (p.$goto.length) { p.$goto.val(p.size); } // twice?
911
+ // force pager refresh
912
+ if (e.type === 'pagerUpdate') { p.last.page = true; }
913
+ moveToPage(table, p, true);
914
+ updatePageDisplay(table, p, false);
915
+ })
916
+ .bind('pageAndSize.pager', function(e, page, size){
917
+ e.stopPropagation();
918
+ p.page = (parseInt(page, 10) || 1) - 1;
919
+ setPageSize(table, parseInt(size, 10) || p.settings.size || 10, p);
895
920
  moveToPage(table, p, true);
921
+ hideRows(table, p);
896
922
  updatePageDisplay(table, p, false);
897
923
  });
898
924
 
@@ -0,0 +1,605 @@
1
+ /*! Dragtable Mod for TableSorter - 2/7/2015 (v2.19.0) *//*
2
+ * Requires
3
+ * tablesorter v2.8+
4
+ * jQuery 1.7+
5
+ * jQuery UI (Core, Widget, Mouse & Sortable)
6
+ * Dragtable by Akottr (https://github.com/akottr) modified by Rob Garrison
7
+ */
8
+ /*jshint browser:true, jquery:true, unused:false */
9
+ /*global jQuery: false */
10
+ ;(function( $ ) {
11
+ 'use strict';
12
+ var undef,
13
+ ts = $.tablesorter;
14
+
15
+ ts.dragtable = {
16
+ create : function( _this ) {
17
+ var hasAccept,
18
+ $table = _this.originalTable.el,
19
+ handle = _this.options.dragHandle.replace('.', '');
20
+ $table.children('thead').children().children('th,td').each(function(){
21
+ var $this = $(this);
22
+ if ( !$this.find( _this.options.dragHandle + ',.' + handle + '-disabled' ).length ) {
23
+ hasAccept = _this.options.dragaccept ? $this.hasClass( _this.options.dragaccept.replace('.', '') ) : true;
24
+ $this
25
+ // sortClass includes a "." to match the tablesorter selectorSort option - for consistency
26
+ .wrapInner('<div class="' + _this.options.sortClass.replace('.', '') + '"/>')
27
+ // add handle class + "-disabled" to drag-disabled columns
28
+ .prepend('<div class="' + handle + ( hasAccept ? '' : '-disabled' ) + '"></div>');
29
+ }
30
+ });
31
+ },
32
+ start : function( table ) {
33
+ table = $( table )[0];
34
+ if ( table && table.config ) {
35
+ table.config.widgetOptions.dragtableLast = {
36
+ search : $( table ).data( 'lastSearch' ),
37
+ order : ts.dragtable.getOrder( table )
38
+ };
39
+ }
40
+ },
41
+ update : function( _this ) {
42
+ var t, list, val,
43
+ dragTable = _this.originalTable,
44
+ table = dragTable.el[ 0 ],
45
+ $table = $( table ),
46
+ c = table.config,
47
+ wo = c && c.widgetOptions,
48
+ startIndex = dragTable.startIndex - 1,
49
+ endIndex = dragTable.endIndex - 1,
50
+ columnOrder = ts.dragtable.getOrder( table ) || [],
51
+ hasFilters = ts.hasWidget( $table, 'filter' ) || false,
52
+ last = wo && wo.dragtableLast || {},
53
+ // update moved filters
54
+ filters = [];
55
+
56
+ // only trigger updateAll if column order changed
57
+ if ( ( last.order || [] ).join( '' ) !== columnOrder.join( '' ) ) {
58
+
59
+ if ( c.sortList.length ) {
60
+ // must deep extend (nested arrays) to prevent list from changing with c.sortList
61
+ list = $.extend( true, [], c.sortList );
62
+ $.each( columnOrder, function( indx, value ) {
63
+ val = ts.isValueInArray( parseInt( value, 10 ), list );
64
+ if ( value !== last.order[ indx ] && val >= 0 ) {
65
+ c.sortList[ val ][ 0 ] = indx;
66
+ }
67
+ });
68
+ }
69
+
70
+ // update filter widget
71
+ if ( hasFilters ) {
72
+ $.each( last.search || [], function( indx ) {
73
+ filters[ indx ] = last.search[ columnOrder[ indx ] ];
74
+ });
75
+ }
76
+
77
+ // update preset editable widget columns
78
+ t = ( ts.hasWidget( c.$table, 'editable' ) || false ) ? wo.editable_columnsArray : false;
79
+ if ( t ) {
80
+ c.widgetOptions.editable_columnsArray = ts.dragtable.reindexArrayItem( t, startIndex, endIndex );
81
+ }
82
+ // update ignore math columns
83
+ t = ( ts.hasWidget( c.$table, 'math' ) || false ) ? wo.math_ignore : false;
84
+ if ( t ) {
85
+ c.widgetOptions.math_ignore = ts.dragtable.reindexArrayItem( t, startIndex, endIndex );
86
+ }
87
+ // update preset resizable widget widths
88
+ t = ( ts.hasWidget( c.$table, 'resizable' ) || false ) ? wo.resizable_widths : false;
89
+ if ( t ) {
90
+ // use zero-based indexes in the array
91
+ wo.resizable_widths = ts.dragtable.moveArrayItem( t, startIndex, endIndex );
92
+ }
93
+ /*
94
+ // chart widget WIP - there are other options that need to be rearranged!
95
+ t = ( ts.hasWidget( c.$table, 'chart' ) || false ) ? wo.chart_ignoreColumns : false;
96
+ if ( t ) {
97
+ // use zero-based indexes in the array
98
+ wo.chart_ignoreColumns = ts.dragtable.moveArrayItem( t, startIndex, endIndex );
99
+ }
100
+ */
101
+
102
+ $table.trigger('updateAll', [ false, function() {
103
+ if ( hasFilters ) {
104
+ setTimeout( function() {
105
+ // just update the filter values
106
+ c.lastCombinedFilter = null;
107
+ c.$table.data('lastSearch', filters);
108
+ ts.setFilters( $table, filters );
109
+ if ($.isFunction(_this.options.tablesorterComplete)) {
110
+ _this.options.tablesorterComplete( c.table );
111
+ }
112
+ }, 10 );
113
+ }
114
+ } ]);
115
+ }
116
+ },
117
+ getOrder : function( table ) {
118
+ return $( table ).children( 'thead' ).children( '.' + ts.css.headerRow ).children().map( function() {
119
+ return $( this ).attr( 'data-column' );
120
+ }).get() || [];
121
+ },
122
+ // bubble the moved col left or right
123
+ startColumnMove : function( dragTable ) {
124
+ var $cols,
125
+ c = dragTable.el[ 0 ].config,
126
+ startIndex = dragTable.startIndex - 1,
127
+ endIndex = dragTable.endIndex - 1,
128
+ cols = c.columns - 1,
129
+ pos = endIndex === cols ? false : endIndex <= startIndex,
130
+ $rows = c.$table.children().children( 'tr' );
131
+ if ( c.debug ) {
132
+ ts.log( 'Inserting column ' + startIndex + ( pos ? ' before' : ' after' ) + ' column ' + endIndex );
133
+ }
134
+ $rows.each( function() {
135
+ $cols = $( this ).children();
136
+ $cols.eq( startIndex )[ pos ? 'insertBefore' : 'insertAfter' ]( $cols.eq( endIndex ) );
137
+ });
138
+ // rearrange col in colgroup
139
+ $cols = c.$table.children( 'colgroup' ).children();
140
+ $cols.eq( startIndex )[ pos ? 'insertBefore' : 'insertAfter' ]( $cols.eq( endIndex ) );
141
+ },
142
+ swapNodes : function( a, b ) {
143
+ var indx, aparent, asibling,
144
+ len = a.length;
145
+ for ( indx = 0; indx < len; indx++ ) {
146
+ aparent = a[ indx ].parentNode;
147
+ asibling = a[ indx ].nextSibling === b[ indx ] ? a[ indx ] : a[ indx ].nextSibling;
148
+ b[ indx ].parentNode.insertBefore( a[ indx ], b[ indx ] );
149
+ aparent.insertBefore( b[ indx ], asibling );
150
+ }
151
+ },
152
+ // http://stackoverflow.com/a/5306832/145346
153
+ moveArrayItem : function( array, oldIndex, newIndex ) {
154
+ var indx, len = array.length;
155
+ if ( newIndex >= len ) {
156
+ indx = newIndex - len;
157
+ while ( ( indx-- ) + 1 ) {
158
+ array.push( undef );
159
+ }
160
+ }
161
+ array.splice( newIndex, 0, array.splice( oldIndex, 1 )[ 0 ] );
162
+ return array;
163
+ },
164
+ reindexArrayItem : function( array, oldIndex, newIndex ) {
165
+ var nIndx = $.inArray( newIndex, array ),
166
+ oIndx = $.inArray( oldIndex, array ),
167
+ max = Math.max.apply( Math, array ),
168
+ arry = [];
169
+ // columns in the array were swapped so return original array
170
+ if ( nIndx >= 0 && oIndx >= 0 ) {
171
+ return array;
172
+ }
173
+ // columns not in the array were moved
174
+ $.each( array, function( indx, value ) {
175
+ // column (not in array) inserted between indexes
176
+ if ( newIndex < oldIndex ) {
177
+ // ( [ 0,1,2,3 ], 5, 1 ) -> column inserted between 0 & 1 => [ 0,2,3,4 ]
178
+ if ( value >= newIndex ) {
179
+ // 5 -> 1 [ 0, 2, 3 ] then 1 -> 0 [ 1, 2, 3 ]
180
+ arry.push( value + ( value < oldIndex ? 1 : 0 ) );
181
+ } else {
182
+ arry.push( value );
183
+ }
184
+ } else if ( newIndex > oldIndex ) {
185
+ // ( [ 0,1,2,3 ], 1, 5 ) -> column in array moved outside => [ 0,1,2,5 ]
186
+ if ( value === oldIndex ) {
187
+ arry.push( newIndex );
188
+ } else if ( value < newIndex && value >= oldIndex ) {
189
+ arry.push( value - 1 );
190
+ } else if ( value <= newIndex ) {
191
+ arry.push( value );
192
+ } else if ( value > oldIndex ) {
193
+ arry.push( value + ( value < newIndex ? 0 : 1 ) );
194
+ }
195
+ }
196
+ });
197
+ return arry.sort();
198
+ }
199
+ };
200
+
201
+ /*!
202
+ * dragtable
203
+ * _____ _
204
+ * | |___ _| |
205
+ * | | | | . | . |
206
+ * |_|_|_|___|___|
207
+ *
208
+ * @Version 2.0.14 MOD
209
+ *
210
+ * Copyright (c) 2010-2013, Andres akottr@gmail.com
211
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
212
+ * and GPL (GPL-LICENSE.txt) licenses.
213
+ *
214
+ * Inspired by the the dragtable from Dan Vanderkam (danvk.org/dragtable/)
215
+ * Thanks to the jquery and jqueryui comitters
216
+ *
217
+ * Any comment, bug report, feature-request is welcome
218
+ * Feel free to contact me.
219
+ */
220
+
221
+ /* TOKNOW:
222
+ * For IE7 you need this css rule:
223
+ * table {
224
+ * border-collapse: collapse;
225
+ * }
226
+ * Or take a clean reset.css (see http://meyerweb.com/eric/tools/css/reset/)
227
+ */
228
+
229
+ /* TODO: investigate
230
+ * Does not work properly with css rule:
231
+ * html {
232
+ * overflow: -moz-scrollbars-vertical;
233
+ * }
234
+ * Workaround:
235
+ * Fixing Firefox issues by scrolling down the page
236
+ * http://stackoverflow.com/questions/2451528/jquery-ui-sortable-scroll-helper-element-offset-firefox-issue
237
+ *
238
+ * var start = $.noop;
239
+ * var beforeStop = $.noop;
240
+ * if($.browser.mozilla) {
241
+ * var start = function (event, ui) {
242
+ * if( ui.helper !== undefined )
243
+ * ui.helper.css('position','absolute').css('margin-top', $(window).scrollTop() );
244
+ * }
245
+ * var beforeStop = function (event, ui) {
246
+ * if( ui.offset !== undefined )
247
+ * ui.helper.css('margin-top', 0);
248
+ * }
249
+ * }
250
+ *
251
+ * and pass this as start and stop function to the sortable initialisation
252
+ * start: start,
253
+ * beforeStop: beforeStop
254
+ */
255
+ /*
256
+ * Special thx to all pull requests comitters
257
+ */
258
+
259
+ $.widget("akottr.dragtable", {
260
+ options: {
261
+ revert: false, // smooth revert
262
+ dragHandle: '.table-handle', // handle for moving cols, if not exists the whole 'th' is the handle
263
+ maxMovingRows: 40, // 1 -> only header. 40 row should be enough, the rest is usually not in the viewport
264
+ excludeFooter: false, // excludes the footer row(s) while moving other columns. Make sense if there is a footer with a colspan. */
265
+ onlyHeaderThreshold: 100, // TODO: not implemented yet, switch automatically between entire col moving / only header moving
266
+ dragaccept: null, // draggable cols -> default all
267
+ persistState: null, // url or function -> plug in your custom persistState function right here. function call is persistState(originalTable)
268
+ restoreState: null, // JSON-Object or function: some kind of experimental aka Quick-Hack TODO: do it better
269
+ exact: true, // removes pixels, so that the overlay table width fits exactly the original table width
270
+ clickDelay: 10, // ms to wait before rendering sortable list and delegating click event
271
+ containment: null, // @see http://api.jqueryui.com/sortable/#option-containment, use it if you want to move in 2 dimesnions (together with axis: null)
272
+ cursor: 'move', // @see http://api.jqueryui.com/sortable/#option-cursor
273
+ cursorAt: false, // @see http://api.jqueryui.com/sortable/#option-cursorAt
274
+ distance: 0, // @see http://api.jqueryui.com/sortable/#option-distance, for immediate feedback use "0"
275
+ tolerance: 'pointer', // @see http://api.jqueryui.com/sortable/#option-tolerance
276
+ axis: 'x', // @see http://api.jqueryui.com/sortable/#option-axis, Only vertical moving is allowed. Use 'x' or null. Use this in conjunction with the 'containment' setting
277
+ beforeStart: $.noop, // returning FALSE will stop the execution chain.
278
+ beforeMoving: $.noop,
279
+ beforeReorganize: $.noop,
280
+ beforeStop: $.noop,
281
+ // new options
282
+ tablesorterComplete: null,
283
+ sortClass : '.sorter'
284
+ },
285
+ originalTable: {
286
+ el: null,
287
+ selectedHandle: null,
288
+ sortOrder: null,
289
+ startIndex: 0,
290
+ endIndex: 0
291
+ },
292
+ sortableTable: {
293
+ el: $(),
294
+ selectedHandle: $(),
295
+ movingRow: $()
296
+ },
297
+ persistState: function() {
298
+ var _this = this;
299
+ this.originalTable.el.find('th').each(function(i) {
300
+ if (this.id !== '') {
301
+ _this.originalTable.sortOrder[this.id] = i;
302
+ }
303
+ });
304
+ $.ajax({
305
+ url: this.options.persistState,
306
+ data: this.originalTable.sortOrder
307
+ });
308
+ },
309
+ /*
310
+ * persistObj looks like
311
+ * {'id1':'2','id3':'3','id2':'1'}
312
+ * table looks like
313
+ * | id2 | id1 | id3 |
314
+ */
315
+ _restoreState: function(persistObj) {
316
+ for (var n in persistObj) {
317
+ if (n in persistObj) {
318
+ this.originalTable.startIndex = $('#' + n).closest('th').prevAll().length + 1;
319
+ this.originalTable.endIndex = parseInt(persistObj[n], 10) + 1;
320
+ this._bubbleCols();
321
+ }
322
+ }
323
+ },
324
+ // bubble the moved col left or right
325
+ _bubbleCols: function() {
326
+ ts.dragtable.startColumnMove(this.originalTable);
327
+ },
328
+ _rearrangeTableBackroundProcessing: function() {
329
+ var _this = this;
330
+ return function() {
331
+ _this._bubbleCols();
332
+ _this.options.beforeStop(_this.originalTable);
333
+ _this.sortableTable.el.remove();
334
+ restoreTextSelection();
335
+ ts.dragtable.update(_this);
336
+ // persist state if necessary
337
+ if ($.isFunction(_this.options.persistState)) {
338
+ _this.options.persistState(_this.originalTable);
339
+ } else {
340
+ _this.persistState();
341
+ }
342
+
343
+ };
344
+ },
345
+ _rearrangeTable: function() {
346
+ var _this = this;
347
+ return function() {
348
+ // remove handler-class -> handler is now finished
349
+ _this.originalTable.selectedHandle.removeClass('dragtable-handle-selected');
350
+ // add disabled class -> reorgorganisation starts soon
351
+ _this.sortableTable.el.sortable("disable");
352
+ _this.sortableTable.el.addClass('dragtable-disabled');
353
+ _this.options.beforeReorganize(_this.originalTable, _this.sortableTable);
354
+ // do reorganisation asynchronous
355
+ // for chrome a little bit more than 1 ms because we want to force a rerender
356
+ _this.originalTable.endIndex = _this.sortableTable.movingRow.prevAll().length + 1;
357
+ setTimeout(_this._rearrangeTableBackroundProcessing(), 50);
358
+ };
359
+ },
360
+ /*
361
+ * Disrupts the table. The original table stays the same.
362
+ * But on a layer above the original table we are constructing a list (ul > li)
363
+ * each li with a separate table representig a single col of the original table.
364
+ */
365
+ _generateSortable: function(e) {
366
+ if (e.cancelBubble) {
367
+ e.cancelBubble = true;
368
+ } else {
369
+ e.stopPropagation();
370
+ }
371
+ var _this = this;
372
+ // table attributes
373
+ var attrs = this.originalTable.el[0].attributes;
374
+ var tableAttrsString = '';
375
+ for (var i = 0; i < attrs.length; i++) {
376
+ if ( (attrs[i].value || attrs[i].nodeValue) && attrs[i].nodeName != 'id' && attrs[i].nodeName != 'width') {
377
+ tableAttrsString += attrs[i].nodeName + '="' + ( attrs[i].value || attrs[i].nodeValue ) + '" ';
378
+ }
379
+ }
380
+ // row attributes
381
+ var rowAttrsArr = [];
382
+ //compute height, special handling for ie needed :-(
383
+ var heightArr = [];
384
+
385
+ // don't save tfoot attributes because it messes up indexing
386
+ _this.originalTable.el.children('thead, tbody').children('tr:visible').slice(0, _this.options.maxMovingRow).each(function() {
387
+ // row attributes
388
+ var attrs = this.attributes;
389
+ var attrsString = '';
390
+ for (var j = 0; j < attrs.length; j++) {
391
+ if ( (attrs[j].value || attrs[j].nodeValue ) && attrs[j].nodeName != 'id') {
392
+ attrsString += ' ' + attrs[j].nodeName + '="' + ( attrs[j].value || attrs[j].nodeValue ) + '"';
393
+ }
394
+ }
395
+ rowAttrsArr.push(attrsString);
396
+ heightArr.push($(this).height());
397
+ });
398
+
399
+ // compute width, no special handling for ie needed :-)
400
+ var widthArr = [];
401
+ // compute total width, needed for not wrapping around after the screen ends (floating)
402
+ var totalWidth = 0;
403
+ /* Find children thead and tbody.
404
+ * Only to process the immediate tr-children. Bugfix for inner tables
405
+ */
406
+ var thtb = _this.originalTable.el.children();
407
+ var headerRows = thtb.filter('thead').children('tr:visible');
408
+ var visibleRows = thtb.filter('tbody').children('tr:visible');
409
+
410
+ headerRows.eq(0).children('th, td').filter(':visible').each(function() {
411
+ var w = $(this).outerWidth();
412
+ widthArr.push(w);
413
+ totalWidth += w;
414
+ });
415
+ if(_this.options.exact) {
416
+ var difference = totalWidth - _this.originalTable.el.outerWidth();
417
+ widthArr[0] -= difference;
418
+ }
419
+ // one extra px on right and left side
420
+ totalWidth += 2;
421
+
422
+ var captionHeight = 0;
423
+ thtb.filter('caption').each(function(){
424
+ captionHeight += $(this).outerHeight();
425
+ });
426
+
427
+ var sortableHtml = '<ul class="dragtable-sortable" style="position:absolute; width:' + totalWidth + 'px;">';
428
+ var sortableColumn = [];
429
+ // assemble the needed html
430
+ // build list
431
+ var rowIndex,
432
+ columns = headerRows.eq(0).children('th, td').length;
433
+ /*jshint loopfunc:true */
434
+ for (i = 0; i < columns; i++) {
435
+ var row = headerRows.children(':nth-child(' + (i + 1) + ')');
436
+ if (row.is(':visible')) {
437
+ rowIndex = 0;
438
+ sortableColumn[i] = '<li style="width:' + row.outerWidth() + 'px;">' +
439
+ '<table ' + tableAttrsString + '>' +
440
+ ( captionHeight ? '<caption style="height:' + captionHeight + 'px;"></caption>' : '' ) +
441
+ '<thead>';
442
+ // thead
443
+ headerRows.each(function(j){
444
+ sortableColumn[i] += '<tr ' + rowAttrsArr[rowIndex++] +
445
+ ( heightArr[j] ? ' style="height:' + heightArr[j] + 'px;"' : '' ) + '>' +
446
+ row[j].outerHTML + '</tr>';
447
+ });
448
+ sortableColumn[i] += '</thead><tbody>';
449
+ // tbody
450
+ row = visibleRows.children(':nth-child(' + (i + 1) + ')');
451
+ if (_this.options.maxMovingRows > 1) {
452
+ row = row.add(visibleRows.children(':nth-child(' + (i + 1) + ')').slice(0, _this.options.maxMovingRows - 1));
453
+ }
454
+ row.each(function(j) {
455
+ sortableColumn[i] += '<tr ' + rowAttrsArr[rowIndex++] +
456
+ ( heightArr[j] ? ' style="height:' + heightArr[j] + 'px;"' : '' ) + '>' +
457
+ this.outerHTML + '</tr>';
458
+ });
459
+ sortableColumn[i] += '</tbody>';
460
+
461
+ // add footer to end of max Rows
462
+ if (!_this.options.excludeFooter) {
463
+ sortableColumn[i] += '<tfoot><tr ' + rowAttrsArr[rowIndex++] + '>' +
464
+ thtb.filter('tfoot').children('tr:visible').children()[i].outerHTML + '</tr></tfoot>';
465
+ }
466
+ sortableColumn[i] += '</table></li>';
467
+ }
468
+ }
469
+ sortableHtml += sortableColumn.join('') + '</ul>';
470
+ this.sortableTable.el = this.originalTable.el.before(sortableHtml).prev();
471
+ // set width if necessary
472
+ this.sortableTable.el.find('> li > table').each(function(i) {
473
+ $(this).css('width', widthArr[i] + 'px');
474
+ });
475
+
476
+ // assign this.sortableTable.selectedHandle
477
+ this.sortableTable.selectedHandle = this.sortableTable.el.find('th .dragtable-handle-selected');
478
+
479
+ var items = !this.options.dragaccept ? 'li' : 'li:has(' + this.options.dragaccept + ')';
480
+ this.sortableTable.el.sortable({
481
+ items: items,
482
+ stop: this._rearrangeTable(),
483
+ // pass thru options for sortable widget
484
+ revert: this.options.revert,
485
+ tolerance: this.options.tolerance,
486
+ containment: this.options.containment,
487
+ cursor: this.options.cursor,
488
+ cursorAt: this.options.cursorAt,
489
+ distance: this.options.distance,
490
+ axis: this.options.axis
491
+ });
492
+
493
+ // assign start index
494
+ this.originalTable.startIndex = $(e.target).closest('th,td').prevAll().length + 1;
495
+ this.options.beforeMoving(this.originalTable, this.sortableTable);
496
+ // Start moving by delegating the original event to the new sortable table
497
+ this.sortableTable.movingRow = this.sortableTable.el.children('li:nth-child(' + this.originalTable.startIndex + ')');
498
+
499
+ // prevent the user from drag selecting "highlighting" surrounding page elements
500
+ disableTextSelection();
501
+ // clone the initial event and trigger the sort with it
502
+ this.sortableTable.movingRow.trigger($.extend($.Event(e.type), {
503
+ which: 1,
504
+ clientX: e.clientX,
505
+ clientY: e.clientY,
506
+ pageX: e.pageX,
507
+ pageY: e.pageY,
508
+ screenX: e.screenX,
509
+ screenY: e.screenY
510
+ }));
511
+
512
+ // Some inner divs to deliver the posibillity to style the placeholder more sophisticated
513
+ var placeholder = this.sortableTable.el.find('.ui-sortable-placeholder');
514
+ if(placeholder.height() > 0) {
515
+ placeholder.css('height', this.sortableTable.el.find('.ui-sortable-helper').height());
516
+ }
517
+
518
+ placeholder.html('<div class="outer" style="height:100%;"><div class="inner" style="height:100%;"></div></div>');
519
+ },
520
+ bindTo: {},
521
+ _create: function() {
522
+ var _this = this;
523
+ _this.originalTable = {
524
+ el: _this.element,
525
+ selectedHandle: $(),
526
+ sortOrder: {},
527
+ startIndex: 0,
528
+ endIndex: 0
529
+ };
530
+ ts.dragtable.create( _this );
531
+ // filter only the cols that are accepted
532
+ _this.bindTo = '> thead > tr > ' + ( _this.options.dragaccept || 'th, td' );
533
+ // bind draggable to handle if exists
534
+ if (_this.element.find(_this.bindTo).find(_this.options.dragHandle).length) {
535
+ _this.bindTo += ' ' + _this.options.dragHandle;
536
+ }
537
+ // restore state if necessary
538
+ if ($.isFunction(_this.options.restoreState)) {
539
+ _this.options.restoreState(_this.originalTable);
540
+ } else {
541
+ _this._restoreState(_this.options.restoreState);
542
+ }
543
+ _this.originalTable.el.on( 'mousedown.dragtable', _this.bindTo, function(evt) {
544
+ // listen only to left mouse click
545
+ if (evt.which!==1) return;
546
+ ts.dragtable.start( _this.originalTable.el );
547
+ if (_this.options.beforeStart(_this.originalTable) === false) {
548
+ return;
549
+ }
550
+ clearTimeout(_this.downTimer);
551
+ _this.downTimer = setTimeout(function() {
552
+ _this.originalTable.selectedHandle = $(_this);
553
+ _this.originalTable.selectedHandle.addClass('dragtable-handle-selected');
554
+ _this._generateSortable(evt);
555
+ }, _this.options.clickDelay);
556
+ }).on( 'mouseup.dragtable', _this.options.dragHandle,function() {
557
+ clearTimeout(_this.downTimer);
558
+ });
559
+ },
560
+ redraw: function(){
561
+ this.destroy();
562
+ this._create();
563
+ },
564
+ destroy: function() {
565
+ this.originalTable.el.off('mousedown.dragtable mouseup.dragtable', this.bindTo);
566
+ $.Widget.prototype.destroy.apply(this, arguments); // default destroy
567
+ // now do other stuff particular to this widget
568
+ }
569
+ });
570
+
571
+ /** closure-scoped "private" functions **/
572
+ var body_onselectstart_save = $(document.body).attr('onselectstart'),
573
+ body_unselectable_save = $(document.body).attr('unselectable');
574
+
575
+ // css properties to disable user-select on the body tag by appending a <style> tag to the <head>
576
+ // remove any current document selections
577
+ function disableTextSelection() {
578
+ // jQuery doesn't support the element.text attribute in MSIE 8
579
+ // http://stackoverflow.com/questions/2692770/style-style-textcss-appendtohead-does-not-work-in-ie
580
+ var $style = $('<style id="__dragtable_disable_text_selection__" type="text/css">body { -ms-user-select:none;-moz-user-select:-moz-none;-khtml-user-select:none;-webkit-user-select:none;user-select:none; }</style>');
581
+ $(document.head).append($style);
582
+ $(document.body).attr('onselectstart', 'return false;').attr('unselectable', 'on');
583
+ if (window.getSelection) {
584
+ window.getSelection().removeAllRanges();
585
+ } else {
586
+ document.selection.empty(); // MSIE http://msdn.microsoft.com/en-us/library/ms535869%28v=VS.85%29.aspx
587
+ }
588
+ }
589
+
590
+ // remove the <style> tag, and restore the original <body> onselectstart attribute
591
+ function restoreTextSelection() {
592
+ $('#__dragtable_disable_text_selection__').remove();
593
+ if (body_onselectstart_save) {
594
+ $(document.body).attr('onselectstart', body_onselectstart_save);
595
+ } else {
596
+ $(document.body).removeAttr('onselectstart');
597
+ }
598
+ if (body_unselectable_save) {
599
+ $(document.body).attr('unselectable', body_unselectable_save);
600
+ } else {
601
+ $(document.body).removeAttr('unselectable');
602
+ }
603
+ }
604
+
605
+ })(jQuery);