weaver 0.1.9 → 0.2.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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/data/weaver/css/bootstrap.css +647 -205
  3. data/data/weaver/css/bootstrap.css.map +1 -0
  4. data/data/weaver/css/bootstrap.min.css +3 -3
  5. data/data/weaver/css/crossfade_style.css +19 -0
  6. data/data/weaver/css/patterns/1.png +0 -0
  7. data/data/weaver/css/patterns/2.png +0 -0
  8. data/data/weaver/css/patterns/3.png +0 -0
  9. data/data/weaver/css/patterns/4.png +0 -0
  10. data/data/weaver/css/patterns/5.png +0 -0
  11. data/data/weaver/css/patterns/6.png +0 -0
  12. data/data/weaver/css/patterns/7.png +0 -0
  13. data/data/weaver/css/plugins/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css +251 -0
  14. data/data/weaver/css/plugins/chartist/chartist.min.css +773 -0
  15. data/data/weaver/css/plugins/clockpicker/clockpicker.css +168 -0
  16. data/data/weaver/css/plugins/dataTables/dataTables.bootstrap.css +118 -190
  17. data/data/weaver/css/plugins/dataTables/dataTables.tableTools.min.css +1 -1
  18. data/data/weaver/css/plugins/daterangepicker/daterangepicker-bs3.css +335 -0
  19. data/data/weaver/css/plugins/footable/fonts/footable.eot +0 -0
  20. data/data/weaver/css/plugins/footable/fonts/footable.svg +78 -0
  21. data/data/weaver/css/plugins/footable/fonts/footable.ttf +0 -0
  22. data/data/weaver/css/plugins/footable/fonts/footable.woff +0 -0
  23. data/data/weaver/css/plugins/footable/footable.core.css +178 -0
  24. data/data/weaver/css/plugins/select2/select2.min.css +1 -0
  25. data/data/weaver/css/plugins/slick/ajax-loader.gif +0 -0
  26. data/data/weaver/css/plugins/slick/fonts/slick.eot +0 -0
  27. data/data/weaver/css/plugins/slick/fonts/slick.svg +14 -0
  28. data/data/weaver/css/plugins/slick/fonts/slick.ttf +0 -0
  29. data/data/weaver/css/plugins/slick/fonts/slick.woff +0 -0
  30. data/data/weaver/css/plugins/slick/slick-theme.css +201 -0
  31. data/data/weaver/css/plugins/slick/slick.css +119 -0
  32. data/data/weaver/css/plugins/sweetalert/sweetalert.css +715 -0
  33. data/data/weaver/css/style.css +4352 -1310
  34. data/data/weaver/css/style.min.css +1 -1
  35. data/data/weaver/fonts/glyphicons-halflings-regular.eot +0 -0
  36. data/data/weaver/fonts/glyphicons-halflings-regular.svg +273 -214
  37. data/data/weaver/fonts/glyphicons-halflings-regular.ttf +0 -0
  38. data/data/weaver/fonts/glyphicons-halflings-regular.woff +0 -0
  39. data/data/weaver/fonts/glyphicons-halflings-regular.woff2 +0 -0
  40. data/data/weaver/js/bootstrap.js +299 -212
  41. data/data/weaver/js/bootstrap.min.js +5 -5
  42. data/data/weaver/js/inspinia.js +184 -42
  43. data/data/weaver/js/plugins/chartist/chartist.min.js +9 -0
  44. data/data/weaver/js/plugins/chartist/chartist.min.js.map +1 -0
  45. data/data/weaver/js/plugins/clockpicker/clockpicker.js +729 -0
  46. data/data/weaver/js/plugins/dataTables/dataTables.bootstrap.js +195 -234
  47. data/data/weaver/js/plugins/dataTables/dataTables.tableTools.min.js +46 -45
  48. data/data/weaver/js/plugins/dataTables/jquery.dataTables.js +628 -373
  49. data/data/weaver/js/plugins/dataTables/swf/copy_csv_xls.swf +0 -0
  50. data/data/weaver/js/plugins/dataTables/swf/copy_csv_xls_pdf.swf +0 -0
  51. data/data/weaver/js/plugins/daterangepicker/daterangepicker.js +1304 -0
  52. data/data/weaver/js/plugins/diff_match_patch/COPYING +177 -0
  53. data/data/weaver/js/plugins/diff_match_patch/README.txt +43 -0
  54. data/data/weaver/js/plugins/diff_match_patch/javascript/diff_match_patch.js +49 -0
  55. data/data/weaver/js/plugins/footable/footable.all.min.js +14 -0
  56. data/data/weaver/js/plugins/fullcalendar/moment.min.js +3 -3
  57. data/data/weaver/js/plugins/idle-timer/idle-timer.min.js +2 -0
  58. data/data/weaver/js/plugins/jvectormap/jquery-jvectormap-2.0.2.css +130 -0
  59. data/data/weaver/js/plugins/jvectormap/jquery-jvectormap-2.0.2.min.js +3328 -0
  60. data/data/weaver/js/plugins/masonary/masonry.pkgd.min.js +9 -0
  61. data/data/weaver/js/plugins/metisMenu/jquery.metisMenu.js +3 -113
  62. data/data/weaver/js/plugins/morris/morris.js +27 -23
  63. data/data/weaver/js/plugins/pace/pace.min.js +2 -2
  64. data/data/weaver/js/plugins/preetyTextDiff/jquery.pretty-text-diff.min.js +76 -0
  65. data/data/weaver/js/plugins/select2/select2.full.min.js +3 -0
  66. data/data/weaver/js/plugins/slick/slick.min.js +18 -0
  67. data/data/weaver/js/plugins/slimscroll/jquery.slimscroll.js +96 -90
  68. data/data/weaver/js/plugins/slimscroll/jquery.slimscroll.min.js +10 -10
  69. data/data/weaver/js/plugins/sweetalert/sweetalert.min.js +1 -0
  70. data/data/weaver/js/plugins/tinycon/tinycon.min.js +8 -0
  71. data/data/weaver/js/plugins/wow/wow.min.js +2 -0
  72. data/{bin → exe}/weaver +3 -2
  73. data/lib/weaver.rb +236 -53
  74. data/lib/weaver/version.rb +1 -1
  75. data/weaver.gemspec +2 -2
  76. metadata +50 -7
  77. data/data/weaver/js/plugins/jvectormap/jquery-jvectormap-1.2.2.min.js +0 -8
@@ -1,11 +1,11 @@
1
- /*! DataTables 1.10.4
1
+ /*! DataTables 1.10.8
2
2
  * ©2008-2014 SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
5
5
  /**
6
6
  * @summary DataTables
7
7
  * @description Paginate, search and order HTML tables
8
- * @version 1.10.4
8
+ * @version 1.10.8
9
9
  * @file jquery.dataTables.js
10
10
  * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
11
  * @contact www.sprymedia.co.uk/contact
@@ -22,7 +22,7 @@
22
22
  */
23
23
 
24
24
  /*jslint evil: true, undef: true, browser: true */
25
- /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
25
+ /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
26
 
27
27
  (/** @lends <global> */function( window, document, undefined ) {
28
28
 
@@ -33,10 +33,10 @@
33
33
  // Define as an AMD module if possible
34
34
  define( 'datatables', ['jquery'], factory );
35
35
  }
36
- else if ( typeof exports === 'object' ) {
37
- // Node/CommonJS
38
- factory( require( 'jquery' ) );
39
- }
36
+ else if ( typeof exports === 'object' ) {
37
+ // Node/CommonJS
38
+ module.exports = factory( require( 'jquery' ) );
39
+ }
40
40
  else if ( jQuery && !jQuery.fn.dataTable ) {
41
41
  // Define using browser globals otherwise
42
42
  // Prevent multiple instantiations if the script is loaded twice
@@ -111,9 +111,17 @@
111
111
  // Escape regular expression special characters
112
112
  var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
113
113
 
114
- // U+2009 is thin space and U+202F is narrow no-break space, both used in many
115
- // standards as thousands separators
116
- var _re_formatted_numeric = /[',$£€¥%\u2009\u202F]/g;
114
+ // http://en.wikipedia.org/wiki/Foreign_exchange_market
115
+ // - \u20BD - Russian ruble.
116
+ // - \u20a9 - South Korean Won
117
+ // - \u20BA - Turkish Lira
118
+ // - \u20B9 - Indian Rupee
119
+ // - R - Brazil (R$) and South Africa
120
+ // - fr - Swiss Franc
121
+ // - kr - Swedish krona, Norwegian krone and Danish krone
122
+ // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
123
+ // standards as thousands separators.
124
+ var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
117
125
 
118
126
 
119
127
  var _empty = function ( d ) {
@@ -142,6 +150,13 @@
142
150
  var _isNumber = function ( d, decimalPoint, formatted ) {
143
151
  var strType = typeof d === 'string';
144
152
 
153
+ // If empty return immediately so there must be a number if it is a
154
+ // formatted string (this stops the string "k", or "kr", etc being detected
155
+ // as a formatted number for currency
156
+ if ( _empty( d ) ) {
157
+ return true;
158
+ }
159
+
145
160
  if ( decimalPoint && strType ) {
146
161
  d = _numToDecimal( d, decimalPoint );
147
162
  }
@@ -150,7 +165,7 @@
150
165
  d = d.replace( _re_formatted_numeric, '' );
151
166
  }
152
167
 
153
- return _empty( d ) || (!isNaN( parseFloat(d) ) && isFinite( d ));
168
+ return !isNaN( parseFloat(d) ) && isFinite( d );
154
169
  };
155
170
 
156
171
 
@@ -452,6 +467,11 @@
452
467
  _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
453
468
  _fnCompatMap( init, 'searching', 'bFilter' );
454
469
 
470
+ // Boolean initialisation of x-scrolling
471
+ if ( typeof init.sScrollX === 'boolean' ) {
472
+ init.sScrollX = init.sScrollX ? '100%' : '';
473
+ }
474
+
455
475
  // Column search objects are in an array, so it needs to be converted
456
476
  // element by element
457
477
  var searchCols = init.aoSearchCols;
@@ -478,6 +498,12 @@
478
498
  _fnCompatMap( init, 'orderData', 'aDataSort' );
479
499
  _fnCompatMap( init, 'orderSequence', 'asSorting' );
480
500
  _fnCompatMap( init, 'orderDataType', 'sortDataType' );
501
+
502
+ // orderData can be given as an integer
503
+ var dataSort = init.aDataSort;
504
+ if ( dataSort && ! $.isArray( dataSort ) ) {
505
+ init.aDataSort = [ dataSort ];
506
+ }
481
507
  }
482
508
 
483
509
 
@@ -493,7 +519,7 @@
493
519
  // Scrolling feature / quirks detection
494
520
  var n = $('<div/>')
495
521
  .css( {
496
- position: 'absolute',
522
+ position: 'fixed',
497
523
  top: 0,
498
524
  left: 0,
499
525
  height: 1,
@@ -528,7 +554,10 @@
528
554
 
529
555
  // In rtl text layout, some browsers (most, but not all) will place the
530
556
  // scrollbar on the left, rather than the right.
531
- browser.bScrollbarLeft = test.offset().left !== 1;
557
+ browser.bScrollbarLeft = Math.round( test.offset().left ) !== 1;
558
+
559
+ // IE8- don't provide height and width for getBoundingClientRect
560
+ browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
532
561
 
533
562
  n.remove();
534
563
  }
@@ -595,7 +624,7 @@
595
624
  searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
596
625
 
597
626
  // Use the default column options function to initialise classes etc
598
- _fnColumnOptions( oSettings, iCol, null );
627
+ _fnColumnOptions( oSettings, iCol, $(nTh).data() );
599
628
  }
600
629
 
601
630
 
@@ -658,7 +687,7 @@
658
687
  /* iDataSort to be applied (backwards compatibility), but aDataSort will take
659
688
  * priority if defined
660
689
  */
661
- if ( typeof oOptions.iDataSort === 'number' )
690
+ if ( oOptions.iDataSort !== undefined )
662
691
  {
663
692
  oCol.aDataSort = [ oOptions.iDataSort ];
664
693
  }
@@ -987,7 +1016,8 @@
987
1016
  /* Create the object for storing information about this new row */
988
1017
  var iRow = oSettings.aoData.length;
989
1018
  var oData = $.extend( true, {}, DataTable.models.oRow, {
990
- src: nTr ? 'dom' : 'data'
1019
+ src: nTr ? 'dom' : 'data',
1020
+ idx: iRow
991
1021
  } );
992
1022
 
993
1023
  oData._aData = aDataIn;
@@ -1010,6 +1040,11 @@
1010
1040
  /* Add to the display array */
1011
1041
  oSettings.aiDisplayMaster.push( iRow );
1012
1042
 
1043
+ var id = oSettings.rowIdFn( aDataIn );
1044
+ if ( id !== undefined ) {
1045
+ oSettings.aIds[ id ] = oData;
1046
+ }
1047
+
1013
1048
  /* Create the DOM information, or register it if already present */
1014
1049
  if ( nTr || ! oSettings.oFeatures.bDeferRender )
1015
1050
  {
@@ -1153,7 +1188,7 @@
1153
1188
  */
1154
1189
  function _fnSplitObjNotation( str )
1155
1190
  {
1156
- return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) {
1191
+ return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
1157
1192
  return s.replace(/\\./g, '.');
1158
1193
  } );
1159
1194
  }
@@ -1519,7 +1554,7 @@
1519
1554
  }
1520
1555
 
1521
1556
  // Update DataTables special `DT_*` attributes for the row
1522
- _fnRowAttributes( row );
1557
+ _fnRowAttributes( settings, row );
1523
1558
  }
1524
1559
  }
1525
1560
 
@@ -1614,12 +1649,18 @@
1614
1649
  else {
1615
1650
  // Existing row object passed in
1616
1651
  tds = row.anCells;
1617
-
1652
+
1618
1653
  for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
1619
1654
  cellProcess( tds[j] );
1620
1655
  }
1621
1656
  }
1622
1657
 
1658
+ // Read the ID from the DOM if present
1659
+ var id = row.getAttribute( 'id' );
1660
+ if ( id ) {
1661
+ _fnSetObjectDataFn( settings.rowId )( d, id );
1662
+ }
1663
+
1623
1664
  return {
1624
1665
  data: d,
1625
1666
  cells: tds
@@ -1657,7 +1698,7 @@
1657
1698
  nTr._DT_RowIndex = iRow;
1658
1699
 
1659
1700
  /* Special parameters can be given by the data source to be used on the row */
1660
- _fnRowAttributes( row );
1701
+ _fnRowAttributes( oSettings, row );
1661
1702
 
1662
1703
  /* Process each column */
1663
1704
  for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
@@ -1709,17 +1750,20 @@
1709
1750
  /**
1710
1751
  * Add attributes to a row based on the special `DT_*` parameters in a data
1711
1752
  * source object.
1753
+ * @param {object} settings DataTables settings object
1712
1754
  * @param {object} DataTables row object for the row to be modified
1713
1755
  * @memberof DataTable#oApi
1714
1756
  */
1715
- function _fnRowAttributes( row )
1757
+ function _fnRowAttributes( settings, row )
1716
1758
  {
1717
1759
  var tr = row.nTr;
1718
1760
  var data = row._aData;
1719
1761
 
1720
1762
  if ( tr ) {
1721
- if ( data.DT_RowId ) {
1722
- tr.id = data.DT_RowId;
1763
+ var id = settings.rowIdFn( data );
1764
+
1765
+ if ( id ) {
1766
+ tr.id = id;
1723
1767
  }
1724
1768
 
1725
1769
  if ( data.DT_RowClass ) {
@@ -1734,6 +1778,10 @@
1734
1778
  .addClass( data.DT_RowClass );
1735
1779
  }
1736
1780
 
1781
+ if ( data.DT_RowAttr ) {
1782
+ $(tr).attr( data.DT_RowAttr );
1783
+ }
1784
+
1737
1785
  if ( data.DT_RowData ) {
1738
1786
  $(tr).data( data.DT_RowData );
1739
1787
  }
@@ -1780,7 +1828,7 @@
1780
1828
  }
1781
1829
  }
1782
1830
 
1783
- if ( column.sTitle != cell.html() ) {
1831
+ if ( column.sTitle != cell[0].innerHTML ) {
1784
1832
  cell.html( column.sTitle );
1785
1833
  }
1786
1834
 
@@ -2252,6 +2300,7 @@
2252
2300
 
2253
2301
  /* Built our DOM structure - replace the holding div with what we want */
2254
2302
  holding.replaceWith( insert );
2303
+ oSettings.nHolding = null;
2255
2304
  }
2256
2305
 
2257
2306
 
@@ -2367,8 +2416,6 @@
2367
2416
  return aReturn;
2368
2417
  }
2369
2418
 
2370
-
2371
-
2372
2419
  /**
2373
2420
  * Create an Ajax call based on the table's settings, taking into account that
2374
2421
  * parameters can have multiple forms, and backwards compatibility.
@@ -2411,16 +2458,20 @@
2411
2458
  var ajaxData;
2412
2459
  var ajax = oSettings.ajax;
2413
2460
  var instance = oSettings.oInstance;
2461
+ var callback = function ( json ) {
2462
+ _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
2463
+ fn( json );
2464
+ };
2414
2465
 
2415
2466
  if ( $.isPlainObject( ajax ) && ajax.data )
2416
2467
  {
2417
2468
  ajaxData = ajax.data;
2418
2469
 
2419
2470
  var newData = $.isFunction( ajaxData ) ?
2420
- ajaxData( data ) : // fn can manipulate data or return an object
2421
- ajaxData; // object or array to merge
2471
+ ajaxData( data, oSettings ) : // fn can manipulate data or return
2472
+ ajaxData; // an object object or array to merge
2422
2473
 
2423
- // If the function returned an object, use that alone
2474
+ // If the function returned something, use that alone
2424
2475
  data = $.isFunction( ajaxData ) && newData ?
2425
2476
  newData :
2426
2477
  $.extend( true, data, newData );
@@ -2435,24 +2486,25 @@
2435
2486
  "success": function (json) {
2436
2487
  var error = json.error || json.sError;
2437
2488
  if ( error ) {
2438
- oSettings.oApi._fnLog( oSettings, 0, error );
2489
+ _fnLog( oSettings, 0, error );
2439
2490
  }
2440
2491
 
2441
2492
  oSettings.json = json;
2442
- _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] );
2443
- fn( json );
2493
+ callback( json );
2444
2494
  },
2445
2495
  "dataType": "json",
2446
2496
  "cache": false,
2447
2497
  "type": oSettings.sServerMethod,
2448
2498
  "error": function (xhr, error, thrown) {
2449
- var log = oSettings.oApi._fnLog;
2499
+ var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
2450
2500
 
2451
- if ( error == "parsererror" ) {
2452
- log( oSettings, 0, 'Invalid JSON response', 1 );
2453
- }
2454
- else if ( xhr.readyState === 4 ) {
2455
- log( oSettings, 0, 'Ajax error', 7 );
2501
+ if ( $.inArray( true, ret ) === -1 ) {
2502
+ if ( error == "parsererror" ) {
2503
+ _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
2504
+ }
2505
+ else if ( xhr.readyState === 4 ) {
2506
+ _fnLog( oSettings, 0, 'Ajax error', 7 );
2507
+ }
2456
2508
  }
2457
2509
 
2458
2510
  _fnProcessingDisplay( oSettings, false );
@@ -2473,7 +2525,7 @@
2473
2525
  $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2474
2526
  return { name: key, value: val };
2475
2527
  } ),
2476
- fn,
2528
+ callback,
2477
2529
  oSettings
2478
2530
  );
2479
2531
  }
@@ -2487,7 +2539,7 @@
2487
2539
  else if ( $.isFunction( ajax ) )
2488
2540
  {
2489
2541
  // Is a function - let the caller define what needs to be done
2490
- oSettings.jqXHR = ajax.call( instance, data, fn, oSettings );
2542
+ oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
2491
2543
  }
2492
2544
  else
2493
2545
  {
@@ -2653,6 +2705,7 @@
2653
2705
  return json[old] !== undefined ? json[old] : json[modern];
2654
2706
  };
2655
2707
 
2708
+ var data = _fnAjaxDataSrc( settings, json );
2656
2709
  var draw = compat( 'sEcho', 'draw' );
2657
2710
  var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2658
2711
  var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
@@ -2669,7 +2722,6 @@
2669
2722
  settings._iRecordsTotal = parseInt(recordsTotal, 10);
2670
2723
  settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
2671
2724
 
2672
- var data = _fnAjaxDataSrc( settings, json );
2673
2725
  for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2674
2726
  _fnAddData( settings, data[i] );
2675
2727
  }
@@ -2712,7 +2764,6 @@
2712
2764
  json;
2713
2765
  }
2714
2766
 
2715
-
2716
2767
  /**
2717
2768
  * Generate the node required for filtering text
2718
2769
  * @returns {node} Filter control element
@@ -2993,7 +3044,7 @@
2993
3044
  *
2994
3045
  * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
2995
3046
  */
2996
- var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) {
3047
+ var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
2997
3048
  if ( word.charAt(0) === '"' ) {
2998
3049
  var m = word.match( /^"(.*)"$/ );
2999
3050
  word = m ? m[1] : word;
@@ -3238,6 +3289,7 @@
3238
3289
  var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3239
3290
  var columns = settings.aoColumns, column;
3240
3291
  var features = settings.oFeatures;
3292
+ var deferLoading = settings.bDeferLoading; // value modified by the draw
3241
3293
 
3242
3294
  /* Ensure that the table data is fully initialised */
3243
3295
  if ( ! settings.bInitialised ) {
@@ -3269,6 +3321,8 @@
3269
3321
  }
3270
3322
  }
3271
3323
 
3324
+ _fnCallbackFire( settings, null, 'preInit', [settings] );
3325
+
3272
3326
  // If there is default sorting required - let's do it. The sort function
3273
3327
  // will do the drawing for us. Otherwise we draw the table regardless of the
3274
3328
  // Ajax source - this allows the table to look initialised for Ajax sourcing
@@ -3277,7 +3331,7 @@
3277
3331
 
3278
3332
  // Server-side processing init complete is done by _fnAjaxUpdateDraw
3279
3333
  var dataSrc = _fnDataSource( settings );
3280
- if ( dataSrc != 'ssp' ) {
3334
+ if ( dataSrc != 'ssp' || deferLoading ) {
3281
3335
  // if there is an ajax source load the data
3282
3336
  if ( dataSrc == 'ajax' ) {
3283
3337
  _fnBuildAjax( settings, [], function(json) {
@@ -3318,9 +3372,9 @@
3318
3372
  {
3319
3373
  settings._bInitComplete = true;
3320
3374
 
3321
- // On an Ajax load we now have data and therefore want to apply the column
3322
- // sizing
3323
- if ( json ) {
3375
+ // When data was added after the initialisation (data or Ajax) we need to
3376
+ // calculate the column sizing
3377
+ if ( json || settings.oInit.aaData ) {
3324
3378
  _fnAdjustColumnSizing( settings );
3325
3379
  }
3326
3380
 
@@ -3660,8 +3714,8 @@
3660
3714
  .append(
3661
3715
  $(_div, { 'class': classes.sScrollBody } )
3662
3716
  .css( {
3717
+ position: 'relative',
3663
3718
  overflow: 'auto',
3664
- height: size( scrollY ),
3665
3719
  width: size( scrollX )
3666
3720
  } )
3667
3721
  .append( table )
@@ -3697,7 +3751,7 @@
3697
3751
 
3698
3752
  // When the body is scrolled, then we also want to scroll the headers
3699
3753
  if ( scrollX ) {
3700
- $(scrollBody).scroll( function (e) {
3754
+ $(scrollBody).on( 'scroll.DT', function (e) {
3701
3755
  var scrollLeft = this.scrollLeft;
3702
3756
 
3703
3757
  scrollHead.scrollLeft = scrollLeft;
@@ -3708,6 +3762,11 @@
3708
3762
  } );
3709
3763
  }
3710
3764
 
3765
+ $(scrollBody).css(
3766
+ scrollY && scroll.bCollapse ? 'max-height' : 'height',
3767
+ scrollY
3768
+ );
3769
+
3711
3770
  settings.nScrollHead = scrollHead;
3712
3771
  settings.nScrollBody = scrollBody;
3713
3772
  settings.nScrollFoot = scrollFoot;
@@ -3824,13 +3883,6 @@
3824
3883
  }, footerSrcEls );
3825
3884
  }
3826
3885
 
3827
- // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
3828
- // will end up forcing the scrollbar to appear, making our measurements wrong for when we
3829
- // then hide it (end of this function), so add the header height to the body scroller.
3830
- if ( scroll.bCollapse && scrollY !== "" ) {
3831
- divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px";
3832
- }
3833
-
3834
3886
  // Size the table as a whole
3835
3887
  sanityWidth = table.outerWidth();
3836
3888
  if ( scrollX === "" ) {
@@ -3845,32 +3897,17 @@
3845
3897
  ) {
3846
3898
  tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3847
3899
  }
3900
+
3901
+ // Recalculate the sanity width
3902
+ sanityWidth = table.outerWidth();
3848
3903
  }
3849
- else
3850
- {
3851
- // x scrolling
3852
- if ( scrollXInner !== "" ) {
3853
- // x scroll inner has been given - use it
3854
- tableStyle.width = _fnStringToCss(scrollXInner);
3855
- }
3856
- else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {
3857
- // There is y-scrolling - try to take account of the y scroll bar
3858
- tableStyle.width = _fnStringToCss( sanityWidth-barWidth );
3859
- if ( table.outerWidth() > sanityWidth-barWidth ) {
3860
- // Not possible to take account of it
3861
- tableStyle.width = _fnStringToCss( sanityWidth );
3862
- }
3863
- }
3864
- else {
3865
- // When all else fails
3866
- tableStyle.width = _fnStringToCss( sanityWidth );
3867
- }
3868
- }
3904
+ else if ( scrollXInner !== "" ) {
3905
+ // legacy x scroll inner has been given - use it
3906
+ tableStyle.width = _fnStringToCss(scrollXInner);
3869
3907
 
3870
- // Recalculate the sanity width - now that we've applied the required width,
3871
- // before it was a temporary variable. This is required because the column
3872
- // width calculation is done before this table DOM is created.
3873
- sanityWidth = table.outerWidth();
3908
+ // Recalculate the sanity width
3909
+ sanityWidth = table.outerWidth();
3910
+ }
3874
3911
 
3875
3912
  // Hidden header should have zero height, so remove padding and borders. Then
3876
3913
  // set the width based on the real headers
@@ -3978,18 +4015,6 @@
3978
4015
  }
3979
4016
  }
3980
4017
 
3981
- if ( scrollY && scroll.bCollapse ) {
3982
- divBodyStyle.height = _fnStringToCss( scrollY );
3983
-
3984
- var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?
3985
- barWidth :
3986
- 0;
3987
-
3988
- if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {
3989
- divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );
3990
- }
3991
- }
3992
-
3993
4018
  /* Finally set the width's of the header and footer tables */
3994
4019
  var iOuterWidth = table.outerWidth();
3995
4020
  divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
@@ -4078,10 +4103,17 @@
4078
4103
  columnCount = columns.length,
4079
4104
  visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4080
4105
  headerCells = $('th', oSettings.nTHead),
4081
- tableWidthAttr = table.getAttribute('width'),
4106
+ tableWidthAttr = table.getAttribute('width'), // from DOM element
4082
4107
  tableContainer = table.parentNode,
4083
4108
  userInputs = false,
4084
- i, column, columnIdx, width, outerWidth;
4109
+ i, column, columnIdx, width, outerWidth,
4110
+ browser = oSettings.oBrowser,
4111
+ ie67 = browser.bScrollOversize;
4112
+
4113
+ var styleWidth = table.style.width;
4114
+ if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
4115
+ tableWidthAttr = styleWidth;
4116
+ }
4085
4117
 
4086
4118
  /* Convert any user input sizes into pixel sizes */
4087
4119
  for ( i=0 ; i<visibleColumns.length ; i++ ) {
@@ -4099,9 +4131,9 @@
4099
4131
  * the web- browser. No custom sizes can be set in order for this to happen,
4100
4132
  * nor scrolling used
4101
4133
  */
4102
- if ( ! userInputs && ! scrollX && ! scrollY &&
4103
- columnCount == _fnVisbleColumns( oSettings ) &&
4104
- columnCount == headerCells.length
4134
+ if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
4135
+ columnCount == _fnVisbleColumns( oSettings ) &&
4136
+ columnCount == headerCells.length
4105
4137
  ) {
4106
4138
  for ( i=0 ; i<columnCount ; i++ ) {
4107
4139
  columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );
@@ -4109,22 +4141,29 @@
4109
4141
  }
4110
4142
  else
4111
4143
  {
4112
- // Otherwise construct a single row table with the widest node in the
4113
- // data, assign any user defined widths, then insert it into the DOM and
4114
- // allow the browser to do all the hard work of calculating table widths
4144
+ // Otherwise construct a single row, worst case, table with the widest
4145
+ // node in the data, assign any user defined widths, then insert it into
4146
+ // the DOM and allow the browser to do all the hard work of calculating
4147
+ // table widths
4115
4148
  var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4116
- .empty()
4117
4149
  .css( 'visibility', 'hidden' )
4118
- .removeAttr( 'id' )
4119
- .append( $(oSettings.nTHead).clone( false ) )
4120
- .append( $(oSettings.nTFoot).clone( false ) )
4121
- .append( $('<tbody><tr/></tbody>') );
4150
+ .removeAttr( 'id' );
4151
+
4152
+ // Clean up the table body
4153
+ tmpTable.find('tbody tr').remove();
4154
+ var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
4155
+
4156
+ // Clone the table header and footer - we can't use the header / footer
4157
+ // from the cloned table, since if scrolling is active, the table's
4158
+ // real header and footer are contained in different table tags
4159
+ tmpTable.find('thead, tfoot').remove();
4160
+ tmpTable
4161
+ .append( $(oSettings.nTHead).clone() )
4162
+ .append( $(oSettings.nTFoot).clone() );
4122
4163
 
4123
4164
  // Remove any assigned widths from the footer (from scrolling)
4124
4165
  tmpTable.find('tfoot th, tfoot td').css('width', '');
4125
4166
 
4126
- var tr = tmpTable.find( 'tbody tr' );
4127
-
4128
4167
  // Apply custom sizing to the cloned header
4129
4168
  headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4130
4169
 
@@ -4149,8 +4188,24 @@
4149
4188
  }
4150
4189
  }
4151
4190
 
4152
- // Table has been built, attach to the document so we can work with it
4153
- tmpTable.appendTo( tableContainer );
4191
+ // Table has been built, attach to the document so we can work with it.
4192
+ // A holding element is used, positioned at the top of the container
4193
+ // with minimal height, so it has no effect on if the container scrolls
4194
+ // or not. Otherwise it might trigger scrolling when it actually isn't
4195
+ // needed
4196
+ var holder = $('<div/>').css( scrollX || scrollY ?
4197
+ {
4198
+ position: 'absolute',
4199
+ top: 0,
4200
+ left: 0,
4201
+ height: 1,
4202
+ right: 0,
4203
+ overflow: 'hidden'
4204
+ } :
4205
+ {}
4206
+ )
4207
+ .append( tmpTable )
4208
+ .appendTo( tableContainer );
4154
4209
 
4155
4210
  // When scrolling (X or Y) we want to set the width of the table as
4156
4211
  // appropriate. However, when not scrolling leave the table width as it
@@ -4161,20 +4216,17 @@
4161
4216
  else if ( scrollX ) {
4162
4217
  tmpTable.css( 'width', 'auto' );
4163
4218
 
4164
- if ( tmpTable.width() < tableContainer.offsetWidth ) {
4165
- tmpTable.width( tableContainer.offsetWidth );
4219
+ if ( tmpTable.width() < tableContainer.clientWidth ) {
4220
+ tmpTable.width( tableContainer.clientWidth );
4166
4221
  }
4167
4222
  }
4168
4223
  else if ( scrollY ) {
4169
- tmpTable.width( tableContainer.offsetWidth );
4224
+ tmpTable.width( tableContainer.clientWidth );
4170
4225
  }
4171
4226
  else if ( tableWidthAttr ) {
4172
4227
  tmpTable.width( tableWidthAttr );
4173
4228
  }
4174
4229
 
4175
- // Take into account the y scrollbar
4176
- _fnScrollingWidthAdjust( oSettings, tmpTable[0] );
4177
-
4178
4230
  // Browsers need a bit of a hand when a width is assigned to any columns
4179
4231
  // when x-scrolling as they tend to collapse the table to the min-width,
4180
4232
  // even if we sent the column widths. So we need to keep track of what
@@ -4186,7 +4238,12 @@
4186
4238
 
4187
4239
  for ( i=0 ; i<visibleColumns.length ; i++ ) {
4188
4240
  column = columns[ visibleColumns[i] ];
4189
- outerWidth = $(headerCells[i]).outerWidth();
4241
+
4242
+ // Much prefer to use getBoundingClientRect due to its sub-pixel
4243
+ // resolution, but IE8- do not support the width property.
4244
+ outerWidth = browser.bBounding ?
4245
+ headerCells[i].getBoundingClientRect().width :
4246
+ $(headerCells[i]).outerWidth();
4190
4247
 
4191
4248
  total += column.sWidthOrig === null ?
4192
4249
  outerWidth :
@@ -4210,7 +4267,7 @@
4210
4267
  table.style.width = _fnStringToCss( tmpTable.css('width') );
4211
4268
 
4212
4269
  // Finished with the table - ditch it
4213
- tmpTable.remove();
4270
+ holder.remove();
4214
4271
  }
4215
4272
 
4216
4273
  // If there is a width attr, we want to attach an event listener which
@@ -4222,9 +4279,20 @@
4222
4279
  }
4223
4280
 
4224
4281
  if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4225
- $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4226
- _fnAdjustColumnSizing( oSettings );
4227
- } ) );
4282
+ var bindResize = function () {
4283
+ $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4284
+ _fnAdjustColumnSizing( oSettings );
4285
+ } ) );
4286
+ };
4287
+
4288
+ // IE6/7 will crash if we bind a resize event handler on page load.
4289
+ // To be removed in 1.11 which drops IE6/7 support
4290
+ if ( ie67 ) {
4291
+ setTimeout( bindResize, 1000 );
4292
+ }
4293
+ else {
4294
+ bindResize();
4295
+ }
4228
4296
 
4229
4297
  oSettings._reszEvt = true;
4230
4298
  }
@@ -4259,12 +4327,9 @@
4259
4327
  fn.apply( that, args );
4260
4328
  }, frequency );
4261
4329
  }
4262
- else if ( last ) {
4263
- last = now;
4264
- fn.apply( that, args );
4265
- }
4266
4330
  else {
4267
4331
  last = now;
4332
+ fn.apply( that, args );
4268
4333
  }
4269
4334
  };
4270
4335
  }
@@ -4294,27 +4359,6 @@
4294
4359
  }
4295
4360
 
4296
4361
 
4297
- /**
4298
- * Adjust a table's width to take account of vertical scroll bar
4299
- * @param {object} oSettings dataTables settings object
4300
- * @param {node} n table node
4301
- * @memberof DataTable#oApi
4302
- */
4303
-
4304
- function _fnScrollingWidthAdjust ( settings, n )
4305
- {
4306
- var scroll = settings.oScroll;
4307
-
4308
- if ( scroll.sX || scroll.sY ) {
4309
- // When y-scrolling only, we want to remove the width of the scroll bar
4310
- // so the table + scroll bar will fit into the area available, otherwise
4311
- // we fix the table at its current size with no adjustment
4312
- var correction = ! scroll.sX ? scroll.iBarWidth : 0;
4313
- n.style.width = _fnStringToCss( $(n).outerWidth() - correction );
4314
- }
4315
- }
4316
-
4317
-
4318
4362
  /**
4319
4363
  * Get the widest node
4320
4364
  * @param {object} settings dataTables settings object
@@ -4395,41 +4439,28 @@
4395
4439
  {
4396
4440
  // On first run a static variable is set, since this is only needed once.
4397
4441
  // Subsequent runs will just use the previously calculated value
4398
- if ( ! DataTable.__scrollbarWidth ) {
4399
- var inner = $('<p/>').css( {
4400
- width: '100%',
4401
- height: 200,
4402
- padding: 0
4403
- } )[0];
4404
-
4405
- var outer = $('<div/>')
4406
- .css( {
4442
+ var width = DataTable.__scrollbarWidth;
4443
+
4444
+ if ( width === undefined ) {
4445
+ var sizer = $('<p/>').css( {
4407
4446
  position: 'absolute',
4408
4447
  top: 0,
4409
4448
  left: 0,
4410
- width: 200,
4449
+ width: '100%',
4411
4450
  height: 150,
4412
4451
  padding: 0,
4413
- overflow: 'hidden',
4452
+ overflow: 'scroll',
4414
4453
  visibility: 'hidden'
4415
4454
  } )
4416
- .append( inner )
4417
- .appendTo( 'body' );
4455
+ .appendTo('body');
4418
4456
 
4419
- var w1 = inner.offsetWidth;
4420
- outer.css( 'overflow', 'scroll' );
4421
- var w2 = inner.offsetWidth;
4457
+ width = sizer[0].offsetWidth - sizer[0].clientWidth;
4458
+ DataTable.__scrollbarWidth = width;
4422
4459
 
4423
- if ( w1 === w2 ) {
4424
- w2 = outer[0].clientWidth;
4425
- }
4426
-
4427
- outer.remove();
4428
-
4429
- DataTable.__scrollbarWidth = w1 - w2;
4460
+ sizer.remove();
4430
4461
  }
4431
4462
 
4432
- return DataTable.__scrollbarWidth;
4463
+ return width;
4433
4464
  }
4434
4465
 
4435
4466
 
@@ -4720,6 +4751,10 @@
4720
4751
  // Yes, modify the sort
4721
4752
  nextSortIdx = next( sorting[sortIdx], true );
4722
4753
 
4754
+ if ( nextSortIdx === null && sorting.length === 1 ) {
4755
+ nextSortIdx = 0; // can't remove sorting completely
4756
+ }
4757
+
4723
4758
  if ( nextSortIdx === null ) {
4724
4759
  sorting.splice( sortIdx, 1 );
4725
4760
  }
@@ -4954,31 +4989,43 @@
4954
4989
 
4955
4990
  // Restore key features - todo - for 1.11 this needs to be done by
4956
4991
  // subscribed events
4957
- settings._iDisplayStart = state.start;
4958
- settings.iInitDisplayStart = state.start;
4959
- settings._iDisplayLength = state.length;
4960
- settings.aaSorting = [];
4992
+ if ( state.start !== undefined ) {
4993
+ settings._iDisplayStart = state.start;
4994
+ settings.iInitDisplayStart = state.start;
4995
+ }
4996
+ if ( state.length !== undefined ) {
4997
+ settings._iDisplayLength = state.length;
4998
+ }
4961
4999
 
4962
5000
  // Order
4963
- $.each( state.order, function ( i, col ) {
4964
- settings.aaSorting.push( col[0] >= columns.length ?
4965
- [ 0, col[1] ] :
4966
- col
4967
- );
4968
- } );
5001
+ if ( state.order !== undefined ) {
5002
+ settings.aaSorting = [];
5003
+ $.each( state.order, function ( i, col ) {
5004
+ settings.aaSorting.push( col[0] >= columns.length ?
5005
+ [ 0, col[1] ] :
5006
+ col
5007
+ );
5008
+ } );
5009
+ }
4969
5010
 
4970
5011
  // Search
4971
- $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
5012
+ if ( state.search !== undefined ) {
5013
+ $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
5014
+ }
4972
5015
 
4973
5016
  // Columns
4974
5017
  for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
4975
5018
  var col = state.columns[i];
4976
5019
 
4977
5020
  // Visibility
4978
- columns[i].bVisible = col.visible;
5021
+ if ( col.visible !== undefined ) {
5022
+ columns[i].bVisible = col.visible;
5023
+ }
4979
5024
 
4980
5025
  // Search
4981
- $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
5026
+ if ( col.search !== undefined ) {
5027
+ $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
5028
+ }
4982
5029
  }
4983
5030
 
4984
5031
  _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
@@ -5013,7 +5060,7 @@
5013
5060
  function _fnLog( settings, level, msg, tn )
5014
5061
  {
5015
5062
  msg = 'DataTables warning: '+
5016
- (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;
5063
+ (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
5017
5064
 
5018
5065
  if ( tn ) {
5019
5066
  msg += '. For more information about this error, please see '+
@@ -5025,12 +5072,19 @@
5025
5072
  var ext = DataTable.ext;
5026
5073
  var type = ext.sErrMode || ext.errMode;
5027
5074
 
5075
+ if ( settings ) {
5076
+ _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
5077
+ }
5078
+
5028
5079
  if ( type == 'alert' ) {
5029
5080
  alert( msg );
5030
5081
  }
5031
- else {
5082
+ else if ( type == 'throw' ) {
5032
5083
  throw new Error(msg);
5033
5084
  }
5085
+ else if ( typeof type == 'function' ) {
5086
+ type( settings, tn, msg );
5087
+ }
5034
5088
  }
5035
5089
  else if ( window.console && console.log ) {
5036
5090
  console.log( msg );
@@ -5173,13 +5227,13 @@
5173
5227
  * @param {object} settings dataTables settings object
5174
5228
  * @param {string} callbackArr Name of the array storage for the callbacks in
5175
5229
  * oSettings
5176
- * @param {string} event Name of the jQuery custom event to trigger. If null no
5177
- * trigger is fired
5230
+ * @param {string} eventName Name of the jQuery custom event to trigger. If
5231
+ * null no trigger is fired
5178
5232
  * @param {array} args Array of arguments to pass to the callback function /
5179
5233
  * trigger
5180
5234
  * @memberof DataTable#oApi
5181
5235
  */
5182
- function _fnCallbackFire( settings, callbackArr, e, args )
5236
+ function _fnCallbackFire( settings, callbackArr, eventName, args )
5183
5237
  {
5184
5238
  var ret = [];
5185
5239
 
@@ -5189,8 +5243,12 @@
5189
5243
  } );
5190
5244
  }
5191
5245
 
5192
- if ( e !== null ) {
5193
- $(settings.nTable).trigger( e+'.dt', args );
5246
+ if ( eventName !== null ) {
5247
+ var e = $.Event( eventName+'.dt' );
5248
+
5249
+ $(settings.nTable).trigger( e, args );
5250
+
5251
+ ret.push( e.result );
5194
5252
  }
5195
5253
 
5196
5254
  return ret;
@@ -5602,8 +5660,8 @@
5602
5660
  this.fnDraw = function( complete )
5603
5661
  {
5604
5662
  // Note that this isn't an exact match to the old call to _fnDraw - it takes
5605
- // into account the new data, but can old position.
5606
- this.api( true ).draw( ! complete );
5663
+ // into account the new data, but can hold position.
5664
+ this.api( true ).draw( complete );
5607
5665
  };
5608
5666
 
5609
5667
 
@@ -6051,6 +6109,7 @@
6051
6109
  var sId = this.getAttribute( 'id' );
6052
6110
  var bInitHandedOff = false;
6053
6111
  var defaults = DataTable.defaults;
6112
+ var $this = $(this);
6054
6113
 
6055
6114
 
6056
6115
  /* Sanity check */
@@ -6069,30 +6128,34 @@
6069
6128
  _fnCamelToHungarian( defaults.column, defaults.column, true );
6070
6129
 
6071
6130
  /* Setting up the initialisation object */
6072
- _fnCamelToHungarian( defaults, oInit );
6131
+ _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
6132
+
6133
+
6073
6134
 
6074
6135
  /* Check to see if we are re-initialising a table */
6075
6136
  var allSettings = DataTable.settings;
6076
6137
  for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
6077
6138
  {
6139
+ var s = allSettings[i];
6140
+
6078
6141
  /* Base check on table node */
6079
- if ( allSettings[i].nTable == this )
6142
+ if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
6080
6143
  {
6081
6144
  var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
6082
6145
  var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
6083
6146
 
6084
6147
  if ( emptyInit || bRetrieve )
6085
6148
  {
6086
- return allSettings[i].oInstance;
6149
+ return s.oInstance;
6087
6150
  }
6088
6151
  else if ( bDestroy )
6089
6152
  {
6090
- allSettings[i].oInstance.fnDestroy();
6153
+ s.oInstance.fnDestroy();
6091
6154
  break;
6092
6155
  }
6093
6156
  else
6094
6157
  {
6095
- _fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 );
6158
+ _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
6096
6159
  return;
6097
6160
  }
6098
6161
  }
@@ -6102,7 +6165,7 @@
6102
6165
  * instance by simply deleting it. This is under the assumption that the table has been
6103
6166
  * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6104
6167
  */
6105
- if ( allSettings[i].sTableId == this.id )
6168
+ if ( s.sTableId == this.id )
6106
6169
  {
6107
6170
  allSettings.splice( i, 1 );
6108
6171
  break;
@@ -6118,18 +6181,19 @@
6118
6181
 
6119
6182
  /* Create the settings object for this table and set some of the default parameters */
6120
6183
  var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6121
- "nTable": this,
6122
- "oApi": _that.internal,
6123
- "oInit": oInit,
6124
- "sDestroyWidth": $(this)[0].style.width,
6184
+ "sDestroyWidth": $this[0].style.width,
6125
6185
  "sInstance": sId,
6126
6186
  "sTableId": sId
6127
6187
  } );
6188
+ oSettings.nTable = this;
6189
+ oSettings.oApi = _that.internal;
6190
+ oSettings.oInit = oInit;
6191
+
6128
6192
  allSettings.push( oSettings );
6129
6193
 
6130
6194
  // Need to add the instance after the instance after the settings object has been added
6131
6195
  // to the settings array, so we can self reference the table instance if more than one
6132
- oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
6196
+ oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
6133
6197
 
6134
6198
  // Backwards compatibility, before we apply all the defaults
6135
6199
  _fnCompatOpts( oInit );
@@ -6185,6 +6249,7 @@
6185
6249
  "fnStateSaveCallback",
6186
6250
  "renderer",
6187
6251
  "searchDelay",
6252
+ "rowId",
6188
6253
  [ "iCookieDuration", "iStateDuration" ], // backwards compat
6189
6254
  [ "oSearch", "oPreviousSearch" ],
6190
6255
  [ "aoSearchCols", "aoPreSearchCols" ],
@@ -6212,6 +6277,8 @@
6212
6277
  _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
6213
6278
  _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
6214
6279
 
6280
+ oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
6281
+
6215
6282
  var oClasses = oSettings.oClasses;
6216
6283
 
6217
6284
  // @todo Remove in 1.11
@@ -6239,16 +6306,13 @@
6239
6306
  {
6240
6307
  $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6241
6308
  }
6242
- $(this).addClass( oClasses.sTable );
6309
+ $this.addClass( oClasses.sTable );
6243
6310
 
6244
6311
  /* Calculate the scroll bar width and cache it for use later on */
6245
6312
  if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6246
6313
  {
6247
6314
  oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6248
6315
  }
6249
- if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling
6250
- oSettings.oScroll.sX = '100%';
6251
- }
6252
6316
 
6253
6317
  if ( oSettings.iInitDisplayStart === undefined )
6254
6318
  {
@@ -6305,7 +6369,7 @@
6305
6369
 
6306
6370
  /* Remove row stripe classes if they are already on the table row */
6307
6371
  var stripeClasses = oSettings.asStripeClasses;
6308
- var rowOne = $('tbody tr:eq(0)', this);
6372
+ var rowOne = $this.children('tbody').find('tr').eq(0);
6309
6373
  if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6310
6374
  return rowOne.hasClass(el);
6311
6375
  } ) ) !== -1 ) {
@@ -6356,7 +6420,7 @@
6356
6420
  */
6357
6421
  if ( rowOne.length ) {
6358
6422
  var a = function ( cell, name ) {
6359
- return cell.getAttribute( 'data-'+name ) ? name : null;
6423
+ return cell.getAttribute( 'data-'+name ) !== null ? name : null;
6360
6424
  };
6361
6425
 
6362
6426
  $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
@@ -6445,25 +6509,25 @@
6445
6509
  _fnBrowserDetect( oSettings );
6446
6510
 
6447
6511
  // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6448
- var captions = $(this).children('caption').each( function () {
6449
- this._captionSide = $(this).css('caption-side');
6512
+ var captions = $this.children('caption').each( function () {
6513
+ this._captionSide = $this.css('caption-side');
6450
6514
  } );
6451
6515
 
6452
- var thead = $(this).children('thead');
6516
+ var thead = $this.children('thead');
6453
6517
  if ( thead.length === 0 )
6454
6518
  {
6455
6519
  thead = $('<thead/>').appendTo(this);
6456
6520
  }
6457
6521
  oSettings.nTHead = thead[0];
6458
6522
 
6459
- var tbody = $(this).children('tbody');
6523
+ var tbody = $this.children('tbody');
6460
6524
  if ( tbody.length === 0 )
6461
6525
  {
6462
6526
  tbody = $('<tbody/>').appendTo(this);
6463
6527
  }
6464
6528
  oSettings.nTBody = tbody[0];
6465
6529
 
6466
- var tfoot = $(this).children('tfoot');
6530
+ var tfoot = $this.children('tfoot');
6467
6531
  if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6468
6532
  {
6469
6533
  // If we are a scrolling table, and no footer has been given, then we need to create
@@ -6472,7 +6536,7 @@
6472
6536
  }
6473
6537
 
6474
6538
  if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6475
- $(this).addClass( oClasses.sNoFooter );
6539
+ $this.addClass( oClasses.sNoFooter );
6476
6540
  }
6477
6541
  else if ( tfoot.length > 0 ) {
6478
6542
  oSettings.nTFoot = tfoot[0];
@@ -6681,10 +6745,8 @@
6681
6745
  */
6682
6746
  _Api = function ( context, data )
6683
6747
  {
6684
- if ( ! this instanceof _Api ) {
6685
- throw 'DT API must be constructed as a new object';
6686
- // or should it do the 'new' for the caller?
6687
- // return new _Api.apply( this, arguments );
6748
+ if ( ! (this instanceof _Api) ) {
6749
+ return new _Api( context, data );
6688
6750
  }
6689
6751
 
6690
6752
  var settings = [];
@@ -6725,24 +6787,24 @@
6725
6787
  DataTable.Api = _Api;
6726
6788
 
6727
6789
  _Api.prototype = /** @lends DataTables.Api */{
6728
- /**
6729
- * Return a new Api instance, comprised of the data held in the current
6730
- * instance, join with the other array(s) and/or value(s).
6731
- *
6732
- * An alias for `Array.prototype.concat`.
6733
- *
6734
- * @type method
6735
- * @param {*} value1 Arrays and/or values to concatenate.
6736
- * @param {*} [...] Additional arrays and/or values to concatenate.
6737
- * @returns {DataTables.Api} New API instance, comprising of the combined
6738
- * array.
6739
- */
6790
+ any: function ()
6791
+ {
6792
+ return this.count() !== 0;
6793
+ },
6794
+
6795
+
6740
6796
  concat: __arrayProto.concat,
6741
6797
 
6742
6798
 
6743
6799
  context: [], // array of table settings objects
6744
6800
 
6745
6801
 
6802
+ count: function ()
6803
+ {
6804
+ return this.flatten().length;
6805
+ },
6806
+
6807
+
6746
6808
  each: function ( fn )
6747
6809
  {
6748
6810
  for ( var i=0, ien=this.length ; i<ien; i++ ) {
@@ -6803,7 +6865,6 @@
6803
6865
  return -1;
6804
6866
  },
6805
6867
 
6806
- // Note that `alwaysNew` is internal - use iteratorNew externally
6807
6868
  iterator: function ( flatten, type, fn, alwaysNew ) {
6808
6869
  var
6809
6870
  a = [], ret,
@@ -6977,7 +7038,7 @@
6977
7038
  _Api.extend = function ( scope, obj, ext )
6978
7039
  {
6979
7040
  // Only extend API instances and static properties of the API
6980
- if ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7041
+ if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6981
7042
  return;
6982
7043
  }
6983
7044
 
@@ -7226,15 +7287,21 @@
7226
7287
 
7227
7288
  /**
7228
7289
  * Redraw the tables in the current context.
7229
- *
7230
- * @param {boolean} [reset=true] Reset (default) or hold the current paging
7231
- * position. A full re-sort and re-filter is performed when this method is
7232
- * called, which is why the pagination reset is the default action.
7233
- * @returns {DataTables.Api} this
7234
7290
  */
7235
- _api_register( 'draw()', function ( resetPaging ) {
7291
+ _api_register( 'draw()', function ( paging ) {
7236
7292
  return this.iterator( 'table', function ( settings ) {
7237
- _fnReDraw( settings, resetPaging===false );
7293
+ if ( paging === 'page' ) {
7294
+ _fnDraw( settings );
7295
+ }
7296
+ else {
7297
+ if ( typeof paging === 'string' ) {
7298
+ paging = paging === 'full-hold' ?
7299
+ false :
7300
+ true;
7301
+ }
7302
+
7303
+ _fnReDraw( settings, paging===false );
7304
+ }
7238
7305
  } );
7239
7306
  } );
7240
7307
 
@@ -7308,7 +7375,8 @@
7308
7375
  "end": settings.fnDisplayEnd(),
7309
7376
  "length": len,
7310
7377
  "recordsTotal": settings.fnRecordsTotal(),
7311
- "recordsDisplay": visRecords
7378
+ "recordsDisplay": visRecords,
7379
+ "serverSide": _fnDataSource( settings ) === 'ssp'
7312
7380
  };
7313
7381
  } );
7314
7382
 
@@ -7343,13 +7411,28 @@
7343
7411
 
7344
7412
 
7345
7413
  var __reload = function ( settings, holdPosition, callback ) {
7414
+ // Use the draw event to trigger a callback
7415
+ if ( callback ) {
7416
+ var api = new _Api( settings );
7417
+
7418
+ api.one( 'draw', function () {
7419
+ callback( api.ajax.json() );
7420
+ } );
7421
+ }
7422
+
7346
7423
  if ( _fnDataSource( settings ) == 'ssp' ) {
7347
7424
  _fnReDraw( settings, holdPosition );
7348
7425
  }
7349
7426
  else {
7350
- // Trigger xhr
7351
7427
  _fnProcessingDisplay( settings, true );
7352
7428
 
7429
+ // Cancel an existing request
7430
+ var xhr = settings.jqXHR;
7431
+ if ( xhr && xhr.readyState !== 4 ) {
7432
+ xhr.abort();
7433
+ }
7434
+
7435
+ // Trigger xhr
7353
7436
  _fnBuildAjax( settings, [], function( json ) {
7354
7437
  _fnClearTable( settings );
7355
7438
 
@@ -7362,16 +7445,6 @@
7362
7445
  _fnProcessingDisplay( settings, false );
7363
7446
  } );
7364
7447
  }
7365
-
7366
- // Use the draw event to trigger a callback, regardless of if it is an async
7367
- // or sync draw
7368
- if ( callback ) {
7369
- var api = new _Api( settings );
7370
-
7371
- api.one( 'draw', function () {
7372
- callback( api.ajax.json() );
7373
- } );
7374
- }
7375
7448
  };
7376
7449
 
7377
7450
 
@@ -7487,7 +7560,7 @@
7487
7560
 
7488
7561
 
7489
7562
 
7490
- var _selector_run = function ( selector, select )
7563
+ var _selector_run = function ( type, selector, selectFn, settings, opts )
7491
7564
  {
7492
7565
  var
7493
7566
  out = [], res,
@@ -7506,7 +7579,7 @@
7506
7579
  [ selector[i] ];
7507
7580
 
7508
7581
  for ( j=0, jen=a.length ; j<jen ; j++ ) {
7509
- res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7582
+ res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7510
7583
 
7511
7584
  if ( res && res.length ) {
7512
7585
  out.push.apply( out, res );
@@ -7514,6 +7587,14 @@
7514
7587
  }
7515
7588
  }
7516
7589
 
7590
+ // selector extensions
7591
+ var ext = _ext.selector[ type ];
7592
+ if ( ext.length ) {
7593
+ for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7594
+ out = ext[i]( settings, opts, out );
7595
+ }
7596
+ }
7597
+
7517
7598
  return out;
7518
7599
  };
7519
7600
 
@@ -7526,15 +7607,15 @@
7526
7607
 
7527
7608
  // Backwards compatibility for 1.9- which used the terminology filter rather
7528
7609
  // than search
7529
- if ( opts.filter && ! opts.search ) {
7610
+ if ( opts.filter && opts.search === undefined ) {
7530
7611
  opts.search = opts.filter;
7531
7612
  }
7532
7613
 
7533
- return {
7534
- search: opts.search || 'none',
7535
- order: opts.order || 'current',
7536
- page: opts.page || 'all'
7537
- };
7614
+ return $.extend( {
7615
+ search: 'none',
7616
+ order: 'current',
7617
+ page: 'all'
7618
+ }, opts );
7538
7619
  };
7539
7620
 
7540
7621
 
@@ -7546,6 +7627,7 @@
7546
7627
  // Assign the first element to the first item in the instance
7547
7628
  // and truncate the instance and context
7548
7629
  inst[0] = inst[i];
7630
+ inst[0].length = 1;
7549
7631
  inst.length = 1;
7550
7632
  inst.context = [ inst.context[i] ];
7551
7633
 
@@ -7632,7 +7714,7 @@
7632
7714
 
7633
7715
  var __row_selector = function ( settings, selector, opts )
7634
7716
  {
7635
- return _selector_run( selector, function ( sel ) {
7717
+ var run = function ( sel ) {
7636
7718
  var selInt = _intVal( sel );
7637
7719
  var i, ien;
7638
7720
 
@@ -7675,6 +7757,26 @@
7675
7757
  }
7676
7758
  }
7677
7759
 
7760
+ // ID selector. Want to always be able to select rows by id, regardless
7761
+ // of if the tr element has been created or not, so can't rely upon
7762
+ // jQuery here - hence a custom implementation. This does not match
7763
+ // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7764
+ // but to select it using a CSS selector engine (like Sizzle or
7765
+ // querySelect) it would need to need to be escaped for some characters.
7766
+ // DataTables simplifies this for row selectors since you can select
7767
+ // only a row. A # indicates an id any anything that follows is the id -
7768
+ // unescaped.
7769
+ if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7770
+ // get row index from id
7771
+ var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7772
+ if ( rowObj !== undefined ) {
7773
+ return [ rowObj.idx ];
7774
+ }
7775
+
7776
+ // need to fall through to jQuery in case there is DOM id that
7777
+ // matches
7778
+ }
7779
+
7678
7780
  // Selector - jQuery selector string, array of nodes or jQuery object/
7679
7781
  // As jQuery's .filter() allows jQuery objects to be passed in filter,
7680
7782
  // it also allows arrays, so this will cope with all three options
@@ -7684,13 +7786,12 @@
7684
7786
  return this._DT_RowIndex;
7685
7787
  } )
7686
7788
  .toArray();
7687
- } );
7789
+ };
7790
+
7791
+ return _selector_run( 'row', selector, run, settings, opts );
7688
7792
  };
7689
7793
 
7690
7794
 
7691
- /**
7692
- *
7693
- */
7694
7795
  _api_register( 'rows()', function ( selector, opts ) {
7695
7796
  // argument shifting
7696
7797
  if ( selector === undefined ) {
@@ -7714,7 +7815,6 @@
7714
7815
  return inst;
7715
7816
  } );
7716
7817
 
7717
-
7718
7818
  _api_register( 'rows().nodes()', function () {
7719
7819
  return this.iterator( 'row', function ( settings, row ) {
7720
7820
  return settings.aoData[ row ].nTr || undefined;
@@ -7746,10 +7846,25 @@
7746
7846
  }, 1 );
7747
7847
  } );
7748
7848
 
7849
+ _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
7850
+ var a = [];
7851
+ var context = this.context;
7852
+
7853
+ // `iterator` will drop undefined values, but in this case we want them
7854
+ for ( var i=0, ien=context.length ; i<ien ; i++ ) {
7855
+ for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
7856
+ var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
7857
+ a.push( (hash === true ? '#' : '' )+ id );
7858
+ }
7859
+ }
7860
+
7861
+ return new _Api( context, a );
7862
+ } );
7863
+
7749
7864
  _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7750
7865
  var that = this;
7751
7866
 
7752
- return this.iterator( 'row', function ( settings, row, thatIdx ) {
7867
+ this.iterator( 'row', function ( settings, row, thatIdx ) {
7753
7868
  var data = settings.aoData;
7754
7869
 
7755
7870
  data.splice( row, 1 );
@@ -7761,9 +7876,6 @@
7761
7876
  }
7762
7877
  }
7763
7878
 
7764
- // Remove the target row from the search array
7765
- var displayIndex = $.inArray( row, settings.aiDisplay );
7766
-
7767
7879
  // Delete from the display arrays
7768
7880
  _fnDeleteIndex( settings.aiDisplayMaster, row );
7769
7881
  _fnDeleteIndex( settings.aiDisplay, row );
@@ -7772,6 +7884,14 @@
7772
7884
  // Check for an 'overflow' they case for displaying the table
7773
7885
  _fnLengthOverflow( settings );
7774
7886
  } );
7887
+
7888
+ this.iterator( 'table', function ( settings ) {
7889
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7890
+ settings.aoData[i].idx = i;
7891
+ }
7892
+ } );
7893
+
7894
+ return this;
7775
7895
  } );
7776
7896
 
7777
7897
 
@@ -7868,6 +7988,14 @@
7868
7988
  // Convert to array of TR elements
7869
7989
  var rows = [];
7870
7990
  var addRow = function ( r, k ) {
7991
+ // Recursion to allow for arrays of jQuery objects
7992
+ if ( $.isArray( r ) || r instanceof $ ) {
7993
+ for ( var i=0, ien=r.length ; i<ien ; i++ ) {
7994
+ addRow( r[i], k );
7995
+ }
7996
+ return;
7997
+ }
7998
+
7871
7999
  // If we get a TR element, then just add it directly - up to the dev
7872
8000
  // to add the correct number of columns etc
7873
8001
  if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
@@ -7885,14 +8013,7 @@
7885
8013
  }
7886
8014
  };
7887
8015
 
7888
- if ( $.isArray( data ) || data instanceof $ ) {
7889
- for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7890
- addRow( data[i], klass );
7891
- }
7892
- }
7893
- else {
7894
- addRow( data, klass );
7895
- }
8016
+ addRow( data, klass );
7896
8017
 
7897
8018
  if ( row._details ) {
7898
8019
  row._details.remove();
@@ -7914,7 +8035,7 @@
7914
8035
  if ( ctx.length ) {
7915
8036
  var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
7916
8037
 
7917
- if ( row._details ) {
8038
+ if ( row && row._details ) {
7918
8039
  row._details.remove();
7919
8040
 
7920
8041
  row._detailsShow = undefined;
@@ -8117,7 +8238,7 @@
8117
8238
  names = _pluck( columns, 'sName' ),
8118
8239
  nodes = _pluck( columns, 'nTh' );
8119
8240
 
8120
- return _selector_run( selector, function ( s ) {
8241
+ var run = function ( s ) {
8121
8242
  var selInt = _intVal( s );
8122
8243
 
8123
8244
  // Selector - all
@@ -8183,7 +8304,9 @@
8183
8304
  } )
8184
8305
  .toArray();
8185
8306
  }
8186
- } );
8307
+ };
8308
+
8309
+ return _selector_run( 'column', selector, run, settings, opts );
8187
8310
  };
8188
8311
 
8189
8312
 
@@ -8246,9 +8369,6 @@
8246
8369
  };
8247
8370
 
8248
8371
 
8249
- /**
8250
- *
8251
- */
8252
8372
  _api_register( 'columns()', function ( selector, opts ) {
8253
8373
  // argument shifting
8254
8374
  if ( selector === undefined ) {
@@ -8272,42 +8392,28 @@
8272
8392
  return inst;
8273
8393
  } );
8274
8394
 
8275
-
8276
- /**
8277
- *
8278
- */
8279
8395
  _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8280
8396
  return this.iterator( 'column', function ( settings, column ) {
8281
8397
  return settings.aoColumns[column].nTh;
8282
8398
  }, 1 );
8283
8399
  } );
8284
8400
 
8285
-
8286
- /**
8287
- *
8288
- */
8289
8401
  _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8290
8402
  return this.iterator( 'column', function ( settings, column ) {
8291
8403
  return settings.aoColumns[column].nTf;
8292
8404
  }, 1 );
8293
8405
  } );
8294
8406
 
8295
-
8296
- /**
8297
- *
8298
- */
8299
8407
  _api_registerPlural( 'columns().data()', 'column().data()', function () {
8300
8408
  return this.iterator( 'column-rows', __columnData, 1 );
8301
8409
  } );
8302
8410
 
8303
-
8304
8411
  _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8305
8412
  return this.iterator( 'column', function ( settings, column ) {
8306
8413
  return settings.aoColumns[column].mData;
8307
8414
  }, 1 );
8308
8415
  } );
8309
8416
 
8310
-
8311
8417
  _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8312
8418
  return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8313
8419
  return _pluck_order( settings.aoData, rows,
@@ -8316,15 +8422,12 @@
8316
8422
  }, 1 );
8317
8423
  } );
8318
8424
 
8319
-
8320
8425
  _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8321
8426
  return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8322
8427
  return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8323
8428
  }, 1 );
8324
8429
  } );
8325
8430
 
8326
-
8327
-
8328
8431
  _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8329
8432
  return this.iterator( 'column', function ( settings, column ) {
8330
8433
  if ( vis === undefined ) {
@@ -8334,8 +8437,6 @@
8334
8437
  } );
8335
8438
  } );
8336
8439
 
8337
-
8338
-
8339
8440
  _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8340
8441
  return this.iterator( 'column', function ( settings, column ) {
8341
8442
  return type === 'visible' ?
@@ -8344,28 +8445,12 @@
8344
8445
  }, 1 );
8345
8446
  } );
8346
8447
 
8347
-
8348
- // _api_register( 'columns().show()', function () {
8349
- // var selector = this.selector;
8350
- // return this.columns( selector.cols, selector.opts ).visible( true );
8351
- // } );
8352
-
8353
-
8354
- // _api_register( 'columns().hide()', function () {
8355
- // var selector = this.selector;
8356
- // return this.columns( selector.cols, selector.opts ).visible( false );
8357
- // } );
8358
-
8359
-
8360
-
8361
8448
  _api_register( 'columns.adjust()', function () {
8362
8449
  return this.iterator( 'table', function ( settings ) {
8363
8450
  _fnAdjustColumnSizing( settings );
8364
8451
  }, 1 );
8365
8452
  } );
8366
8453
 
8367
-
8368
- // Convert from one column index type, to another type
8369
8454
  _api_register( 'column.index()', function ( type, idx ) {
8370
8455
  if ( this.context.length !== 0 ) {
8371
8456
  var ctx = this.context[0];
@@ -8379,7 +8464,6 @@
8379
8464
  }
8380
8465
  } );
8381
8466
 
8382
-
8383
8467
  _api_register( 'column()', function ( selector, opts ) {
8384
8468
  return _selector_first( this.columns( selector, opts ) );
8385
8469
  } );
@@ -8397,7 +8481,7 @@
8397
8481
  var columns = settings.aoColumns.length;
8398
8482
  var a, i, ien, j, o, host;
8399
8483
 
8400
- return _selector_run( selector, function ( s ) {
8484
+ var run = function ( s ) {
8401
8485
  var fnSelector = typeof s === 'function';
8402
8486
 
8403
8487
  if ( s === null || s === undefined || fnSelector ) {
@@ -8417,7 +8501,7 @@
8417
8501
  // Selector - function
8418
8502
  host = settings.aoData[ row ];
8419
8503
 
8420
- if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) {
8504
+ if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8421
8505
  a.push( o );
8422
8506
  }
8423
8507
  }
@@ -8448,7 +8532,9 @@
8448
8532
  };
8449
8533
  } )
8450
8534
  .toArray();
8451
- } );
8535
+ };
8536
+
8537
+ return _selector_run( 'cell', selector, run, settings, opts );
8452
8538
  };
8453
8539
 
8454
8540
 
@@ -8458,14 +8544,16 @@
8458
8544
  // Argument shifting
8459
8545
  if ( $.isPlainObject( rowSelector ) ) {
8460
8546
  // Indexes
8461
- if ( typeof rowSelector.row !== undefined ) {
8462
- opts = columnSelector;
8463
- columnSelector = null;
8464
- }
8465
- else {
8547
+ if ( rowSelector.row === undefined ) {
8548
+ // Selector options in first parameter
8466
8549
  opts = rowSelector;
8467
8550
  rowSelector = null;
8468
8551
  }
8552
+ else {
8553
+ // Cell index objects in first parameter
8554
+ opts = columnSelector;
8555
+ columnSelector = null;
8556
+ }
8469
8557
  }
8470
8558
  if ( $.isPlainObject( columnSelector ) ) {
8471
8559
  opts = columnSelector;
@@ -8826,7 +8914,10 @@
8826
8914
  var is = false;
8827
8915
 
8828
8916
  $.each( DataTable.settings, function (i, o) {
8829
- if ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) {
8917
+ var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
8918
+ var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
8919
+
8920
+ if ( o.nTable === t || head === t || foot === t ) {
8830
8921
  is = true;
8831
8922
  }
8832
8923
  } );
@@ -8853,11 +8944,22 @@
8853
8944
  */
8854
8945
  DataTable.tables = DataTable.fnTables = function ( visible )
8855
8946
  {
8856
- return $.map( DataTable.settings, function (o) {
8947
+ var api = false;
8948
+
8949
+ if ( $.isPlainObject( visible ) ) {
8950
+ api = visible.api;
8951
+ visible = visible.visible;
8952
+ }
8953
+
8954
+ var a = $.map( DataTable.settings, function (o) {
8857
8955
  if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8858
8956
  return o.nTable;
8859
8957
  }
8860
8958
  } );
8959
+
8960
+ return api ?
8961
+ new _Api( a ) :
8962
+ a;
8861
8963
  };
8862
8964
 
8863
8965
 
@@ -8954,6 +9056,12 @@
8954
9056
  } );
8955
9057
 
8956
9058
 
9059
+ _api_register( 'init()', function () {
9060
+ var ctx = this.context;
9061
+ return ctx.length ? ctx[0].oInit : null;
9062
+ } );
9063
+
9064
+
8957
9065
  _api_register( 'data()', function () {
8958
9066
  return this.iterator( 'table', function ( settings ) {
8959
9067
  return _pluck( settings.aoData, '_aData' );
@@ -9006,10 +9114,6 @@
9006
9114
  jqTable.append( tfoot );
9007
9115
  }
9008
9116
 
9009
- // Remove the DataTables generated nodes, events and classes
9010
- jqTable.detach();
9011
- jqWrapper.detach();
9012
-
9013
9117
  settings.aaSorting = [];
9014
9118
  settings.aaSortingFixed = [];
9015
9119
  _fnSortingClasses( settings );
@@ -9029,30 +9133,36 @@
9029
9133
  } );
9030
9134
  }
9031
9135
 
9032
- if ( ! remove && orig ) {
9033
- // insertBefore acts like appendChild if !arg[1]
9034
- orig.insertBefore( table, settings.nTableReinsertBefore );
9035
- }
9036
-
9037
9136
  // Add the TR elements back into the table in their original order
9038
9137
  jqTbody.children().detach();
9039
9138
  jqTbody.append( rows );
9040
9139
 
9041
- // Restore the width of the original table - was read from the style property,
9042
- // so we can restore directly to that
9043
- jqTable
9044
- .css( 'width', settings.sDestroyWidth )
9045
- .removeClass( classes.sTable );
9140
+ // Remove the DataTables generated nodes, events and classes
9141
+ var removedMethod = remove ? 'remove' : 'detach';
9142
+ jqTable[ removedMethod ]();
9143
+ jqWrapper[ removedMethod ]();
9046
9144
 
9047
- // If the were originally stripe classes - then we add them back here.
9048
- // Note this is not fool proof (for example if not all rows had stripe
9049
- // classes - but it's a good effort without getting carried away
9050
- ien = settings.asDestroyStripes.length;
9145
+ // If we need to reattach the table to the document
9146
+ if ( ! remove && orig ) {
9147
+ // insertBefore acts like appendChild if !arg[1]
9148
+ orig.insertBefore( table, settings.nTableReinsertBefore );
9051
9149
 
9052
- if ( ien ) {
9053
- jqTbody.children().each( function (i) {
9054
- $(this).addClass( settings.asDestroyStripes[i % ien] );
9055
- } );
9150
+ // Restore the width of the original table - was read from the style property,
9151
+ // so we can restore directly to that
9152
+ jqTable
9153
+ .css( 'width', settings.sDestroyWidth )
9154
+ .removeClass( classes.sTable );
9155
+
9156
+ // If the were originally stripe classes - then we add them back here.
9157
+ // Note this is not fool proof (for example if not all rows had stripe
9158
+ // classes - but it's a good effort without getting carried away
9159
+ ien = settings.asDestroyStripes.length;
9160
+
9161
+ if ( ien ) {
9162
+ jqTbody.children().each( function (i) {
9163
+ $(this).addClass( settings.asDestroyStripes[i % ien] );
9164
+ } );
9165
+ }
9056
9166
  }
9057
9167
 
9058
9168
  /* Remove the settings object from the settings array */
@@ -9063,6 +9173,48 @@
9063
9173
  } );
9064
9174
  } );
9065
9175
 
9176
+
9177
+ // Add the `every()` method for rows, columns and cells in a compact form
9178
+ $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9179
+ _api_register( type+'s().every()', function ( fn ) {
9180
+ return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9181
+ // Rows and columns:
9182
+ // arg1 - index
9183
+ // arg2 - table counter
9184
+ // arg3 - loop counter
9185
+ // arg4 - undefined
9186
+ // Cells:
9187
+ // arg1 - row index
9188
+ // arg2 - column index
9189
+ // arg3 - table counter
9190
+ // arg4 - loop counter
9191
+ fn.call(
9192
+ new _Api( settings )[ type ]( arg1, type==='cell' ? arg2 : undefined ),
9193
+ arg1, arg2, arg3, arg4
9194
+ );
9195
+ } );
9196
+ } );
9197
+ } );
9198
+
9199
+
9200
+ // i18n method for extensions to be able to use the language object from the
9201
+ // DataTable
9202
+ _api_register( 'i18n()', function ( token, def, plural ) {
9203
+ var ctx = this.context[0];
9204
+ var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9205
+
9206
+ if ( resolved === undefined ) {
9207
+ resolved = def;
9208
+ }
9209
+
9210
+ if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9211
+ resolved = resolved[ plural ] !== undefined ?
9212
+ resolved[ plural ] :
9213
+ resolved._;
9214
+ }
9215
+
9216
+ return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9217
+ } );
9066
9218
 
9067
9219
  /**
9068
9220
  * Version string for plug-ins to check compatibility. Allowed format is
@@ -9072,7 +9224,7 @@
9072
9224
  * @type string
9073
9225
  * @default Version number
9074
9226
  */
9075
- DataTable.version = "1.10.4";
9227
+ DataTable.version = "1.10.8";
9076
9228
 
9077
9229
  /**
9078
9230
  * Private data store, containing all of the settings objects that are
@@ -9224,7 +9376,16 @@
9224
9376
  * @default null
9225
9377
  * @private
9226
9378
  */
9227
- "src": null
9379
+ "src": null,
9380
+
9381
+ /**
9382
+ * Index in the aoData array. This saves an indexOf lookup when we have the
9383
+ * object, but want to know the index
9384
+ * @type integer
9385
+ * @default -1
9386
+ * @private
9387
+ */
9388
+ "idx": -1
9228
9389
  };
9229
9390
 
9230
9391
 
@@ -11665,7 +11826,18 @@
11665
11826
  * @name DataTable.defaults.renderer
11666
11827
  *
11667
11828
  */
11668
- "renderer": null
11829
+ "renderer": null,
11830
+
11831
+
11832
+ /**
11833
+ * Set the data property name that DataTables should use to get a row's id
11834
+ * to set as the `id` property in the node.
11835
+ * @type string
11836
+ * @default DT_RowId
11837
+ *
11838
+ * @name DataTable.defaults.rowId
11839
+ */
11840
+ "rowId": "DT_RowId"
11669
11841
  };
11670
11842
 
11671
11843
  _fnHungarianMap( DataTable.defaults );
@@ -12764,7 +12936,14 @@
12764
12936
  * @type boolean
12765
12937
  * @default false
12766
12938
  */
12767
- "bScrollbarLeft": false
12939
+ "bScrollbarLeft": false,
12940
+
12941
+ /**
12942
+ * Flag for if `getBoundingClientRect` is fully supported or not
12943
+ * @type boolean
12944
+ * @default false
12945
+ */
12946
+ "bBounding": false
12768
12947
  },
12769
12948
 
12770
12949
 
@@ -12809,6 +12988,13 @@
12809
12988
  */
12810
12989
  "aiDisplayMaster": [],
12811
12990
 
12991
+ /**
12992
+ * Map of row ids to data indexes
12993
+ * @type object
12994
+ * @default {}
12995
+ */
12996
+ "aIds": {},
12997
+
12812
12998
  /**
12813
12999
  * Store information about each column that is in use
12814
13000
  * @type array
@@ -13417,7 +13603,21 @@
13417
13603
  * @type object
13418
13604
  * @default {}
13419
13605
  */
13420
- "oPlugins": {}
13606
+ "oPlugins": {},
13607
+
13608
+ /**
13609
+ * Function used to get a row's id from the row's data
13610
+ * @type function
13611
+ * @default null
13612
+ */
13613
+ "rowIdFn": null,
13614
+
13615
+ /**
13616
+ * Data location where to store a row's id
13617
+ * @type string
13618
+ * @default null
13619
+ */
13620
+ "rowId": null
13421
13621
  };
13422
13622
 
13423
13623
  /**
@@ -13446,6 +13646,17 @@
13446
13646
  * @namespace
13447
13647
  */
13448
13648
  DataTable.ext = _ext = {
13649
+ /**
13650
+ * Buttons. For use with the Buttons extension for DataTables. This is
13651
+ * defined here so other extensions can define buttons regardless of load
13652
+ * order. It is _not_ used by DataTables core.
13653
+ *
13654
+ * @type object
13655
+ * @default {}
13656
+ */
13657
+ buttons: {},
13658
+
13659
+
13449
13660
  /**
13450
13661
  * Element class names
13451
13662
  *
@@ -13458,10 +13669,10 @@
13458
13669
  /**
13459
13670
  * Error reporting.
13460
13671
  *
13461
- * How should DataTables report an error. Can take the value 'alert' or
13462
- * 'throw'
13672
+ * How should DataTables report an error. Can take the value 'alert',
13673
+ * 'throw', 'none' or a function.
13463
13674
  *
13464
- * @type string
13675
+ * @type string|function
13465
13676
  * @default alert
13466
13677
  */
13467
13678
  errMode: "alert",
@@ -13568,6 +13779,37 @@
13568
13779
  search: [],
13569
13780
 
13570
13781
 
13782
+ /**
13783
+ * Selector extensions
13784
+ *
13785
+ * The `selector` option can be used to extend the options available for the
13786
+ * selector modifier options (`selector-modifier` object data type) that
13787
+ * each of the three built in selector types offer (row, column and cell +
13788
+ * their plural counterparts). For example the Select extension uses this
13789
+ * mechanism to provide an option to select only rows, columns and cells
13790
+ * that have been marked as selected by the end user (`{selected: true}`),
13791
+ * which can be used in conjunction with the existing built in selector
13792
+ * options.
13793
+ *
13794
+ * Each property is an array to which functions can be pushed. The functions
13795
+ * take three attributes:
13796
+ *
13797
+ * * Settings object for the host table
13798
+ * * Options object (`selector-modifier` object type)
13799
+ * * Array of selected item indexes
13800
+ *
13801
+ * The return is an array of the resulting item indexes after the custom
13802
+ * selector has been applied.
13803
+ *
13804
+ * @type object
13805
+ */
13806
+ selector: {
13807
+ cell: [],
13808
+ column: [],
13809
+ row: []
13810
+ },
13811
+
13812
+
13571
13813
  /**
13572
13814
  * Internal functions, exposed for used in plug-ins.
13573
13815
  *
@@ -14061,7 +14303,7 @@
14061
14303
  numbers.splice( 0, 0, 0 );
14062
14304
  }
14063
14305
  else {
14064
- numbers = _range( page-1, page+2 );
14306
+ numbers = _range( page-half+2, page+half-1 );
14065
14307
  numbers.push( 'ellipsis' );
14066
14308
  numbers.push( pages-1 );
14067
14309
  numbers.splice( 0, 0, 'ellipsis' );
@@ -14082,6 +14324,10 @@
14082
14324
  return [ 'first', 'previous', 'next', 'last' ];
14083
14325
  },
14084
14326
 
14327
+ numbers: function ( page, pages ) {
14328
+ return [ _numbers(page, pages) ];
14329
+ },
14330
+
14085
14331
  simple_numbers: function ( page, pages ) {
14086
14332
  return [ 'previous', _numbers(page, pages), 'next' ];
14087
14333
  },
@@ -14092,6 +14338,8 @@
14092
14338
 
14093
14339
  // For testing and plug-ins to use
14094
14340
  _numbers: _numbers,
14341
+
14342
+ // Number of number buttons (including ellipsis) to show. _Must be odd!_
14095
14343
  numbers_length: 7
14096
14344
  } );
14097
14345
 
@@ -14118,12 +14366,12 @@
14118
14366
  attach( inner, button );
14119
14367
  }
14120
14368
  else {
14121
- btnDisplay = '';
14369
+ btnDisplay = null;
14122
14370
  btnClass = '';
14123
14371
 
14124
14372
  switch ( button ) {
14125
14373
  case 'ellipsis':
14126
- container.append('<span>&hellip;</span>');
14374
+ container.append('<span class="ellipsis">&#x2026;</span>');
14127
14375
  break;
14128
14376
 
14129
14377
  case 'first':
@@ -14157,7 +14405,7 @@
14157
14405
  break;
14158
14406
  }
14159
14407
 
14160
- if ( btnDisplay ) {
14408
+ if ( btnDisplay !== null ) {
14161
14409
  node = $('<a>', {
14162
14410
  'class': classes.sPageButton+' '+btnClass,
14163
14411
  'aria-controls': settings.sTableId,
@@ -14183,20 +14431,22 @@
14183
14431
  // IE9 throws an 'unknown error' if document.activeElement is used
14184
14432
  // inside an iframe or frame. Try / catch the error. Not good for
14185
14433
  // accessibility, but neither are frames.
14434
+ var activeEl;
14435
+
14186
14436
  try {
14187
14437
  // Because this approach is destroying and recreating the paging
14188
14438
  // elements, focus is lost on the select button which is bad for
14189
14439
  // accessibility. So we want to restore focus once the draw has
14190
14440
  // completed
14191
- var activeEl = $(document.activeElement).data('dt-idx');
14441
+ activeEl = $(host).find(document.activeElement).data('dt-idx');
14442
+ }
14443
+ catch (e) {}
14192
14444
 
14193
- attach( $(host).empty(), buttons );
14445
+ attach( $(host).empty(), buttons );
14194
14446
 
14195
- if ( activeEl !== null ) {
14196
- $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14197
- }
14447
+ if ( activeEl ) {
14448
+ $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14198
14449
  }
14199
- catch (e) {}
14200
14450
  }
14201
14451
  }
14202
14452
  } );
@@ -14486,11 +14736,12 @@
14486
14736
  *
14487
14737
  * * `number` - Will format numeric data (defined by `columns.data`) for
14488
14738
  * display, retaining the original unformatted data for sorting and filtering.
14489
- * It takes 4 parameters:
14739
+ * It takes 5 parameters:
14490
14740
  * * `string` - Thousands grouping separator
14491
14741
  * * `string` - Decimal point indicator
14492
14742
  * * `integer` - Number of decimal points to show
14493
14743
  * * `string` (optional) - Prefix.
14744
+ * * `string` (optional) - Postfix (/suffix).
14494
14745
  *
14495
14746
  * @example
14496
14747
  * // Column definition using the number renderer
@@ -14502,9 +14753,13 @@
14502
14753
  * @namespace
14503
14754
  */
14504
14755
  DataTable.render = {
14505
- number: function ( thousands, decimal, precision, prefix ) {
14756
+ number: function ( thousands, decimal, precision, prefix, postfix ) {
14506
14757
  return {
14507
14758
  display: function ( d ) {
14759
+ if ( typeof d !== 'number' && typeof d !== 'string' ) {
14760
+ return d;
14761
+ }
14762
+
14508
14763
  var negative = d < 0 ? '-' : '';
14509
14764
  d = Math.abs( parseFloat( d ) );
14510
14765
 
@@ -14517,7 +14772,8 @@
14517
14772
  intPart.toString().replace(
14518
14773
  /\B(?=(\d{3})+(?!\d))/g, thousands
14519
14774
  ) +
14520
- floatPart;
14775
+ floatPart +
14776
+ (postfix||'');
14521
14777
  }
14522
14778
  };
14523
14779
  }
@@ -14621,7 +14877,6 @@
14621
14877
  _fnCalculateColumnWidths: _fnCalculateColumnWidths,
14622
14878
  _fnThrottle: _fnThrottle,
14623
14879
  _fnConvertToWidth: _fnConvertToWidth,
14624
- _fnScrollingWidthAdjust: _fnScrollingWidthAdjust,
14625
14880
  _fnGetWidestNode: _fnGetWidestNode,
14626
14881
  _fnGetMaxLenString: _fnGetMaxLenString,
14627
14882
  _fnStringToCss: _fnStringToCss,