jquery-tablesorter 1.5.0 → 1.6.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.
@@ -1,5 +1,5 @@
1
- /*!
2
- * TableSorter 2.10.8 - Client-side table sorting with ease!
1
+ /**!
2
+ * TableSorter 2.11.1 - Client-side table sorting with ease!
3
3
  * @requires jQuery v1.2.6+
4
4
  *
5
5
  * Copyright (c) 2007 Christian Bach
@@ -24,7 +24,7 @@
24
24
 
25
25
  var ts = this;
26
26
 
27
- ts.version = "2.10.8";
27
+ ts.version = "2.11.1";
28
28
 
29
29
  ts.parsers = [];
30
30
  ts.widgets = [];
@@ -75,16 +75,17 @@
75
75
  // *** callbacks
76
76
  initialized : null, // function(table){},
77
77
 
78
- // *** css class names
79
- tableClass : 'tablesorter',
80
- cssAsc : 'tablesorter-headerAsc',
81
- cssChildRow : 'tablesorter-childRow', // previously "expand-child"
82
- cssDesc : 'tablesorter-headerDesc',
83
- cssHeader : 'tablesorter-header',
84
- cssHeaderRow : 'tablesorter-headerRow',
85
- cssIcon : 'tablesorter-icon', // if this class exists, a <i> will be added to the header automatically
86
- cssInfoBlock : 'tablesorter-infoOnly', // don't sort tbody with this class name
87
- cssProcessing : 'tablesorter-processing', // processing icon applied to header during sort/filter
78
+ // *** extra css class names
79
+ tableClass : '',
80
+ cssAsc : '',
81
+ cssDesc : '',
82
+ cssHeader : '',
83
+ cssHeaderRow : '',
84
+ cssProcessing : '', // processing icon applied to header during sort/filter
85
+
86
+ cssChildRow : 'tablesorter-childRow', // class name indiciating that a row is to be attached to the its parent
87
+ cssIcon : 'tablesorter-icon', // if this class exists, a <i> will be added to the header automatically
88
+ cssInfoBlock : 'tablesorter-infoOnly', // don't sort tbody with this class name (only one class name allowed here!)
88
89
 
89
90
  // *** selectors
90
91
  selectorHeaders : '> thead th, > thead td',
@@ -105,6 +106,20 @@
105
106
 
106
107
  };
107
108
 
109
+ // internal css classes - these will ALWAYS be added to
110
+ // the table and MUST only contain one class name - fixes #381
111
+ ts.css = {
112
+ table : 'tablesorter',
113
+ childRow : 'tablesorter-childRow',
114
+ header : 'tablesorter-header',
115
+ headerRow : 'tablesorter-headerRow',
116
+ icon : 'tablesorter-icon',
117
+ info : 'tablesorter-infoOnly',
118
+ processing : 'tablesorter-processing',
119
+ sortAsc : 'tablesorter-headerAsc',
120
+ sortDesc : 'tablesorter-headerDesc'
121
+ };
122
+
108
123
  /* debuging utils */
109
124
  function log(s) {
110
125
  if (typeof console !== "undefined" && typeof console.log !== "undefined") {
@@ -121,6 +136,15 @@
121
136
  ts.log = log;
122
137
  ts.benchmark = benchmark;
123
138
 
139
+ // $.isEmptyObject from jQuery v1.4
140
+ function isEmptyObject(obj) {
141
+ /*jshint forin: false */
142
+ for (var name in obj) {
143
+ return false;
144
+ }
145
+ return true;
146
+ }
147
+
124
148
  function getElementText(table, node, cellIndex) {
125
149
  if (!node) { return ""; }
126
150
  var c = table.config,
@@ -234,7 +258,7 @@
234
258
  }
235
259
  for (k = 0; k < b.length; k++) {
236
260
  tc.cache[k] = { row: [], normalized: [] };
237
- // ignore tbodies with class name from css.cssInfoBlock
261
+ // ignore tbodies with class name from c.cssInfoBlock
238
262
  if (!$(b[k]).hasClass(tc.cssInfoBlock)) {
239
263
  totalRows = (b[k] && b[k].rows.length) || 0;
240
264
  totalCells = (b[k].rows[0] && b[k].rows[0].cells.length) || 0;
@@ -281,7 +305,7 @@
281
305
  c2 = c.cache,
282
306
  r, n, totalRows, checkCell, $bk, $tb,
283
307
  i, j, k, l, pos, appendTime;
284
- if (!c2[0]) { return; } // empty table - fixes #206
308
+ if (isEmptyObject(c2)) { return; } // empty table - fixes #206/#346
285
309
  if (c.debug) {
286
310
  appendTime = new Date();
287
311
  }
@@ -319,6 +343,7 @@
319
343
  if (!init) { ts.applyWidget(table); }
320
344
  // trigger sortend
321
345
  $(table).trigger("sortEnd", table);
346
+ $(table).trigger("updateComplete", table);
322
347
  }
323
348
 
324
349
  // computeTableHeaderCellIndexes from:
@@ -380,7 +405,7 @@
380
405
  if (c.debug) {
381
406
  time = new Date();
382
407
  }
383
- i = c.cssIcon ? '<i class="' + c.cssIcon + '"></i>' : ''; // add icon if cssIcon option exists
408
+ i = c.cssIcon ? '<i class="' + c.cssIcon + ' ' + ts.css.icon + '"></i>' : ''; // add icon if cssIcon option exists
384
409
  c.$headers = $(table).find(c.selectorHeaders).each(function(index) {
385
410
  $t = $(this);
386
411
  ch = c.headers[index];
@@ -403,11 +428,11 @@
403
428
  if (typeof lock !== 'undefined' && lock !== false) {
404
429
  this.order = this.lockedOrder = formatSortingOrder(lock) ? [1,1,1] : [0,0,0];
405
430
  }
406
- $t.addClass(c.cssHeader);
431
+ $t.addClass(ts.css.header + ' ' + c.cssHeader);
407
432
  // add cell to headerList
408
433
  c.headerList[index] = this;
409
434
  // add to parent in case there are multiple rows
410
- $t.parent().addClass(c.cssHeaderRow);
435
+ $t.parent().addClass(ts.css.headerRow + ' ' + c.cssHeaderRow);
411
436
  // allow keyboard cursor to focus on element
412
437
  $t.attr("tabindex", 0);
413
438
  });
@@ -443,7 +468,7 @@
443
468
  var f, i, j, l,
444
469
  c = table.config,
445
470
  list = c.sortList,
446
- css = [c.cssAsc, c.cssDesc],
471
+ css = [ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc],
447
472
  // find the footer
448
473
  $t = $(table).find('tfoot tr').children().removeClass(css.join(' '));
449
474
  // remove all header information
@@ -474,7 +499,8 @@
474
499
  if (table.config.widthFixed && $(table).find('colgroup').length === 0) {
475
500
  var colgroup = $('<colgroup>'),
476
501
  overallWidth = $(table).width();
477
- $(table.tBodies[0]).find("tr:first").children("td").each(function() {
502
+ // only add col for visible columns - fixes #371
503
+ $(table.tBodies[0]).find("tr:first").children("td:visible").each(function() {
478
504
  colgroup.append($('<col>').css('width', parseInt(($(this).width()/overallWidth)*1000, 10)/10 + '%'));
479
505
  });
480
506
  $(table).prepend(colgroup);
@@ -516,7 +542,7 @@
516
542
  i = cell;
517
543
  c.$headers.each(function() {
518
544
  // only reset counts on columns that weren't just clicked on and if not included in a multisort
519
- if (this !== i && (k || !$(this).is('.' + c.cssDesc + ',.' + c.cssAsc))) {
545
+ if (this !== i && (k || !$(this).is('.' + ts.css.sortDesc + ',.' + ts.css.sortAsc))) {
520
546
  this.count = -1;
521
547
  }
522
548
  });
@@ -606,7 +632,7 @@
606
632
  var dir = 0, tc = table.config,
607
633
  sortList = tc.sortList, l = sortList.length, bl = table.tBodies.length,
608
634
  sortTime, i, k, c, colMax, cache, lc, s, order, orgOrderCol;
609
- if (tc.serverSideSorting || !tc.cache[0]) { // empty table - fixes #206
635
+ if (tc.serverSideSorting || isEmptyObject(tc.cache)) { // empty table - fixes #206/#346
610
636
  return;
611
637
  }
612
638
  if (tc.debug) { sortTime = new Date(); }
@@ -641,7 +667,10 @@
641
667
  }
642
668
 
643
669
  function resortComplete($table, callback){
644
- $table.trigger('updateComplete');
670
+ var c = $table[0].config;
671
+ if (c.pager && !c.pager.ajax) {
672
+ $table.trigger('updateComplete');
673
+ }
645
674
  if (typeof callback === "function") {
646
675
  callback($table[0]);
647
676
  }
@@ -671,16 +700,16 @@
671
700
  .bind('mousedown.tablesorter mouseup.tablesorter sort.tablesorter keypress.tablesorter', function(e, external) {
672
701
  // only recognize left clicks or enter
673
702
  if ( ((e.which || e.button) !== 1 && !/sort|keypress/.test(e.type)) || (e.type === 'keypress' && e.which !== 13) ) {
674
- return false;
703
+ return;
675
704
  }
676
705
  // ignore long clicks (prevents resizable widget from initializing a sort)
677
- if (e.type === 'mouseup' && external !== true && (new Date().getTime() - downTime > 250)) { return false; }
706
+ if (e.type === 'mouseup' && external !== true && (new Date().getTime() - downTime > 250)) { return; }
678
707
  // set timer on mousedown
679
708
  if (e.type === 'mousedown') {
680
709
  downTime = new Date().getTime();
681
710
  return e.target.tagName === "INPUT" ? '' : !c.cancelSelection;
682
711
  }
683
- if (c.delayInit && !c.cache) { buildCache(table); }
712
+ if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); }
684
713
  // jQuery v1.2.6 doesn't have closest()
685
714
  var $cell = /TH|TD/.test(this.tagName) ? $(this) : $(this).parents('th, td').filter(':first'), cell = $cell[0];
686
715
  if (!cell.sortDisabled) {
@@ -768,12 +797,15 @@
768
797
  checkResort($this, resort, callback);
769
798
  })
770
799
  .bind("sorton.tablesorter", function(e, list, callback, init) {
800
+ var c = table.config;
771
801
  e.stopPropagation();
772
802
  $this.trigger("sortStart", this);
773
803
  // update header count index
774
804
  updateHeaderSortCount(table, list);
775
805
  // set css for headers
776
806
  setHeadersCss(table);
807
+ // fixes #346
808
+ if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); }
777
809
  $this.trigger("sortBegin", this);
778
810
  // sort the table and append it to the dom
779
811
  multisort(table);
@@ -811,83 +843,99 @@
811
843
  /* public methods */
812
844
  ts.construct = function(settings) {
813
845
  return this.each(function() {
814
- // if no thead or tbody, or tablesorter is already present, quit
815
- if (!this.tHead || this.tBodies.length === 0 || this.hasInitialized === true) {
816
- return (this.config && this.config.debug) ? log('stopping initialization! No thead, tbody or tablesorter has already been initialized') : '';
817
- }
818
- // declare
819
- var $this = $(this), table = this,
820
- c, k = '',
821
- m = $.metadata;
822
- // initialization flag
823
- table.hasInitialized = false;
824
- // table is being processed flag
825
- table.isProcessing = true;
826
- // new blank config object
827
- table.config = {};
828
- // merge and extend
829
- c = $.extend(true, table.config, ts.defaults, settings);
830
- // save the settings where they read
831
- $.data(table, "tablesorter", c);
832
- if (c.debug) { $.data( table, 'startoveralltimer', new Date()); }
833
- // constants
834
- c.supportsTextContent = $('<span>x</span>')[0].textContent === 'x';
835
- c.supportsDataObject = parseFloat($.fn.jquery) >= 1.4;
836
- // digit sort text location; keeping max+/- for backwards compatibility
837
- c.string = { 'max': 1, 'min': -1, 'max+': 1, 'max-': -1, 'zero': 0, 'none': 0, 'null': 0, 'top': true, 'bottom': false };
838
- // add table theme class only if there isn't already one there
839
- if (!/tablesorter\-/.test($this.attr('class'))) {
840
- k = (c.theme !== '' ? ' tablesorter-' + c.theme : '');
841
- }
842
- c.$table = $this.addClass(c.tableClass + k);
843
- c.$tbodies = $this.children('tbody:not(.' + c.cssInfoBlock + ')');
844
- // build headers
845
- buildHeaders(table);
846
- // fixate columns if the users supplies the fixedWidth option
847
- // do this after theme has been applied
848
- fixColumnWidth(table);
849
- // try to auto detect column type, and store in tables config
850
- buildParserCache(table);
851
- // build the cache for the tbody cells
852
- // delayInit will delay building the cache until the user starts a sort
853
- if (!c.delayInit) { buildCache(table); }
854
- // bind all header events and methods
855
- bindEvents(table);
856
- // get sort list from jQuery data or metadata
857
- // in jQuery < 1.4, an error occurs when calling $this.data()
858
- if (c.supportsDataObject && typeof $this.data().sortlist !== 'undefined') {
859
- c.sortList = $this.data().sortlist;
860
- } else if (m && ($this.metadata() && $this.metadata().sortlist)) {
861
- c.sortList = $this.metadata().sortlist;
862
- }
863
- // apply widget init code
864
- ts.applyWidget(table, true);
865
- // if user has supplied a sort list to constructor
866
- if (c.sortList.length > 0) {
867
- $this.trigger("sorton", [c.sortList, {}, !c.initWidgets]);
868
- } else if (c.initWidgets) {
869
- // apply widget format
870
- ts.applyWidget(table);
846
+ var table = this,
847
+ // merge & extend config options
848
+ c = $.extend(true, {}, ts.defaults, settings);
849
+ // create a table from data (build table widget)
850
+ if (!table.hasInitialized && ts.buildTable && this.tagName !== 'TABLE') {
851
+ // return the table (in case the original target is the table's container)
852
+ ts.buildTable(table, c);
871
853
  }
854
+ ts.setup(table, c);
855
+ });
856
+ };
872
857
 
873
- // show processesing icon
874
- if (c.showProcessing) {
875
- $this
876
- .unbind('sortBegin.tablesorter sortEnd.tablesorter')
877
- .bind('sortBegin.tablesorter sortEnd.tablesorter', function(e) {
878
- ts.isProcessing(table, e.type === 'sortBegin');
879
- });
880
- }
858
+ ts.setup = function(table, c) {
859
+ // if no thead or tbody, or tablesorter is already present, quit
860
+ if (!table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true) {
861
+ return c.debug ? log('stopping initialization! No table, thead, tbody or tablesorter has already been initialized') : '';
862
+ }
881
863
 
882
- // initialized
883
- table.hasInitialized = true;
884
- table.isProcessing = false;
885
- if (c.debug) {
886
- ts.benchmark("Overall initialization time", $.data( table, 'startoveralltimer'));
887
- }
888
- $this.trigger('tablesorter-initialized', table);
889
- if (typeof c.initialized === 'function') { c.initialized(table); }
890
- });
864
+ var k = '',
865
+ $this = $(table),
866
+ m = $.metadata;
867
+ // initialization flag
868
+ table.hasInitialized = false;
869
+ // table is being processed flag
870
+ table.isProcessing = true;
871
+ // make sure to store the config object
872
+ table.config = c;
873
+ // save the settings where they read
874
+ $.data(table, "tablesorter", c);
875
+ if (c.debug) { $.data( table, 'startoveralltimer', new Date()); }
876
+
877
+ // constants
878
+ c.supportsTextContent = $('<span>x</span>')[0].textContent === 'x';
879
+ // removing this in version 3 (only supports jQuery 1.7+)
880
+ c.supportsDataObject = (function(version) {
881
+ version[0] = parseInt(version[0], 10);
882
+ return (version[0] > 1) || (version[0] === 1 && parseInt(version[1], 10) >= 4);
883
+ })($.fn.jquery.split("."));
884
+ // digit sort text location; keeping max+/- for backwards compatibility
885
+ c.string = { 'max': 1, 'min': -1, 'max+': 1, 'max-': -1, 'zero': 0, 'none': 0, 'null': 0, 'top': true, 'bottom': false };
886
+ // add table theme class only if there isn't already one there
887
+ if (!/tablesorter\-/.test($this.attr('class'))) {
888
+ k = (c.theme !== '' ? ' tablesorter-' + c.theme : '');
889
+ }
890
+ c.$table = $this.addClass(ts.css.table + ' ' + c.tableClass + k);
891
+ c.$tbodies = $this.children('tbody:not(.' + c.cssInfoBlock + ')');
892
+ c.widgetInit = {}; // keep a list of initialized widgets
893
+ // build headers
894
+ buildHeaders(table);
895
+ // fixate columns if the users supplies the fixedWidth option
896
+ // do this after theme has been applied
897
+ fixColumnWidth(table);
898
+ // try to auto detect column type, and store in tables config
899
+ buildParserCache(table);
900
+ // build the cache for the tbody cells
901
+ // delayInit will delay building the cache until the user starts a sort
902
+ if (!c.delayInit) { buildCache(table); }
903
+ // bind all header events and methods
904
+ bindEvents(table);
905
+ // get sort list from jQuery data or metadata
906
+ // in jQuery < 1.4, an error occurs when calling $this.data()
907
+ if (c.supportsDataObject && typeof $this.data().sortlist !== 'undefined') {
908
+ c.sortList = $this.data().sortlist;
909
+ } else if (m && ($this.metadata() && $this.metadata().sortlist)) {
910
+ c.sortList = $this.metadata().sortlist;
911
+ }
912
+ // apply widget init code
913
+ ts.applyWidget(table, true);
914
+ // if user has supplied a sort list to constructor
915
+ if (c.sortList.length > 0) {
916
+ $this.trigger("sorton", [c.sortList, {}, !c.initWidgets]);
917
+ } else if (c.initWidgets) {
918
+ // apply widget format
919
+ ts.applyWidget(table);
920
+ }
921
+
922
+ // show processesing icon
923
+ if (c.showProcessing) {
924
+ $this
925
+ .unbind('sortBegin.tablesorter sortEnd.tablesorter')
926
+ .bind('sortBegin.tablesorter sortEnd.tablesorter', function(e) {
927
+ ts.isProcessing(table, e.type === 'sortBegin');
928
+ });
929
+ }
930
+
931
+ // initialized
932
+ table.hasInitialized = true;
933
+ table.isProcessing = false;
934
+ if (c.debug) {
935
+ ts.benchmark("Overall initialization time", $.data( table, 'startoveralltimer'));
936
+ }
937
+ $this.trigger('tablesorter-initialized', table);
938
+ if (typeof c.initialized === 'function') { c.initialized(table); }
891
939
  };
892
940
 
893
941
  // *** Process table ***
@@ -896,7 +944,7 @@
896
944
  table = $(table);
897
945
  var c = table[0].config,
898
946
  // default to all headers
899
- $h = $ths || table.find('.' + c.cssHeader);
947
+ $h = $ths || table.find('.' + ts.css.header);
900
948
  if (toggle) {
901
949
  if (c.sortList.length > 0) {
902
950
  // get headers from the sortList
@@ -905,9 +953,9 @@
905
953
  return this.sortDisabled ? false : ts.isValueInArray( parseFloat($(this).attr('data-column')), c.sortList);
906
954
  });
907
955
  }
908
- $h.addClass(c.cssProcessing);
956
+ $h.addClass(ts.css.processing + ' ' + c.cssProcessing);
909
957
  } else {
910
- $h.removeClass(c.cssProcessing);
958
+ $h.removeClass(ts.css.processing + ' ' + c.cssProcessing);
911
959
  }
912
960
  };
913
961
 
@@ -951,7 +999,7 @@
951
999
  ts.refreshWidgets(table, true, true);
952
1000
  var $t = $(table), c = table.config,
953
1001
  $h = $t.find('thead:first'),
954
- $r = $h.find('tr.' + c.cssHeaderRow).removeClass(c.cssHeaderRow),
1002
+ $r = $h.find('tr.' + ts.css.headerRow).removeClass(ts.css.headerRow + ' ' + c.cssHeaderRow),
955
1003
  $f = $t.find('tfoot:first > tr').children('th, td');
956
1004
  // remove widget added rows, just in case
957
1005
  $h.find('tr').not($r).remove();
@@ -960,12 +1008,12 @@
960
1008
  .removeData('tablesorter')
961
1009
  .unbind('sortReset update updateAll updateRows updateCell addRows sorton appendCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd '.split(' ').join('.tablesorter '));
962
1010
  c.$headers.add($f)
963
- .removeClass(c.cssHeader + ' ' + c.cssAsc + ' ' + c.cssDesc)
1011
+ .removeClass( [ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc].join(' ') )
964
1012
  .removeAttr('data-column');
965
1013
  $r.find(c.selectorSort).unbind('mousedown.tablesorter mouseup.tablesorter keypress.tablesorter');
966
1014
  ts.restoreHeaders(table);
967
1015
  if (removeClasses !== false) {
968
- $t.removeClass(c.tableClass + ' tablesorter-' + c.theme);
1016
+ $t.removeClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme);
969
1017
  }
970
1018
  // clear flag in case the plugin is initialized again
971
1019
  table.hasInitialized = false;
@@ -976,31 +1024,32 @@
976
1024
 
977
1025
  // *** sort functions ***
978
1026
  // regex used in natural sort
979
- ts.regex = [
980
- /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters
981
- /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/, //date
982
- /^0x[0-9a-f]+$/i // hex
983
- ];
1027
+ ts.regex = {
1028
+ chunk : /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters
1029
+ hex: /^0x[0-9a-f]+$/i // hex
1030
+ };
984
1031
 
985
- // Natural sort - https://github.com/overset/javascript-natural-sort
1032
+ // Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)
986
1033
  ts.sortText = function(table, a, b, col) {
987
1034
  if (a === b) { return 0; }
988
1035
  var c = table.config, e = c.string[ (c.empties[col] || c.emptyTo ) ],
989
1036
  r = ts.regex, xN, xD, yN, yD, xF, yF, i, mx;
1037
+ // sorting empty cells
990
1038
  if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; }
991
1039
  if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; }
1040
+ // custom sorter
992
1041
  if (typeof c.textSorter === 'function') { return c.textSorter(a, b, table, col); }
993
- // chunk/tokenize
994
- xN = a.replace(r[0], '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0');
995
- yN = b.replace(r[0], '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0');
996
- // numeric, hex or date detection
997
- xD = parseInt(a.match(r[2]),16) || (xN.length !== 1 && a.match(r[1]) && Date.parse(a));
998
- yD = parseInt(b.match(r[2]),16) || (xD && b.match(r[1]) && Date.parse(b)) || null;
999
- // first try and sort Hex codes or Dates
1042
+ // numeric or hex detection
1043
+ yD = parseInt(b.match(r.hex), 16);
1044
+ // first try and sort Hex codes
1000
1045
  if (yD) {
1046
+ xD = parseInt(a.match(r.hex), 16);
1001
1047
  if ( xD < yD ) { return -1; }
1002
1048
  if ( xD > yD ) { return 1; }
1003
1049
  }
1050
+ // chunk/tokenize
1051
+ xN = a.replace(r.chunk, '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0');
1052
+ yN = b.replace(r.chunk, '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0');
1004
1053
  mx = Math.max(xN.length, yN.length);
1005
1054
  // natural sorting through split numeric strings and default strings
1006
1055
  for (i = 0; i < mx; i++) {
@@ -1175,18 +1224,19 @@
1175
1224
  widgets.sort(function(a, b){
1176
1225
  return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1;
1177
1226
  });
1178
-
1179
1227
  // add/update selected widgets
1180
1228
  $.each(widgets, function(i,w){
1181
1229
  if (w) {
1182
- if (init) {
1230
+ if (init || !(c.widgetInit[w.id])) {
1183
1231
  if (w.hasOwnProperty('options')) {
1184
1232
  wo = table.config.widgetOptions = $.extend( true, {}, w.options, wo );
1233
+ c.widgetInit[w.id] = true;
1185
1234
  }
1186
1235
  if (w.hasOwnProperty('init')) {
1187
1236
  w.init(table, w, c, wo);
1188
1237
  }
1189
- } else if (!init && w.hasOwnProperty('format')) {
1238
+ }
1239
+ if (!init && w.hasOwnProperty('format')) {
1190
1240
  w.format(table, c, wo, false);
1191
1241
  }
1192
1242
  }
@@ -1207,7 +1257,10 @@
1207
1257
  for (i = 0; i < l; i++){
1208
1258
  if ( w[i] && w[i].id && (doAll || $.inArray( w[i].id, cw ) < 0) ) {
1209
1259
  if (c.debug) { log( 'Refeshing widgets: Removing ' + w[i].id ); }
1210
- if (w[i].hasOwnProperty('remove')) { w[i].remove(table, c, c.widgetOptions); }
1260
+ if (w[i].hasOwnProperty('remove')) {
1261
+ w[i].remove(table, c, c.widgetOptions);
1262
+ c.widgetInit[w[i].id] = false;
1263
+ }
1211
1264
  }
1212
1265
  }
1213
1266
  if (dontapply !== true) {