jquery-tablesorter 1.5.0 → 1.6.0

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