datatables.net 2.3.3 → 2.3.5

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.
package/js/dataTables.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! DataTables 2.3.3
1
+ /*! DataTables 2.3.5
2
2
  * © SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
@@ -166,6 +166,9 @@
166
166
  this.id = sId;
167
167
  }
168
168
 
169
+ // Replacing an existing colgroup with our own. Not ideal, but a merge could take a lot of code
170
+ $this.children('colgroup').remove();
171
+
169
172
  /* Create the settings object for this table and set some of the default parameters */
170
173
  var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
171
174
  "sDestroyWidth": $this[0].style.width,
@@ -2934,12 +2937,12 @@
2934
2937
 
2935
2938
  // Max length string. Its a fairly cheep recalculation, so not worth
2936
2939
  // something more complicated
2937
- cols[ colIdx ].maxLenString = null;
2940
+ cols[ colIdx ].wideStrings = null;
2938
2941
  }
2939
2942
  else {
2940
2943
  for ( i=0, iLen=cols.length ; i<iLen ; i++ ) {
2941
2944
  cols[i].sType = null;
2942
- cols[i].maxLenString = null;
2945
+ cols[i].wideStrings = null;
2943
2946
  }
2944
2947
 
2945
2948
  // Update DataTables special `DT_*` attributes for the row
@@ -3480,6 +3483,14 @@
3480
3483
  {
3481
3484
  var iDataIndex = aiDisplay[j];
3482
3485
  var aoData = oSettings.aoData[ iDataIndex ];
3486
+
3487
+ // Row has been deleted - can't be displayed
3488
+ if (aoData === null)
3489
+ {
3490
+ continue;
3491
+ }
3492
+
3493
+ // Row node hasn't been created yet
3483
3494
  if ( aoData.nTr === null )
3484
3495
  {
3485
3496
  _fnCreateTr( oSettings, iDataIndex );
@@ -4158,24 +4169,21 @@
4158
4169
  * DataTables - may be augmented by developer callbacks
4159
4170
  * @param {function} fn Callback function to run when data is obtained
4160
4171
  */
4161
- function _fnBuildAjax( oSettings, data, fn )
4162
- {
4172
+ function _fnBuildAjax(oSettings, data, fn) {
4163
4173
  var ajaxData;
4164
4174
  var ajax = oSettings.ajax;
4165
4175
  var instance = oSettings.oInstance;
4166
- var callback = function ( json ) {
4167
- var status = oSettings.jqXHR
4168
- ? oSettings.jqXHR.status
4169
- : null;
4176
+ var callback = function (json) {
4177
+ var status = oSettings.jqXHR ? oSettings.jqXHR.status : null;
4170
4178
 
4171
- if ( json === null || (typeof status === 'number' && status == 204 ) ) {
4179
+ if (json === null || (typeof status === 'number' && status == 204)) {
4172
4180
  json = {};
4173
- _fnAjaxDataSrc( oSettings, json, [] );
4181
+ _fnAjaxDataSrc(oSettings, json, []);
4174
4182
  }
4175
4183
 
4176
4184
  var error = json.error || json.sError;
4177
- if ( error ) {
4178
- _fnLog( oSettings, 0, error );
4185
+ if (error) {
4186
+ _fnLog(oSettings, 0, error);
4179
4187
  }
4180
4188
 
4181
4189
  // Microsoft often wrap JSON as a string in another JSON object
@@ -4183,30 +4191,27 @@
4183
4191
  if (json.d && typeof json.d === 'string') {
4184
4192
  try {
4185
4193
  json = JSON.parse(json.d);
4186
- }
4187
- catch (e) {
4194
+ } catch (e) {
4188
4195
  // noop
4189
4196
  }
4190
4197
  }
4191
4198
 
4192
4199
  oSettings.json = json;
4193
4200
 
4194
- _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR], true );
4195
- fn( json );
4201
+ _fnCallbackFire(oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR], true);
4202
+ fn(json);
4196
4203
  };
4197
4204
 
4198
- if ( $.isPlainObject( ajax ) && ajax.data )
4199
- {
4205
+ if ($.isPlainObject(ajax) && ajax.data) {
4200
4206
  ajaxData = ajax.data;
4201
4207
 
4202
- var newData = typeof ajaxData === 'function' ?
4203
- ajaxData( data, oSettings ) : // fn can manipulate data or return
4204
- ajaxData; // an object or array to merge
4208
+ var newData =
4209
+ typeof ajaxData === 'function'
4210
+ ? ajaxData(data, oSettings) // fn can manipulate data or return
4211
+ : ajaxData; // an object or array to merge
4205
4212
 
4206
4213
  // If the function returned something, use that alone
4207
- data = typeof ajaxData === 'function' && newData ?
4208
- newData :
4209
- $.extend( true, data, newData );
4214
+ data = typeof ajaxData === 'function' && newData ? newData : $.extend(true, data, newData);
4210
4215
 
4211
4216
  // Remove the data property as we've resolved it already and don't want
4212
4217
  // jQuery to do it again (it is restored at the end of the function)
@@ -4214,50 +4219,53 @@
4214
4219
  }
4215
4220
 
4216
4221
  var baseAjax = {
4217
- "url": typeof ajax === 'string' ?
4218
- ajax :
4219
- '',
4220
- "data": data,
4221
- "success": callback,
4222
- "dataType": "json",
4223
- "cache": false,
4224
- "type": oSettings.sServerMethod,
4225
- "error": function (xhr, error) {
4226
- var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR], true );
4227
-
4228
- if ( ret.indexOf(true) === -1 ) {
4229
- if ( error == "parsererror" ) {
4230
- _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
4222
+ url: typeof ajax === 'string' ? ajax : '',
4223
+ data: data,
4224
+ success: callback,
4225
+ dataType: 'json',
4226
+ cache: false,
4227
+ type: oSettings.sServerMethod,
4228
+ error: function (xhr, error) {
4229
+ var ret = _fnCallbackFire(
4230
+ oSettings,
4231
+ null,
4232
+ 'xhr',
4233
+ [oSettings, null, oSettings.jqXHR],
4234
+ true
4235
+ );
4236
+
4237
+ if (ret.indexOf(true) === -1) {
4238
+ if (error == 'parsererror') {
4239
+ _fnLog(oSettings, 0, 'Invalid JSON response', 1);
4231
4240
  }
4232
- else if ( xhr.readyState === 4 ) {
4233
- _fnLog( oSettings, 0, 'Ajax error', 7 );
4241
+ else if (xhr.readyState === 4) {
4242
+ _fnLog(oSettings, 0, 'Ajax error', 7);
4234
4243
  }
4235
4244
  }
4236
4245
 
4237
- _fnProcessingDisplay( oSettings, false );
4246
+ _fnProcessingDisplay(oSettings, false);
4238
4247
  }
4239
4248
  };
4240
4249
 
4241
4250
  // If `ajax` option is an object, extend and override our default base
4242
- if ( $.isPlainObject( ajax ) ) {
4243
- $.extend( baseAjax, ajax )
4251
+ if ($.isPlainObject(ajax)) {
4252
+ $.extend(baseAjax, ajax);
4244
4253
  }
4245
4254
 
4246
4255
  // Store the data submitted for the API
4247
4256
  oSettings.oAjaxData = data;
4248
4257
 
4249
4258
  // Allow plug-ins and external processes to modify the data
4250
- _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
4259
+ _fnCallbackFire(oSettings, null, 'preXhr', [oSettings, data, baseAjax], true);
4251
4260
 
4252
4261
  // Custom Ajax option to submit the parameters as a JSON string
4253
4262
  if (baseAjax.submitAs === 'json' && typeof data === 'object') {
4254
4263
  baseAjax.data = JSON.stringify(data);
4255
4264
  }
4256
4265
 
4257
- if ( typeof ajax === 'function' )
4258
- {
4266
+ if (typeof ajax === 'function') {
4259
4267
  // Is a function - let the caller define what needs to be done
4260
- oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
4268
+ oSettings.jqXHR = ajax.call(instance, data, callback, oSettings);
4261
4269
  }
4262
4270
  else if (ajax.url === '') {
4263
4271
  // No url, so don't load any data. Just apply an empty data array
@@ -4269,37 +4277,30 @@
4269
4277
  }
4270
4278
  else {
4271
4279
  // Object to extend the base settings
4272
- oSettings.jqXHR = $.ajax( baseAjax );
4280
+ oSettings.jqXHR = $.ajax(baseAjax);
4273
4281
  }
4274
4282
 
4275
4283
  // Restore for next time around
4276
- if ( ajaxData ) {
4284
+ if (ajaxData) {
4277
4285
  ajax.data = ajaxData;
4278
4286
  }
4279
4287
  }
4280
4288
 
4281
-
4282
4289
  /**
4283
4290
  * Update the table using an Ajax call
4284
4291
  * @param {object} settings dataTables settings object
4285
4292
  * @returns {boolean} Block the table drawing or not
4286
4293
  * @memberof DataTable#oApi
4287
4294
  */
4288
- function _fnAjaxUpdate( settings )
4289
- {
4295
+ function _fnAjaxUpdate(settings) {
4290
4296
  settings.iDraw++;
4291
- _fnProcessingDisplay( settings, true );
4297
+ _fnProcessingDisplay(settings, true);
4292
4298
 
4293
- _fnBuildAjax(
4294
- settings,
4295
- _fnAjaxParameters( settings ),
4296
- function(json) {
4297
- _fnAjaxUpdateDraw( settings, json );
4298
- }
4299
- );
4299
+ _fnBuildAjax(settings, _fnAjaxParameters(settings), function (json) {
4300
+ _fnAjaxUpdateDraw(settings, json);
4301
+ });
4300
4302
  }
4301
4303
 
4302
-
4303
4304
  /**
4304
4305
  * Build up the parameters in an object needed for a server-side processing
4305
4306
  * request.
@@ -4307,22 +4308,18 @@
4307
4308
  * @returns {bool} block the table drawing or not
4308
4309
  * @memberof DataTable#oApi
4309
4310
  */
4310
- function _fnAjaxParameters( settings )
4311
- {
4312
- var
4313
- columns = settings.aoColumns,
4311
+ function _fnAjaxParameters(settings) {
4312
+ var columns = settings.aoColumns,
4314
4313
  features = settings.oFeatures,
4315
4314
  preSearch = settings.oPreviousSearch,
4316
4315
  preColSearch = settings.aoPreSearchCols,
4317
- colData = function ( idx, prop ) {
4318
- return typeof columns[idx][prop] === 'function' ?
4319
- 'function' :
4320
- columns[idx][prop];
4316
+ colData = function (idx, prop) {
4317
+ return typeof columns[idx][prop] === 'function' ? 'function' : columns[idx][prop];
4321
4318
  };
4322
4319
 
4323
4320
  return {
4324
4321
  draw: settings.iDraw,
4325
- columns: columns.map( function ( column, i ) {
4322
+ columns: columns.map(function (column, i) {
4326
4323
  return {
4327
4324
  data: colData(i, 'mData'),
4328
4325
  name: column.sName,
@@ -4331,40 +4328,43 @@
4331
4328
  search: {
4332
4329
  value: preColSearch[i].search,
4333
4330
  regex: preColSearch[i].regex,
4334
- fixed: Object.keys(column.searchFixed).map( function(name) {
4335
- return {
4336
- name: name,
4337
- term: column.searchFixed[name].toString()
4338
- }
4339
- })
4331
+ fixed: Object.keys(column.searchFixed)
4332
+ .map(function (name) {
4333
+ return {
4334
+ name: name,
4335
+ term: typeof column.searchFixed[name] !== 'function'
4336
+ ? column.searchFixed[name].toString()
4337
+ : 'function'
4338
+ };
4339
+ })
4340
4340
  }
4341
4341
  };
4342
- } ),
4343
- order: _fnSortFlatten( settings ).map( function ( val ) {
4342
+ }),
4343
+ order: _fnSortFlatten(settings).map(function (val) {
4344
4344
  return {
4345
4345
  column: val.col,
4346
4346
  dir: val.dir,
4347
4347
  name: colData(val.col, 'sName')
4348
4348
  };
4349
- } ),
4349
+ }),
4350
4350
  start: settings._iDisplayStart,
4351
- length: features.bPaginate ?
4352
- settings._iDisplayLength :
4353
- -1,
4351
+ length: features.bPaginate ? settings._iDisplayLength : -1,
4354
4352
  search: {
4355
4353
  value: preSearch.search,
4356
4354
  regex: preSearch.regex,
4357
- fixed: Object.keys(settings.searchFixed).map( function(name) {
4358
- return {
4359
- name: name,
4360
- term: settings.searchFixed[name].toString()
4361
- }
4362
- })
4355
+ fixed: Object.keys(settings.searchFixed)
4356
+ .map(function (name) {
4357
+ return {
4358
+ name: name,
4359
+ term: typeof settings.searchFixed[name] !== 'function'
4360
+ ? settings.searchFixed[name].toString()
4361
+ : 'function'
4362
+ };
4363
+ })
4363
4364
  }
4364
4365
  };
4365
4366
  }
4366
4367
 
4367
-
4368
4368
  /**
4369
4369
  * Data the data from the server (nuking the old) and redraw the table
4370
4370
  * @param {object} oSettings dataTables settings object
@@ -4376,42 +4376,40 @@
4376
4376
  * @param {string} [json.sColumns] Column ordering (sName, comma separated)
4377
4377
  * @memberof DataTable#oApi
4378
4378
  */
4379
- function _fnAjaxUpdateDraw ( settings, json )
4380
- {
4379
+ function _fnAjaxUpdateDraw(settings, json) {
4381
4380
  var data = _fnAjaxDataSrc(settings, json);
4382
4381
  var draw = _fnAjaxDataSrcParam(settings, 'draw', json);
4383
4382
  var recordsTotal = _fnAjaxDataSrcParam(settings, 'recordsTotal', json);
4384
4383
  var recordsFiltered = _fnAjaxDataSrcParam(settings, 'recordsFiltered', json);
4385
4384
 
4386
- if ( draw !== undefined ) {
4385
+ if (draw !== undefined) {
4387
4386
  // Protect against out of sequence returns
4388
- if ( draw*1 < settings.iDraw ) {
4387
+ if (draw * 1 < settings.iDraw) {
4389
4388
  return;
4390
4389
  }
4391
4390
  settings.iDraw = draw * 1;
4392
4391
  }
4393
4392
 
4394
4393
  // No data in returned object, so rather than an array, we show an empty table
4395
- if ( ! data ) {
4394
+ if (!data) {
4396
4395
  data = [];
4397
4396
  }
4398
4397
 
4399
- _fnClearTable( settings );
4400
- settings._iRecordsTotal = parseInt(recordsTotal, 10);
4398
+ _fnClearTable(settings);
4399
+ settings._iRecordsTotal = parseInt(recordsTotal, 10);
4401
4400
  settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4402
4401
 
4403
- for ( var i=0, iLen=data.length ; i<iLen ; i++ ) {
4404
- _fnAddData( settings, data[i] );
4402
+ for (var i = 0, iLen = data.length; i < iLen; i++) {
4403
+ _fnAddData(settings, data[i]);
4405
4404
  }
4406
4405
  settings.aiDisplay = settings.aiDisplayMaster.slice();
4407
4406
 
4408
4407
  _fnColumnTypes(settings);
4409
- _fnDraw( settings, true );
4410
- _fnInitComplete( settings );
4411
- _fnProcessingDisplay( settings, false );
4408
+ _fnDraw(settings, true);
4409
+ _fnInitComplete(settings);
4410
+ _fnProcessingDisplay(settings, false);
4412
4411
  }
4413
4412
 
4414
-
4415
4413
  /**
4416
4414
  * Get the data from the JSON data source to use for drawing a table. Using
4417
4415
  * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
@@ -4420,11 +4418,10 @@
4420
4418
  * @param {object} json Data source object / array from the server
4421
4419
  * @return {array} Array of data to use
4422
4420
  */
4423
- function _fnAjaxDataSrc ( settings, json, write )
4424
- {
4421
+ function _fnAjaxDataSrc(settings, json, write) {
4425
4422
  var dataProp = 'data';
4426
4423
 
4427
- if ($.isPlainObject( settings.ajax ) && settings.ajax.dataSrc !== undefined) {
4424
+ if ($.isPlainObject(settings.ajax) && settings.ajax.dataSrc !== undefined) {
4428
4425
  // Could in inside a `dataSrc` object, or not!
4429
4426
  var dataSrc = settings.ajax.dataSrc;
4430
4427
 
@@ -4437,20 +4434,18 @@
4437
4434
  }
4438
4435
  }
4439
4436
 
4440
- if ( ! write ) {
4441
- if ( dataProp === 'data' ) {
4437
+ if (!write) {
4438
+ if (dataProp === 'data') {
4442
4439
  // If the default, then we still want to support the old style, and safely ignore
4443
4440
  // it if possible
4444
4441
  return json.aaData || json[dataProp];
4445
4442
  }
4446
4443
 
4447
- return dataProp !== "" ?
4448
- _fnGetObjectDataFn( dataProp )( json ) :
4449
- json;
4444
+ return dataProp !== '' ? _fnGetObjectDataFn(dataProp)(json) : json;
4450
4445
  }
4451
-
4446
+
4452
4447
  // set
4453
- _fnSetObjectDataFn( dataProp )( json, write );
4448
+ _fnSetObjectDataFn(dataProp)(json, write);
4454
4449
  }
4455
4450
 
4456
4451
  /**
@@ -4460,14 +4455,12 @@
4460
4455
  * @param {*} json JSON data
4461
4456
  * @returns Resolved value
4462
4457
  */
4463
- function _fnAjaxDataSrcParam (settings, param, json) {
4464
- var dataSrc = $.isPlainObject( settings.ajax )
4465
- ? settings.ajax.dataSrc
4466
- : null;
4458
+ function _fnAjaxDataSrcParam(settings, param, json) {
4459
+ var dataSrc = $.isPlainObject(settings.ajax) ? settings.ajax.dataSrc : null;
4467
4460
 
4468
4461
  if (dataSrc && dataSrc[param]) {
4469
4462
  // Get from custom location
4470
- return _fnGetObjectDataFn( dataSrc[param] )( json );
4463
+ return _fnGetObjectDataFn(dataSrc[param])(json);
4471
4464
  }
4472
4465
 
4473
4466
  // else - Default behaviour
@@ -4484,9 +4477,7 @@
4484
4477
  old = 'iTotalDisplayRecords';
4485
4478
  }
4486
4479
 
4487
- return json[old] !== undefined
4488
- ? json[old]
4489
- : json[param];
4480
+ return json[old] !== undefined ? json[old] : json[param];
4490
4481
  }
4491
4482
 
4492
4483
 
@@ -5425,7 +5416,7 @@
5425
5416
  visibleColumns = _fnGetColumns( settings, 'bVisible' ),
5426
5417
  tableWidthAttr = table.getAttribute('width'), // from DOM element
5427
5418
  tableContainer = table.parentNode,
5428
- i, column, columnIdx;
5419
+ i, j, column, columnIdx;
5429
5420
 
5430
5421
  var styleWidth = table.style.width;
5431
5422
  var containerWidth = _fnWrapperWidth(settings);
@@ -5459,17 +5450,16 @@
5459
5450
  false
5460
5451
  );
5461
5452
 
5462
- // Construct a single row, worst case, table with the widest
5463
- // node in the data, assign any user defined widths, then insert it into
5464
- // the DOM and allow the browser to do all the hard work of calculating
5465
- // table widths
5453
+ // Construct a worst case table with the widest, assign any user defined
5454
+ // widths, then insert it into the DOM and allow the browser to do all
5455
+ // the hard work of calculating table widths
5466
5456
  var tmpTable = $(table.cloneNode())
5467
5457
  .css( 'visibility', 'hidden' )
5458
+ .css( 'margin', 0 )
5468
5459
  .removeAttr( 'id' );
5469
5460
 
5470
5461
  // Clean up the table body
5471
5462
  tmpTable.append('<tbody/>')
5472
- var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5473
5463
 
5474
5464
  // Clone the table header and footer - we can't use the header / footer
5475
5465
  // from the cloned table, since if scrolling is active, the table's
@@ -5509,23 +5499,37 @@
5509
5499
  }
5510
5500
  } );
5511
5501
 
5512
- // Find the widest piece of data for each column and put it into the table
5502
+ // Get the widest strings for each of the visible columns and add them to
5503
+ // our table to create a "worst case"
5504
+ var longestData = [];
5505
+
5513
5506
  for ( i=0 ; i<visibleColumns.length ; i++ ) {
5514
- columnIdx = visibleColumns[i];
5515
- column = columns[ columnIdx ];
5516
-
5517
- var longest = _fnGetMaxLenString(settings, columnIdx);
5518
- var autoClass = _ext.type.className[column.sType];
5519
- var text = longest + column.sContentPadding;
5520
- var insert = longest.indexOf('<') === -1
5521
- ? document.createTextNode(text)
5522
- : text
5523
-
5524
- $('<td/>')
5525
- .addClass(autoClass)
5526
- .addClass(column.sClass)
5527
- .append(insert)
5528
- .appendTo(tr);
5507
+ longestData.push(_fnGetWideStrings(settings, visibleColumns[i]));
5508
+ }
5509
+
5510
+ if (longestData.length) {
5511
+ for ( i=0 ; i<longestData[0].length ; i++ ) {
5512
+ var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5513
+
5514
+ for ( j=0 ; j<visibleColumns.length ; j++ ) {
5515
+ columnIdx = visibleColumns[j];
5516
+ column = columns[ columnIdx ];
5517
+
5518
+ var longest = longestData[j][i] || '';
5519
+ var autoClass = _ext.type.className[column.sType];
5520
+ var padding = column.sContentPadding || (scrollX ? '-' : '');
5521
+ var text = longest + padding;
5522
+ var insert = longest.indexOf('<') === -1
5523
+ ? document.createTextNode(text)
5524
+ : text
5525
+
5526
+ $('<td/>')
5527
+ .addClass(autoClass)
5528
+ .addClass(column.sClass)
5529
+ .append(insert)
5530
+ .appendTo(tr);
5531
+ }
5532
+ }
5529
5533
  }
5530
5534
 
5531
5535
  // Tidy the temporary table - remove name attributes so there aren't
@@ -5664,19 +5668,31 @@
5664
5668
  }
5665
5669
 
5666
5670
  /**
5667
- * Get the maximum strlen for each data column
5671
+ * Get the widest strings for each column.
5672
+ *
5673
+ * It is very difficult to determine what the widest string actually is due to variable character
5674
+ * width and kerning. Doing an exact calculation with the DOM or even Canvas would kill performance
5675
+ * and this is a critical point, so we use two techniques to determine a collection of the longest
5676
+ * strings from the column, which will likely contain the widest strings:
5677
+ *
5678
+ * 1) Get the top three longest strings from the column
5679
+ * 2) Get the top three widest words (i.e. an unbreakable phrase)
5680
+ *
5668
5681
  * @param {object} settings dataTables settings object
5669
5682
  * @param {int} colIdx column of interest
5670
- * @returns {string} string of the max length
5683
+ * @returns {string[]} Array of the longest strings
5671
5684
  * @memberof DataTable#oApi
5672
5685
  */
5673
- function _fnGetMaxLenString( settings, colIdx )
5686
+ function _fnGetWideStrings( settings, colIdx )
5674
5687
  {
5675
5688
  var column = settings.aoColumns[colIdx];
5676
5689
 
5677
- if (! column.maxLenString) {
5678
- var s, max='', maxLen = -1;
5679
-
5690
+ // Do we need to recalculate (i.e. was invalidated), or just use the cached data?
5691
+ if (! column.wideStrings) {
5692
+ var allStrings = [];
5693
+ var collection = [];
5694
+
5695
+ // Create an array with the string information for the column
5680
5696
  for ( var i=0, iLen=settings.aiDisplayMaster.length ; i<iLen ; i++ ) {
5681
5697
  var rowIdx = settings.aiDisplayMaster[i];
5682
5698
  var data = _fnGetRowDisplay(settings, rowIdx)[colIdx];
@@ -5691,21 +5707,49 @@
5691
5707
  .replace(/id=".*?"/g, '')
5692
5708
  .replace(/name=".*?"/g, '');
5693
5709
 
5694
- s = _stripHtml(cellString)
5710
+ var s = _stripHtml(cellString)
5695
5711
  .replace( /&nbsp;/g, ' ' );
5696
5712
 
5697
- if ( s.length > maxLen ) {
5698
- // We want the HTML in the string, but the length that
5699
- // is important is the stripped string
5700
- max = cellString;
5701
- maxLen = s.length;
5702
- }
5713
+ collection.push({
5714
+ str: s,
5715
+ len: s.length
5716
+ });
5717
+
5718
+ allStrings.push(s);
5719
+ }
5720
+
5721
+ // Order and then cut down to the size we need
5722
+ collection
5723
+ .sort(function (a, b) {
5724
+ return b.len - a.len;
5725
+ })
5726
+ .splice(3);
5727
+
5728
+ column.wideStrings = collection.map(function (item) {
5729
+ return item.str;
5730
+ });
5731
+
5732
+ // Longest unbroken string
5733
+ let parts = allStrings.join(' ').split(' ');
5734
+
5735
+ parts.sort(function (a, b) {
5736
+ return b.length - a.length;
5737
+ });
5738
+
5739
+ if (parts.length) {
5740
+ column.wideStrings.push(parts[0]);
5741
+ }
5742
+
5743
+ if (parts.length > 1) {
5744
+ column.wideStrings.push(parts[1]);
5703
5745
  }
5704
5746
 
5705
- column.maxLenString = max;
5747
+ if (parts.length > 2) {
5748
+ column.wideStrings.push(parts[3]);
5749
+ }
5706
5750
  }
5707
5751
 
5708
- return column.maxLenString;
5752
+ return column.wideStrings;
5709
5753
  }
5710
5754
 
5711
5755
 
@@ -6501,7 +6545,9 @@
6501
6545
 
6502
6546
  // If the api is defined then we need to adjust the columns once the visibility has been changed
6503
6547
  if (api) {
6504
- api.columns.adjust();
6548
+ api.one('draw', function () {
6549
+ api.columns.adjust();
6550
+ });
6505
6551
  }
6506
6552
  }
6507
6553
  }
@@ -9044,13 +9090,16 @@
9044
9090
 
9045
9091
  _api_registerPlural( 'columns().types()', 'column().type()', function () {
9046
9092
  return this.iterator( 'column', function ( settings, column ) {
9047
- var type = settings.aoColumns[column].sType;
9093
+ var colObj = settings.aoColumns[column]
9094
+ var type = colObj.sType;
9048
9095
 
9049
9096
  // If the type was invalidated, then resolve it. This actually does
9050
9097
  // all columns at the moment. Would only happen once if getting all
9051
9098
  // column's data types.
9052
9099
  if (! type) {
9053
9100
  _fnColumnTypes(settings);
9101
+
9102
+ type = colObj.sType;
9054
9103
  }
9055
9104
 
9056
9105
  return type;
@@ -10221,7 +10270,7 @@
10221
10270
  * @type string
10222
10271
  * @default Version number
10223
10272
  */
10224
- DataTable.version = "2.3.3";
10273
+ DataTable.version = "2.3.5";
10225
10274
 
10226
10275
  /**
10227
10276
  * Private data store, containing all of the settings objects that are
@@ -10523,8 +10572,8 @@
10523
10572
  */
10524
10573
  "sWidthOrig": null,
10525
10574
 
10526
- /** Cached string which is the longest in the column */
10527
- maxLenString: null,
10575
+ /** Cached longest strings from a column */
10576
+ wideStrings: null,
10528
10577
 
10529
10578
  /**
10530
10579
  * Store for named searches
@@ -12638,7 +12687,10 @@
12638
12687
  }
12639
12688
 
12640
12689
  var formatted = to === null
12641
- ? __mld(dt, 'toDate', 'toJSDate', '')[localeString]()
12690
+ ? __mld(dt, 'toDate', 'toJSDate', '')[localeString](
12691
+ navigator.language,
12692
+ { timeZone: "UTC" }
12693
+ )
12642
12694
  : __mld(dt, 'format', 'toFormat', 'toISOString', to);
12643
12695
 
12644
12696
  // XSS protection