jquery-datatables-rails 3.3.0 → 3.4.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 (24) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/dataTables/bootstrap/3/jquery.dataTables.bootstrap.js +64 -29
  3. data/app/assets/javascripts/dataTables/extras/dataTables.autoFill.js +806 -648
  4. data/app/assets/javascripts/dataTables/extras/dataTables.buttons.js +1607 -0
  5. data/app/assets/javascripts/dataTables/extras/dataTables.colReorder.js +220 -267
  6. data/app/assets/javascripts/dataTables/extras/dataTables.fixedColumns.js +164 -69
  7. data/app/assets/javascripts/dataTables/extras/dataTables.fixedHeader.js +469 -870
  8. data/app/assets/javascripts/dataTables/extras/dataTables.keyTable.js +636 -972
  9. data/app/assets/javascripts/dataTables/extras/dataTables.responsive.js +472 -187
  10. data/app/assets/javascripts/dataTables/extras/dataTables.rowReorder.js +619 -0
  11. data/app/assets/javascripts/dataTables/extras/dataTables.scroller.js +146 -111
  12. data/app/assets/javascripts/dataTables/extras/dataTables.select.js +1038 -0
  13. data/app/assets/javascripts/dataTables/jquery.dataTables.api.fnGetColumnData.js +0 -0
  14. data/app/assets/javascripts/dataTables/jquery.dataTables.api.fnReloadAjax.js +0 -0
  15. data/app/assets/javascripts/dataTables/jquery.dataTables.foundation.js +37 -61
  16. data/app/assets/javascripts/dataTables/jquery.dataTables.js +720 -387
  17. data/app/assets/javascripts/dataTables/jquery.dataTables.sorting.ipAddress.js +44 -0
  18. data/app/assets/javascripts/dataTables/jquery.dataTables.sorting.numbersHtml.js +0 -0
  19. data/app/assets/javascripts/dataTables/jquery.dataTables.typeDetection.numbersHtml.js +0 -0
  20. data/app/assets/stylesheets/dataTables/jquery.dataTables.scss +34 -66
  21. data/app/assets/stylesheets/dataTables/src/demo_table.css +1 -1
  22. data/app/assets/stylesheets/dataTables/src/demo_table_jui.css.scss +4 -4
  23. data/lib/jquery/datatables/rails/version.rb +1 -1
  24. metadata +24 -19
@@ -1,5 +1,5 @@
1
1
  /*! DataTables Foundation integration
2
- * ©2011-2014 SpryMedia Ltd - datatables.net/license
2
+ * ©2011-2015 SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
5
5
  /**
@@ -10,14 +10,39 @@
10
10
  * controls using Foundation. See http://datatables.net/manual/styling/foundation
11
11
  * for further information.
12
12
  */
13
- (function(window, document, undefined){
13
+ (function( factory ){
14
+ if ( typeof define === 'function' && define.amd ) {
15
+ // AMD
16
+ define( ['jquery', 'datatables.net'], function ( $ ) {
17
+ return factory( $, window, document );
18
+ } );
19
+ }
20
+ else if ( typeof exports === 'object' ) {
21
+ // CommonJS
22
+ module.exports = function (root, $) {
23
+ if ( ! root ) {
24
+ root = window;
25
+ }
26
+
27
+ if ( ! $ || ! $.fn.dataTable ) {
28
+ $ = require('datatables.net')(root, $).$;
29
+ }
14
30
 
15
- var factory = function( $, DataTable ) {
16
- "use strict";
31
+ return factory( $, root, root.document );
32
+ };
33
+ }
34
+ else {
35
+ // Browser
36
+ factory( jQuery, window, document );
37
+ }
38
+ }(function( $, window, document, undefined ) {
39
+ 'use strict';
40
+ var DataTable = $.fn.dataTable;
17
41
 
18
42
 
19
43
  $.extend( DataTable.ext.classes, {
20
- sWrapper: "dataTables_wrapper dt-foundation"
44
+ sWrapper: "dataTables_wrapper dt-foundation",
45
+ sProcessing: "dataTables_processing panel"
21
46
  } );
22
47
 
23
48
 
@@ -36,14 +61,15 @@ DataTable.ext.renderer.pageButton.foundation = function ( settings, host, idx, b
36
61
  var api = new DataTable.Api( settings );
37
62
  var classes = settings.oClasses;
38
63
  var lang = settings.oLanguage.oPaginate;
64
+ var aria = settings.oLanguage.oAria.paginate || {};
39
65
  var btnDisplay, btnClass;
40
66
 
41
67
  var attach = function( container, buttons ) {
42
68
  var i, ien, node, button;
43
69
  var clickHandler = function ( e ) {
44
70
  e.preventDefault();
45
- if ( e.data.action !== 'ellipsis' ) {
46
- api.page( e.data.action ).draw( false );
71
+ if ( !$(e.currentTarget).hasClass('unavailable') && api.page() != e.data.action ) {
72
+ api.page( e.data.action ).draw( 'page' );
47
73
  }
48
74
  };
49
75
 
@@ -59,7 +85,7 @@ DataTable.ext.renderer.pageButton.foundation = function ( settings, host, idx, b
59
85
 
60
86
  switch ( button ) {
61
87
  case 'ellipsis':
62
- btnDisplay = '…';
88
+ btnDisplay = '…';
63
89
  btnClass = 'unavailable';
64
90
  break;
65
91
 
@@ -98,6 +124,7 @@ DataTable.ext.renderer.pageButton.foundation = function ( settings, host, idx, b
98
124
  node = $('<li>', {
99
125
  'class': classes.sPageButton+' '+btnClass,
100
126
  'aria-controls': settings.sTableId,
127
+ 'aria-label': aria[ button ],
101
128
  'tabindex': settings.iTabIndex,
102
129
  'id': idx === 0 && typeof button === 'string' ?
103
130
  settings.sTableId +'_'+ button :
@@ -125,56 +152,5 @@ DataTable.ext.renderer.pageButton.foundation = function ( settings, host, idx, b
125
152
  };
126
153
 
127
154
 
128
- /*
129
- * TableTools Foundation compatibility
130
- * Required TableTools 2.1+
131
- */
132
- if ( DataTable.TableTools ) {
133
- // Set the classes that TableTools uses to something suitable for Foundation
134
- $.extend( true, DataTable.TableTools.classes, {
135
- "container": "DTTT button-group",
136
- "buttons": {
137
- "normal": "button small",
138
- "disabled": "disabled"
139
- },
140
- "collection": {
141
- "container": "DTTT_dropdown dropdown-menu",
142
- "buttons": {
143
- "normal": "",
144
- "disabled": "disabled"
145
- }
146
- },
147
- "select": {
148
- "row": "active"
149
- }
150
- } );
151
-
152
- // Have the collection use a bootstrap compatible dropdown
153
- $.extend( true, DataTable.TableTools.DEFAULTS.oTags, {
154
- "collection": {
155
- "container": "ul",
156
- "button": "li",
157
- "liner": "a"
158
- }
159
- } );
160
- }
161
-
162
- }; // /factory
163
-
164
-
165
- // Define as an AMD module if possible
166
- if ( typeof define === 'function' && define.amd ) {
167
- define( ['jquery', 'datatables'], factory );
168
- }
169
- else if ( typeof exports === 'object' ) {
170
- // Node/CommonJS
171
- factory( require('jquery'), require('datatables') );
172
- }
173
- else if ( jQuery ) {
174
- // Otherwise simply initialise as normal, stopping multiple evaluation
175
- factory( jQuery, jQuery.fn.dataTable );
176
- }
177
-
178
-
179
- })(window, document);
180
-
155
+ return DataTable;
156
+ }));
@@ -1,15 +1,15 @@
1
- /*! DataTables 1.10.6
2
- * ©2008-2014 SpryMedia Ltd - datatables.net/license
1
+ /*! DataTables 1.10.10
2
+ * ©2008-2015 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.6
8
+ * @version 1.10.10
9
9
  * @file jquery.dataTables.js
10
10
  * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
11
  * @contact www.sprymedia.co.uk/contact
12
- * @copyright Copyright 2008-2014 SpryMedia Ltd.
12
+ * @copyright Copyright 2008-2015 SpryMedia Ltd.
13
13
  *
14
14
  * This source file is free software, available under the following license:
15
15
  * MIT license - http://datatables.net/license
@@ -22,28 +22,41 @@
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*/
26
-
27
- (/** @lends <global> */function( window, document, undefined ) {
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,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
28
26
 
29
27
  (function( factory ) {
30
28
  "use strict";
31
29
 
32
30
  if ( typeof define === 'function' && define.amd ) {
33
- // Define as an AMD module if possible
34
- define( 'datatables', ['jquery'], factory );
31
+ // AMD
32
+ define( ['jquery'], function ( $ ) {
33
+ return factory( $, window, document );
34
+ } );
35
35
  }
36
- else if ( typeof exports === 'object' ) {
37
- // Node/CommonJS
38
- module.exports = factory( require( 'jquery' ) );
39
- }
40
- else if ( jQuery && !jQuery.fn.dataTable ) {
41
- // Define using browser globals otherwise
42
- // Prevent multiple instantiations if the script is loaded twice
43
- factory( jQuery );
36
+ else if ( typeof exports === 'object' ) {
37
+ // CommonJS
38
+ module.exports = function (root, $) {
39
+ if ( ! root ) {
40
+ // CommonJS environments without a window global must pass a
41
+ // root. This will give an error otherwise
42
+ root = window;
43
+ }
44
+
45
+ if ( ! $ ) {
46
+ $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
47
+ require('jquery') :
48
+ require('jquery')( root );
49
+ }
50
+
51
+ return factory( $, root, root.document );
52
+ };
53
+ }
54
+ else {
55
+ // Browser
56
+ factory( jQuery, window, document );
44
57
  }
45
58
  }
46
- (/** @lends <global> */function( $ ) {
59
+ (function( $, window, document, undefined ) {
47
60
  "use strict";
48
61
 
49
62
  /**
@@ -467,6 +480,14 @@
467
480
  _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
468
481
  _fnCompatMap( init, 'searching', 'bFilter' );
469
482
 
483
+ // Boolean initialisation of x-scrolling
484
+ if ( typeof init.sScrollX === 'boolean' ) {
485
+ init.sScrollX = init.sScrollX ? '100%' : '';
486
+ }
487
+ if ( typeof init.scrollX === 'boolean' ) {
488
+ init.scrollX = init.scrollX ? '100%' : '';
489
+ }
490
+
470
491
  // Column search objects are in an array, so it needs to be converted
471
492
  // element by element
472
493
  var searchCols = init.aoSearchCols;
@@ -509,49 +530,75 @@
509
530
  */
510
531
  function _fnBrowserDetect( settings )
511
532
  {
512
- var browser = settings.oBrowser;
533
+ // We don't need to do this every time DataTables is constructed, the values
534
+ // calculated are specific to the browser and OS configuration which we
535
+ // don't expect to change between initialisations
536
+ if ( ! DataTable.__browser ) {
537
+ var browser = {};
538
+ DataTable.__browser = browser;
539
+
540
+ // Scrolling feature / quirks detection
541
+ var n = $('<div/>')
542
+ .css( {
543
+ position: 'fixed',
544
+ top: 0,
545
+ left: 0,
546
+ height: 1,
547
+ width: 1,
548
+ overflow: 'hidden'
549
+ } )
550
+ .append(
551
+ $('<div/>')
552
+ .css( {
553
+ position: 'absolute',
554
+ top: 1,
555
+ left: 1,
556
+ width: 100,
557
+ overflow: 'scroll'
558
+ } )
559
+ .append(
560
+ $('<div/>')
561
+ .css( {
562
+ width: '100%',
563
+ height: 10
564
+ } )
565
+ )
566
+ )
567
+ .appendTo( 'body' );
513
568
 
514
- // Scrolling feature / quirks detection
515
- var n = $('<div/>')
516
- .css( {
517
- position: 'absolute',
518
- top: 0,
519
- left: 0,
520
- height: 1,
521
- width: 1,
522
- overflow: 'hidden'
523
- } )
524
- .append(
525
- $('<div/>')
526
- .css( {
527
- position: 'absolute',
528
- top: 1,
529
- left: 1,
530
- width: 100,
531
- overflow: 'scroll'
532
- } )
533
- .append(
534
- $('<div class="test"/>')
535
- .css( {
536
- width: '100%',
537
- height: 10
538
- } )
539
- )
540
- )
541
- .appendTo( 'body' );
569
+ var outer = n.children();
570
+ var inner = outer.children();
542
571
 
543
- var test = n.find('.test');
572
+ // Numbers below, in order, are:
573
+ // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
574
+ //
575
+ // IE6 XP: 100 100 100 83
576
+ // IE7 Vista: 100 100 100 83
577
+ // IE 8+ Windows: 83 83 100 83
578
+ // Evergreen Windows: 83 83 100 83
579
+ // Evergreen Mac with scrollbars: 85 85 100 85
580
+ // Evergreen Mac without scrollbars: 100 100 100 100
544
581
 
545
- // IE6/7 will oversize a width 100% element inside a scrolling element, to
546
- // include the width of the scrollbar, while other browsers ensure the inner
547
- // element is contained without forcing scrolling
548
- browser.bScrollOversize = test[0].offsetWidth === 100;
582
+ // Get scrollbar width
583
+ browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
549
584
 
550
- // In rtl text layout, some browsers (most, but not all) will place the
551
- // scrollbar on the left, rather than the right.
552
- browser.bScrollbarLeft = Math.round( test.offset().left ) !== 1;
585
+ // IE6/7 will oversize a width 100% element inside a scrolling element, to
586
+ // include the width of the scrollbar, while other browsers ensure the inner
587
+ // element is contained without forcing scrolling
588
+ browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
553
589
 
554
- n.remove();
590
+ // In rtl text layout, some browsers (most, but not all) will place the
591
+ // scrollbar on the left, rather than the right.
592
+ browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
593
+
594
+ // IE8- don't provide height and width for getBoundingClientRect
595
+ browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
596
+
597
+ n.remove();
598
+ }
599
+
600
+ $.extend( settings.oBrowser, DataTable.__browser );
601
+ settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
555
602
  }
556
603
 
557
604
 
@@ -1008,7 +1055,8 @@
1008
1055
  /* Create the object for storing information about this new row */
1009
1056
  var iRow = oSettings.aoData.length;
1010
1057
  var oData = $.extend( true, {}, DataTable.models.oRow, {
1011
- src: nTr ? 'dom' : 'data'
1058
+ src: nTr ? 'dom' : 'data',
1059
+ idx: iRow
1012
1060
  } );
1013
1061
 
1014
1062
  oData._aData = aDataIn;
@@ -1017,20 +1065,21 @@
1017
1065
  /* Create the cells */
1018
1066
  var nTd, sThisType;
1019
1067
  var columns = oSettings.aoColumns;
1068
+
1069
+ // Invalidate the column types as the new data needs to be revalidated
1020
1070
  for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
1021
1071
  {
1022
- // When working with a row, the data source object must be populated. In
1023
- // all other cases, the data source object is already populated, so we
1024
- // don't overwrite it, which might break bindings etc
1025
- if ( nTr ) {
1026
- _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
1027
- }
1028
1072
  columns[i].sType = null;
1029
1073
  }
1030
1074
 
1031
1075
  /* Add to the display array */
1032
1076
  oSettings.aiDisplayMaster.push( iRow );
1033
1077
 
1078
+ var id = oSettings.rowIdFn( aDataIn );
1079
+ if ( id !== undefined ) {
1080
+ oSettings.aIds[ id ] = oData;
1081
+ }
1082
+
1034
1083
  /* Create the DOM information, or register it if already present */
1035
1084
  if ( nTr || ! oSettings.oFeatures.bDeferRender )
1036
1085
  {
@@ -1119,7 +1168,7 @@
1119
1168
  if ( settings.iDrawError != draw && defaultContent === null ) {
1120
1169
  _fnLog( settings, 0, "Requested unknown parameter "+
1121
1170
  (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1122
- " for row "+rowIdx, 4 );
1171
+ " for row "+rowIdx+", column "+colIdx, 4 );
1123
1172
  settings.iDrawError = draw;
1124
1173
  }
1125
1174
  return defaultContent;
@@ -1174,7 +1223,7 @@
1174
1223
  */
1175
1224
  function _fnSplitObjNotation( str )
1176
1225
  {
1177
- return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) {
1226
+ return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
1178
1227
  return s.replace(/\\./g, '.');
1179
1228
  } );
1180
1229
  }
@@ -1257,8 +1306,10 @@
1257
1306
  innerSrc = a.join('.');
1258
1307
 
1259
1308
  // Traverse each entry in the array getting the properties requested
1260
- for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1261
- out.push( fetchData( data[j], type, innerSrc ) );
1309
+ if ( $.isArray( data ) ) {
1310
+ for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1311
+ out.push( fetchData( data[j], type, innerSrc ) );
1312
+ }
1262
1313
  }
1263
1314
 
1264
1315
  // If a string is given in between the array notation indicators, that
@@ -1358,11 +1409,21 @@
1358
1409
  innerSrc = b.join('.');
1359
1410
 
1360
1411
  // Traverse each entry in the array setting the properties requested
1361
- for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1412
+ if ( $.isArray( val ) )
1362
1413
  {
1363
- o = {};
1364
- setData( o, val[j], innerSrc );
1365
- data[ a[i] ].push( o );
1414
+ for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1415
+ {
1416
+ o = {};
1417
+ setData( o, val[j], innerSrc );
1418
+ data[ a[i] ].push( o );
1419
+ }
1420
+ }
1421
+ else
1422
+ {
1423
+ // We've been asked to save data to an array, but it
1424
+ // isn't array data to be saved. Best that can be done
1425
+ // is to just save the value.
1426
+ data[ a[i] ] = val;
1366
1427
  }
1367
1428
 
1368
1429
  // The inner call to setData has already traversed through the remainder
@@ -1435,6 +1496,7 @@
1435
1496
  settings.aoData.length = 0;
1436
1497
  settings.aiDisplayMaster.length = 0;
1437
1498
  settings.aiDisplay.length = 0;
1499
+ settings.aIds = {};
1438
1500
  }
1439
1501
 
1440
1502
 
@@ -1540,7 +1602,7 @@
1540
1602
  }
1541
1603
 
1542
1604
  // Update DataTables special `DT_*` attributes for the row
1543
- _fnRowAttributes( row );
1605
+ _fnRowAttributes( settings, row );
1544
1606
  }
1545
1607
  }
1546
1608
 
@@ -1572,7 +1634,11 @@
1572
1634
  objectRead = settings._rowReadObject;
1573
1635
 
1574
1636
  // Allow the data object to be passed in, or construct
1575
- d = d || objectRead ? {} : [];
1637
+ d = d !== undefined ?
1638
+ d :
1639
+ objectRead ?
1640
+ {} :
1641
+ [];
1576
1642
 
1577
1643
  var attr = function ( str, td ) {
1578
1644
  if ( typeof str === 'string' ) {
@@ -1635,12 +1701,23 @@
1635
1701
  else {
1636
1702
  // Existing row object passed in
1637
1703
  tds = row.anCells;
1638
-
1704
+
1639
1705
  for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
1640
1706
  cellProcess( tds[j] );
1641
1707
  }
1642
1708
  }
1643
1709
 
1710
+ // Read the ID from the DOM if present
1711
+ var rowNode = row.firstChild ? row : row.nTr;
1712
+
1713
+ if ( rowNode ) {
1714
+ var id = rowNode.getAttribute( 'id' );
1715
+
1716
+ if ( id ) {
1717
+ _fnSetObjectDataFn( settings.rowId )( d, id );
1718
+ }
1719
+ }
1720
+
1644
1721
  return {
1645
1722
  data: d,
1646
1723
  cells: tds
@@ -1678,7 +1755,7 @@
1678
1755
  nTr._DT_RowIndex = iRow;
1679
1756
 
1680
1757
  /* Special parameters can be given by the data source to be used on the row */
1681
- _fnRowAttributes( row );
1758
+ _fnRowAttributes( oSettings, row );
1682
1759
 
1683
1760
  /* Process each column */
1684
1761
  for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
@@ -1686,6 +1763,11 @@
1686
1763
  oCol = oSettings.aoColumns[i];
1687
1764
 
1688
1765
  nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
1766
+ nTd._DT_CellIndex = {
1767
+ row: iRow,
1768
+ column: i
1769
+ };
1770
+
1689
1771
  cells.push( nTd );
1690
1772
 
1691
1773
  // Need to create the HTML if new, or if a rendering function is defined
@@ -1730,17 +1812,20 @@
1730
1812
  /**
1731
1813
  * Add attributes to a row based on the special `DT_*` parameters in a data
1732
1814
  * source object.
1815
+ * @param {object} settings DataTables settings object
1733
1816
  * @param {object} DataTables row object for the row to be modified
1734
1817
  * @memberof DataTable#oApi
1735
1818
  */
1736
- function _fnRowAttributes( row )
1819
+ function _fnRowAttributes( settings, row )
1737
1820
  {
1738
1821
  var tr = row.nTr;
1739
1822
  var data = row._aData;
1740
1823
 
1741
1824
  if ( tr ) {
1742
- if ( data.DT_RowId ) {
1743
- tr.id = data.DT_RowId;
1825
+ var id = settings.rowIdFn( data );
1826
+
1827
+ if ( id ) {
1828
+ tr.id = id;
1744
1829
  }
1745
1830
 
1746
1831
  if ( data.DT_RowClass ) {
@@ -1805,7 +1890,7 @@
1805
1890
  }
1806
1891
  }
1807
1892
 
1808
- if ( column.sTitle != cell.html() ) {
1893
+ if ( column.sTitle != cell[0].innerHTML ) {
1809
1894
  cell.html( column.sTitle );
1810
1895
  }
1811
1896
 
@@ -2277,6 +2362,7 @@
2277
2362
 
2278
2363
  /* Built our DOM structure - replace the holding div with what we want */
2279
2364
  holding.replaceWith( insert );
2365
+ oSettings.nHolding = null;
2280
2366
  }
2281
2367
 
2282
2368
 
@@ -2435,7 +2521,7 @@
2435
2521
  var ajax = oSettings.ajax;
2436
2522
  var instance = oSettings.oInstance;
2437
2523
  var callback = function ( json ) {
2438
- _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] );
2524
+ _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
2439
2525
  fn( json );
2440
2526
  };
2441
2527
 
@@ -2462,7 +2548,7 @@
2462
2548
  "success": function (json) {
2463
2549
  var error = json.error || json.sError;
2464
2550
  if ( error ) {
2465
- oSettings.oApi._fnLog( oSettings, 0, error );
2551
+ _fnLog( oSettings, 0, error );
2466
2552
  }
2467
2553
 
2468
2554
  oSettings.json = json;
@@ -2472,13 +2558,15 @@
2472
2558
  "cache": false,
2473
2559
  "type": oSettings.sServerMethod,
2474
2560
  "error": function (xhr, error, thrown) {
2475
- var log = oSettings.oApi._fnLog;
2561
+ var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
2476
2562
 
2477
- if ( error == "parsererror" ) {
2478
- log( oSettings, 0, 'Invalid JSON response', 1 );
2479
- }
2480
- else if ( xhr.readyState === 4 ) {
2481
- log( oSettings, 0, 'Ajax error', 7 );
2563
+ if ( $.inArray( true, ret ) === -1 ) {
2564
+ if ( error == "parsererror" ) {
2565
+ _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
2566
+ }
2567
+ else if ( xhr.readyState === 4 ) {
2568
+ _fnLog( oSettings, 0, 'Ajax error', 7 );
2569
+ }
2482
2570
  }
2483
2571
 
2484
2572
  _fnProcessingDisplay( oSettings, false );
@@ -2907,7 +2995,7 @@
2907
2995
  // So the array reference doesn't break set the results into the
2908
2996
  // existing array
2909
2997
  displayRows.length = 0;
2910
- displayRows.push.apply( displayRows, rows );
2998
+ $.merge( displayRows, rows );
2911
2999
  }
2912
3000
  }
2913
3001
 
@@ -3018,7 +3106,7 @@
3018
3106
  *
3019
3107
  * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
3020
3108
  */
3021
- var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) {
3109
+ var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
3022
3110
  if ( word.charAt(0) === '"' ) {
3023
3111
  var m = word.match( /^"(.*)"$/ );
3024
3112
  word = m ? m[1] : word;
@@ -3263,6 +3351,7 @@
3263
3351
  var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3264
3352
  var columns = settings.aoColumns, column;
3265
3353
  var features = settings.oFeatures;
3354
+ var deferLoading = settings.bDeferLoading; // value modified by the draw
3266
3355
 
3267
3356
  /* Ensure that the table data is fully initialised */
3268
3357
  if ( ! settings.bInitialised ) {
@@ -3294,6 +3383,8 @@
3294
3383
  }
3295
3384
  }
3296
3385
 
3386
+ _fnCallbackFire( settings, null, 'preInit', [settings] );
3387
+
3297
3388
  // If there is default sorting required - let's do it. The sort function
3298
3389
  // will do the drawing for us. Otherwise we draw the table regardless of the
3299
3390
  // Ajax source - this allows the table to look initialised for Ajax sourcing
@@ -3302,7 +3393,7 @@
3302
3393
 
3303
3394
  // Server-side processing init complete is done by _fnAjaxUpdateDraw
3304
3395
  var dataSrc = _fnDataSource( settings );
3305
- if ( dataSrc != 'ssp' ) {
3396
+ if ( dataSrc != 'ssp' || deferLoading ) {
3306
3397
  // if there is an ajax source load the data
3307
3398
  if ( dataSrc == 'ajax' ) {
3308
3399
  _fnBuildAjax( settings, [], function(json) {
@@ -3343,12 +3434,13 @@
3343
3434
  {
3344
3435
  settings._bInitComplete = true;
3345
3436
 
3346
- // On an Ajax load we now have data and therefore want to apply the column
3347
- // sizing
3348
- if ( json ) {
3437
+ // When data was added after the initialisation (data or Ajax) we need to
3438
+ // calculate the column sizing
3439
+ if ( json || settings.oInit.aaData ) {
3349
3440
  _fnAdjustColumnSizing( settings );
3350
3441
  }
3351
3442
 
3443
+ _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
3352
3444
  _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
3353
3445
  }
3354
3446
 
@@ -3625,17 +3717,6 @@
3625
3717
  return !s ? null : _fnStringToCss( s );
3626
3718
  };
3627
3719
 
3628
- // This is fairly messy, but with x scrolling enabled, if the table has a
3629
- // width attribute, regardless of any width applied using the column width
3630
- // options, the browser will shrink or grow the table as needed to fit into
3631
- // that 100%. That would make the width options useless. So we remove it.
3632
- // This is okay, under the assumption that width:100% is applied to the
3633
- // table in CSS (it is in the default stylesheet) which will set the table
3634
- // width as appropriate (the attribute and css behave differently...)
3635
- if ( scroll.sX && table.attr('width') === '100%' ) {
3636
- table.removeAttr('width');
3637
- }
3638
-
3639
3720
  if ( ! footer.length ) {
3640
3721
  footer = null;
3641
3722
  }
@@ -3685,8 +3766,8 @@
3685
3766
  .append(
3686
3767
  $(_div, { 'class': classes.sScrollBody } )
3687
3768
  .css( {
3769
+ position: 'relative',
3688
3770
  overflow: 'auto',
3689
- height: size( scrollY ),
3690
3771
  width: size( scrollX )
3691
3772
  } )
3692
3773
  .append( table )
@@ -3733,6 +3814,11 @@
3733
3814
  } );
3734
3815
  }
3735
3816
 
3817
+ $(scrollBody).css(
3818
+ scrollY && scroll.bCollapse ? 'max-height' : 'height',
3819
+ scrollY
3820
+ );
3821
+
3736
3822
  settings.nScrollHead = scrollHead;
3737
3823
  settings.nScrollBody = scrollBody;
3738
3824
  settings.nScrollFoot = scrollFoot;
@@ -3805,6 +3891,20 @@
3805
3891
  style.height = 0;
3806
3892
  };
3807
3893
 
3894
+ // If the scrollbar visibility has changed from the last draw, we need to
3895
+ // adjust the column sizes as the table width will have changed to account
3896
+ // for the scrollbar
3897
+ var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
3898
+
3899
+ if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
3900
+ settings.scrollBarVis = scrollBarVis;
3901
+ _fnAdjustColumnSizing( settings );
3902
+ return; // adjust column sizing will call this function again
3903
+ }
3904
+ else {
3905
+ settings.scrollBarVis = scrollBarVis;
3906
+ }
3907
+
3808
3908
  /*
3809
3909
  * 1. Re-create the table inside the scrolling div
3810
3910
  */
@@ -3849,13 +3949,6 @@
3849
3949
  }, footerSrcEls );
3850
3950
  }
3851
3951
 
3852
- // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
3853
- // will end up forcing the scrollbar to appear, making our measurements wrong for when we
3854
- // then hide it (end of this function), so add the header height to the body scroller.
3855
- if ( scroll.bCollapse && scrollY !== "" ) {
3856
- divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px";
3857
- }
3858
-
3859
3952
  // Size the table as a whole
3860
3953
  sanityWidth = table.outerWidth();
3861
3954
  if ( scrollX === "" ) {
@@ -3870,32 +3963,17 @@
3870
3963
  ) {
3871
3964
  tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3872
3965
  }
3966
+
3967
+ // Recalculate the sanity width
3968
+ sanityWidth = table.outerWidth();
3873
3969
  }
3874
- else
3875
- {
3876
- // x scrolling
3877
- if ( scrollXInner !== "" ) {
3878
- // x scroll inner has been given - use it
3879
- tableStyle.width = _fnStringToCss(scrollXInner);
3880
- }
3881
- else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {
3882
- // There is y-scrolling - try to take account of the y scroll bar
3883
- tableStyle.width = _fnStringToCss( sanityWidth-barWidth );
3884
- if ( table.outerWidth() > sanityWidth-barWidth ) {
3885
- // Not possible to take account of it
3886
- tableStyle.width = _fnStringToCss( sanityWidth );
3887
- }
3888
- }
3889
- else {
3890
- // When all else fails
3891
- tableStyle.width = _fnStringToCss( sanityWidth );
3892
- }
3893
- }
3970
+ else if ( scrollXInner !== "" ) {
3971
+ // legacy x scroll inner has been given - use it
3972
+ tableStyle.width = _fnStringToCss(scrollXInner);
3894
3973
 
3895
- // Recalculate the sanity width - now that we've applied the required width,
3896
- // before it was a temporary variable. This is required because the column
3897
- // width calculation is done before this table DOM is created.
3898
- sanityWidth = table.outerWidth();
3974
+ // Recalculate the sanity width
3975
+ sanityWidth = table.outerWidth();
3976
+ }
3899
3977
 
3900
3978
  // Hidden header should have zero height, so remove padding and borders. Then
3901
3979
  // set the width based on the real headers
@@ -4003,18 +4081,6 @@
4003
4081
  }
4004
4082
  }
4005
4083
 
4006
- if ( scrollY && scroll.bCollapse ) {
4007
- divBodyStyle.height = _fnStringToCss( scrollY );
4008
-
4009
- var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?
4010
- barWidth :
4011
- 0;
4012
-
4013
- if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {
4014
- divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );
4015
- }
4016
- }
4017
-
4018
4084
  /* Finally set the width's of the header and footer tables */
4019
4085
  var iOuterWidth = table.outerWidth();
4020
4086
  divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
@@ -4106,7 +4172,9 @@
4106
4172
  tableWidthAttr = table.getAttribute('width'), // from DOM element
4107
4173
  tableContainer = table.parentNode,
4108
4174
  userInputs = false,
4109
- i, column, columnIdx, width, outerWidth;
4175
+ i, column, columnIdx, width, outerWidth,
4176
+ browser = oSettings.oBrowser,
4177
+ ie67 = browser.bScrollOversize;
4110
4178
 
4111
4179
  var styleWidth = table.style.width;
4112
4180
  if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
@@ -4129,32 +4197,43 @@
4129
4197
  * the web- browser. No custom sizes can be set in order for this to happen,
4130
4198
  * nor scrolling used
4131
4199
  */
4132
- if ( ! userInputs && ! scrollX && ! scrollY &&
4133
- columnCount == _fnVisbleColumns( oSettings ) &&
4134
- columnCount == headerCells.length
4200
+ if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
4201
+ columnCount == _fnVisbleColumns( oSettings ) &&
4202
+ columnCount == headerCells.length
4135
4203
  ) {
4136
4204
  for ( i=0 ; i<columnCount ; i++ ) {
4137
- columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );
4205
+ var colIdx = _fnVisibleToColumnIndex( oSettings, i );
4206
+
4207
+ if ( colIdx !== null ) {
4208
+ columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
4209
+ }
4138
4210
  }
4139
4211
  }
4140
4212
  else
4141
4213
  {
4142
- // Otherwise construct a single row table with the widest node in the
4143
- // data, assign any user defined widths, then insert it into the DOM and
4144
- // allow the browser to do all the hard work of calculating table widths
4214
+ // Otherwise construct a single row, worst case, table with the widest
4215
+ // node in the data, assign any user defined widths, then insert it into
4216
+ // the DOM and allow the browser to do all the hard work of calculating
4217
+ // table widths
4145
4218
  var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4146
- .empty()
4147
4219
  .css( 'visibility', 'hidden' )
4148
- .removeAttr( 'id' )
4149
- .append( $(oSettings.nTHead).clone( false ) )
4150
- .append( $(oSettings.nTFoot).clone( false ) )
4151
- .append( $('<tbody><tr/></tbody>') );
4220
+ .removeAttr( 'id' );
4221
+
4222
+ // Clean up the table body
4223
+ tmpTable.find('tbody tr').remove();
4224
+ var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
4225
+
4226
+ // Clone the table header and footer - we can't use the header / footer
4227
+ // from the cloned table, since if scrolling is active, the table's
4228
+ // real header and footer are contained in different table tags
4229
+ tmpTable.find('thead, tfoot').remove();
4230
+ tmpTable
4231
+ .append( $(oSettings.nTHead).clone() )
4232
+ .append( $(oSettings.nTFoot).clone() );
4152
4233
 
4153
4234
  // Remove any assigned widths from the footer (from scrolling)
4154
4235
  tmpTable.find('tfoot th, tfoot td').css('width', '');
4155
4236
 
4156
- var tr = tmpTable.find( 'tbody tr' );
4157
-
4158
4237
  // Apply custom sizing to the cloned header
4159
4238
  headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4160
4239
 
@@ -4164,6 +4243,19 @@
4164
4243
  headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
4165
4244
  _fnStringToCss( column.sWidthOrig ) :
4166
4245
  '';
4246
+
4247
+ // For scrollX we need to force the column width otherwise the
4248
+ // browser will collapse it. If this width is smaller than the
4249
+ // width the column requires, then it will have no effect
4250
+ if ( column.sWidthOrig && scrollX ) {
4251
+ $( headerCells[i] ).append( $('<div/>').css( {
4252
+ width: column.sWidthOrig,
4253
+ margin: 0,
4254
+ padding: 0,
4255
+ border: 0,
4256
+ height: 1
4257
+ } ) );
4258
+ }
4167
4259
  }
4168
4260
 
4169
4261
  // Find the widest cell for each column and put it into the table
@@ -4179,8 +4271,24 @@
4179
4271
  }
4180
4272
  }
4181
4273
 
4182
- // Table has been built, attach to the document so we can work with it
4183
- tmpTable.appendTo( tableContainer );
4274
+ // Table has been built, attach to the document so we can work with it.
4275
+ // A holding element is used, positioned at the top of the container
4276
+ // with minimal height, so it has no effect on if the container scrolls
4277
+ // or not. Otherwise it might trigger scrolling when it actually isn't
4278
+ // needed
4279
+ var holder = $('<div/>').css( scrollX || scrollY ?
4280
+ {
4281
+ position: 'absolute',
4282
+ top: 0,
4283
+ left: 0,
4284
+ height: 1,
4285
+ right: 0,
4286
+ overflow: 'hidden'
4287
+ } :
4288
+ {}
4289
+ )
4290
+ .append( tmpTable )
4291
+ .appendTo( tableContainer );
4184
4292
 
4185
4293
  // When scrolling (X or Y) we want to set the width of the table as
4186
4294
  // appropriate. However, when not scrolling leave the table width as it
@@ -4190,57 +4298,50 @@
4190
4298
  }
4191
4299
  else if ( scrollX ) {
4192
4300
  tmpTable.css( 'width', 'auto' );
4301
+ tmpTable.removeAttr('width');
4193
4302
 
4194
- if ( tmpTable.width() < tableContainer.offsetWidth ) {
4195
- tmpTable.width( tableContainer.offsetWidth );
4303
+ // If there is no width attribute or style, then allow the table to
4304
+ // collapse
4305
+ if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
4306
+ tmpTable.width( tableContainer.clientWidth );
4196
4307
  }
4197
4308
  }
4198
4309
  else if ( scrollY ) {
4199
- tmpTable.width( tableContainer.offsetWidth );
4310
+ tmpTable.width( tableContainer.clientWidth );
4200
4311
  }
4201
4312
  else if ( tableWidthAttr ) {
4202
4313
  tmpTable.width( tableWidthAttr );
4203
4314
  }
4204
4315
 
4205
- // Take into account the y scrollbar
4206
- _fnScrollingWidthAdjust( oSettings, tmpTable[0] );
4207
-
4208
- // Browsers need a bit of a hand when a width is assigned to any columns
4209
- // when x-scrolling as they tend to collapse the table to the min-width,
4210
- // even if we sent the column widths. So we need to keep track of what
4211
- // the table width should be by summing the user given values, and the
4212
- // automatic values
4213
- if ( scrollX )
4214
- {
4215
- var total = 0;
4216
-
4217
- for ( i=0 ; i<visibleColumns.length ; i++ ) {
4218
- column = columns[ visibleColumns[i] ];
4219
- outerWidth = $(headerCells[i]).outerWidth();
4220
-
4221
- total += column.sWidthOrig === null ?
4222
- outerWidth :
4223
- parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();
4224
- }
4316
+ // Get the width of each column in the constructed table - we need to
4317
+ // know the inner width (so it can be assigned to the other table's
4318
+ // cells) and the outer width so we can calculate the full width of the
4319
+ // table. This is safe since DataTables requires a unique cell for each
4320
+ // column, but if ever a header can span multiple columns, this will
4321
+ // need to be modified.
4322
+ var total = 0;
4323
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
4324
+ var cell = $(headerCells[i]);
4325
+ var border = cell.outerWidth() - cell.width();
4225
4326
 
4226
- tmpTable.width( _fnStringToCss( total ) );
4227
- table.style.width = _fnStringToCss( total );
4228
- }
4327
+ // Use getBounding... where possible (not IE8-) because it can give
4328
+ // sub-pixel accuracy, which we then want to round up!
4329
+ var bounding = browser.bBounding ?
4330
+ Math.ceil( headerCells[i].getBoundingClientRect().width ) :
4331
+ cell.outerWidth();
4229
4332
 
4230
- // Get the width of each column in the constructed table
4231
- for ( i=0 ; i<visibleColumns.length ; i++ ) {
4232
- column = columns[ visibleColumns[i] ];
4233
- width = $(headerCells[i]).width();
4333
+ // Total is tracked to remove any sub-pixel errors as the outerWidth
4334
+ // of the table might not equal the total given here (IE!).
4335
+ total += bounding;
4234
4336
 
4235
- if ( width ) {
4236
- column.sWidth = _fnStringToCss( width );
4237
- }
4337
+ // Width for each column to use
4338
+ columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
4238
4339
  }
4239
4340
 
4240
- table.style.width = _fnStringToCss( tmpTable.css('width') );
4341
+ table.style.width = _fnStringToCss( total );
4241
4342
 
4242
4343
  // Finished with the table - ditch it
4243
- tmpTable.remove();
4344
+ holder.remove();
4244
4345
  }
4245
4346
 
4246
4347
  // If there is a width attr, we want to attach an event listener which
@@ -4252,9 +4353,20 @@
4252
4353
  }
4253
4354
 
4254
4355
  if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4255
- $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4256
- _fnAdjustColumnSizing( oSettings );
4257
- } ) );
4356
+ var bindResize = function () {
4357
+ $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4358
+ _fnAdjustColumnSizing( oSettings );
4359
+ } ) );
4360
+ };
4361
+
4362
+ // IE6/7 will crash if we bind a resize event handler on page load.
4363
+ // To be removed in 1.11 which drops IE6/7 support
4364
+ if ( ie67 ) {
4365
+ setTimeout( bindResize, 1000 );
4366
+ }
4367
+ else {
4368
+ bindResize();
4369
+ }
4258
4370
 
4259
4371
  oSettings._reszEvt = true;
4260
4372
  }
@@ -4321,27 +4433,6 @@
4321
4433
  }
4322
4434
 
4323
4435
 
4324
- /**
4325
- * Adjust a table's width to take account of vertical scroll bar
4326
- * @param {object} oSettings dataTables settings object
4327
- * @param {node} n table node
4328
- * @memberof DataTable#oApi
4329
- */
4330
-
4331
- function _fnScrollingWidthAdjust ( settings, n )
4332
- {
4333
- var scroll = settings.oScroll;
4334
-
4335
- if ( scroll.sX || scroll.sY ) {
4336
- // When y-scrolling only, we want to remove the width of the scroll bar
4337
- // so the table + scroll bar will fit into the area available, otherwise
4338
- // we fix the table at its current size with no adjustment
4339
- var correction = ! scroll.sX ? scroll.iBarWidth : 0;
4340
- n.style.width = _fnStringToCss( $(n).outerWidth() - correction );
4341
- }
4342
- }
4343
-
4344
-
4345
4436
  /**
4346
4437
  * Get the widest node
4347
4438
  * @param {object} settings dataTables settings object
@@ -4377,6 +4468,7 @@
4377
4468
  for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4378
4469
  s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
4379
4470
  s = s.replace( __re_html_remove, '' );
4471
+ s = s.replace( /&nbsp;/g, ' ' );
4380
4472
 
4381
4473
  if ( s.length > max ) {
4382
4474
  max = s.length;
@@ -4413,40 +4505,6 @@
4413
4505
  }
4414
4506
 
4415
4507
 
4416
- /**
4417
- * Get the width of a scroll bar in this browser being used
4418
- * @returns {int} width in pixels
4419
- * @memberof DataTable#oApi
4420
- */
4421
- function _fnScrollBarWidth ()
4422
- {
4423
- // On first run a static variable is set, since this is only needed once.
4424
- // Subsequent runs will just use the previously calculated value
4425
- var width = DataTable.__scrollbarWidth;
4426
-
4427
- if ( width === undefined ) {
4428
- var sizer = $('<p/>').css( {
4429
- position: 'absolute',
4430
- top: 0,
4431
- left: 0,
4432
- width: '100%',
4433
- height: 150,
4434
- padding: 0,
4435
- overflow: 'scroll',
4436
- visibility: 'hidden'
4437
- } )
4438
- .appendTo('body');
4439
-
4440
- width = sizer[0].offsetWidth - sizer[0].clientWidth;
4441
- DataTable.__scrollbarWidth = width;
4442
-
4443
- sizer.remove();
4444
- }
4445
-
4446
- return width;
4447
- }
4448
-
4449
-
4450
4508
 
4451
4509
  function _fnSortFlatten ( settings )
4452
4510
  {
@@ -4466,7 +4524,7 @@
4466
4524
  }
4467
4525
  else {
4468
4526
  // 2D array
4469
- nestedSort.push.apply( nestedSort, a );
4527
+ $.merge( nestedSort, a );
4470
4528
  }
4471
4529
  };
4472
4530
 
@@ -5043,7 +5101,7 @@
5043
5101
  function _fnLog( settings, level, msg, tn )
5044
5102
  {
5045
5103
  msg = 'DataTables warning: '+
5046
- (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;
5104
+ (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
5047
5105
 
5048
5106
  if ( tn ) {
5049
5107
  msg += '. For more information about this error, please see '+
@@ -5055,7 +5113,9 @@
5055
5113
  var ext = DataTable.ext;
5056
5114
  var type = ext.sErrMode || ext.errMode;
5057
5115
 
5058
- _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
5116
+ if ( settings ) {
5117
+ _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
5118
+ }
5059
5119
 
5060
5120
  if ( type == 'alert' ) {
5061
5121
  alert( msg );
@@ -5208,13 +5268,13 @@
5208
5268
  * @param {object} settings dataTables settings object
5209
5269
  * @param {string} callbackArr Name of the array storage for the callbacks in
5210
5270
  * oSettings
5211
- * @param {string} event Name of the jQuery custom event to trigger. If null no
5212
- * trigger is fired
5271
+ * @param {string} eventName Name of the jQuery custom event to trigger. If
5272
+ * null no trigger is fired
5213
5273
  * @param {array} args Array of arguments to pass to the callback function /
5214
5274
  * trigger
5215
5275
  * @memberof DataTable#oApi
5216
5276
  */
5217
- function _fnCallbackFire( settings, callbackArr, e, args )
5277
+ function _fnCallbackFire( settings, callbackArr, eventName, args )
5218
5278
  {
5219
5279
  var ret = [];
5220
5280
 
@@ -5224,8 +5284,12 @@
5224
5284
  } );
5225
5285
  }
5226
5286
 
5227
- if ( e !== null ) {
5228
- $(settings.nTable).trigger( e+'.dt', args );
5287
+ if ( eventName !== null ) {
5288
+ var e = $.Event( eventName+'.dt' );
5289
+
5290
+ $(settings.nTable).trigger( e, args );
5291
+
5292
+ ret.push( e.result );
5229
5293
  }
5230
5294
 
5231
5295
  return ret;
@@ -6226,6 +6290,7 @@
6226
6290
  "fnStateSaveCallback",
6227
6291
  "renderer",
6228
6292
  "searchDelay",
6293
+ "rowId",
6229
6294
  [ "iCookieDuration", "iStateDuration" ], // backwards compat
6230
6295
  [ "oSearch", "oPreviousSearch" ],
6231
6296
  [ "aoSearchCols", "aoPreSearchCols" ],
@@ -6253,6 +6318,11 @@
6253
6318
  _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
6254
6319
  _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
6255
6320
 
6321
+ oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
6322
+
6323
+ /* Browser support detection */
6324
+ _fnBrowserDetect( oSettings );
6325
+
6256
6326
  var oClasses = oSettings.oClasses;
6257
6327
 
6258
6328
  // @todo Remove in 1.11
@@ -6282,14 +6352,6 @@
6282
6352
  }
6283
6353
  $this.addClass( oClasses.sTable );
6284
6354
 
6285
- /* Calculate the scroll bar width and cache it for use later on */
6286
- if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6287
- {
6288
- oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6289
- }
6290
- if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling
6291
- oSettings.oScroll.sX = '100%';
6292
- }
6293
6355
 
6294
6356
  if ( oSettings.iInitDisplayStart === undefined )
6295
6357
  {
@@ -6400,7 +6462,7 @@
6400
6462
  return cell.getAttribute( 'data-'+name ) !== null ? name : null;
6401
6463
  };
6402
6464
 
6403
- $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
6465
+ $( rowOne[0] ).children('th, td').each( function (i, cell) {
6404
6466
  var col = oSettings.aoColumns[i];
6405
6467
 
6406
6468
  if ( col.mData === i ) {
@@ -6482,9 +6544,6 @@
6482
6544
  * Cache the header, body and footer as required, creating them if needed
6483
6545
  */
6484
6546
 
6485
- /* Browser support detection */
6486
- _fnBrowserDetect( oSettings );
6487
-
6488
6547
  // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6489
6548
  var captions = $this.children('caption').each( function () {
6490
6549
  this._captionSide = $this.css('caption-side');
@@ -6722,17 +6781,15 @@
6722
6781
  */
6723
6782
  _Api = function ( context, data )
6724
6783
  {
6725
- if ( ! this instanceof _Api ) {
6726
- throw 'DT API must be constructed as a new object';
6727
- // or should it do the 'new' for the caller?
6728
- // return new _Api.apply( this, arguments );
6784
+ if ( ! (this instanceof _Api) ) {
6785
+ return new _Api( context, data );
6729
6786
  }
6730
6787
 
6731
6788
  var settings = [];
6732
6789
  var ctxSettings = function ( o ) {
6733
6790
  var a = _toSettings( o );
6734
6791
  if ( a ) {
6735
- settings.push.apply( settings, a );
6792
+ settings = settings.concat( a );
6736
6793
  }
6737
6794
  };
6738
6795
 
@@ -6750,7 +6807,7 @@
6750
6807
 
6751
6808
  // Initial data
6752
6809
  if ( data ) {
6753
- this.push.apply( this, data.toArray ? data.toArray() : data );
6810
+ $.merge( this, data );
6754
6811
  }
6755
6812
 
6756
6813
  // selector
@@ -6765,25 +6822,27 @@
6765
6822
 
6766
6823
  DataTable.Api = _Api;
6767
6824
 
6768
- _Api.prototype = /** @lends DataTables.Api */{
6769
- /**
6770
- * Return a new Api instance, comprised of the data held in the current
6771
- * instance, join with the other array(s) and/or value(s).
6772
- *
6773
- * An alias for `Array.prototype.concat`.
6774
- *
6775
- * @type method
6776
- * @param {*} value1 Arrays and/or values to concatenate.
6777
- * @param {*} [...] Additional arrays and/or values to concatenate.
6778
- * @returns {DataTables.Api} New API instance, comprising of the combined
6779
- * array.
6780
- */
6825
+ // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6826
+ // isPlainObject.
6827
+ $.extend( _Api.prototype, {
6828
+ any: function ()
6829
+ {
6830
+ return this.count() !== 0;
6831
+ },
6832
+
6833
+
6781
6834
  concat: __arrayProto.concat,
6782
6835
 
6783
6836
 
6784
6837
  context: [], // array of table settings objects
6785
6838
 
6786
6839
 
6840
+ count: function ()
6841
+ {
6842
+ return this.flatten().length;
6843
+ },
6844
+
6845
+
6787
6846
  each: function ( fn )
6788
6847
  {
6789
6848
  for ( var i=0, ien=this.length ; i<ien; i++ ) {
@@ -6844,7 +6903,6 @@
6844
6903
  return -1;
6845
6904
  },
6846
6905
 
6847
- // Note that `alwaysNew` is internal - use iteratorNew externally
6848
6906
  iterator: function ( flatten, type, fn, alwaysNew ) {
6849
6907
  var
6850
6908
  a = [], ret,
@@ -7012,7 +7070,7 @@
7012
7070
 
7013
7071
 
7014
7072
  unshift: __arrayProto.unshift
7015
- };
7073
+ } );
7016
7074
 
7017
7075
 
7018
7076
  _Api.extend = function ( scope, obj, ext )
@@ -7267,15 +7325,21 @@
7267
7325
 
7268
7326
  /**
7269
7327
  * Redraw the tables in the current context.
7270
- *
7271
- * @param {boolean} [reset=true] Reset (default) or hold the current paging
7272
- * position. A full re-sort and re-filter is performed when this method is
7273
- * called, which is why the pagination reset is the default action.
7274
- * @returns {DataTables.Api} this
7275
7328
  */
7276
- _api_register( 'draw()', function ( resetPaging ) {
7329
+ _api_register( 'draw()', function ( paging ) {
7277
7330
  return this.iterator( 'table', function ( settings ) {
7278
- _fnReDraw( settings, resetPaging===false );
7331
+ if ( paging === 'page' ) {
7332
+ _fnDraw( settings );
7333
+ }
7334
+ else {
7335
+ if ( typeof paging === 'string' ) {
7336
+ paging = paging === 'full-hold' ?
7337
+ false :
7338
+ true;
7339
+ }
7340
+
7341
+ _fnReDraw( settings, paging===false );
7342
+ }
7279
7343
  } );
7280
7344
  } );
7281
7345
 
@@ -7338,7 +7402,7 @@
7338
7402
  var
7339
7403
  settings = this.context[0],
7340
7404
  start = settings._iDisplayStart,
7341
- len = settings._iDisplayLength,
7405
+ len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7342
7406
  visRecords = settings.fnRecordsDisplay(),
7343
7407
  all = len === -1;
7344
7408
 
@@ -7349,7 +7413,8 @@
7349
7413
  "end": settings.fnDisplayEnd(),
7350
7414
  "length": len,
7351
7415
  "recordsTotal": settings.fnRecordsTotal(),
7352
- "recordsDisplay": visRecords
7416
+ "recordsDisplay": visRecords,
7417
+ "serverSide": _fnDataSource( settings ) === 'ssp'
7353
7418
  };
7354
7419
  } );
7355
7420
 
@@ -7397,9 +7462,15 @@
7397
7462
  _fnReDraw( settings, holdPosition );
7398
7463
  }
7399
7464
  else {
7400
- // Trigger xhr
7401
7465
  _fnProcessingDisplay( settings, true );
7402
7466
 
7467
+ // Cancel an existing request
7468
+ var xhr = settings.jqXHR;
7469
+ if ( xhr && xhr.readyState !== 4 ) {
7470
+ xhr.abort();
7471
+ }
7472
+
7473
+ // Trigger xhr
7403
7474
  _fnBuildAjax( settings, [], function( json ) {
7404
7475
  _fnClearTable( settings );
7405
7476
 
@@ -7527,7 +7598,7 @@
7527
7598
 
7528
7599
 
7529
7600
 
7530
- var _selector_run = function ( selector, select )
7601
+ var _selector_run = function ( type, selector, selectFn, settings, opts )
7531
7602
  {
7532
7603
  var
7533
7604
  out = [], res,
@@ -7546,15 +7617,23 @@
7546
7617
  [ selector[i] ];
7547
7618
 
7548
7619
  for ( j=0, jen=a.length ; j<jen ; j++ ) {
7549
- res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7620
+ res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7550
7621
 
7551
7622
  if ( res && res.length ) {
7552
- out.push.apply( out, res );
7623
+ out = out.concat( res );
7553
7624
  }
7554
7625
  }
7555
7626
  }
7556
7627
 
7557
- return out;
7628
+ // selector extensions
7629
+ var ext = _ext.selector[ type ];
7630
+ if ( ext.length ) {
7631
+ for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7632
+ out = ext[i]( settings, opts, out );
7633
+ }
7634
+ }
7635
+
7636
+ return _unique( out );
7558
7637
  };
7559
7638
 
7560
7639
 
@@ -7566,15 +7645,15 @@
7566
7645
 
7567
7646
  // Backwards compatibility for 1.9- which used the terminology filter rather
7568
7647
  // than search
7569
- if ( opts.filter && ! opts.search ) {
7648
+ if ( opts.filter && opts.search === undefined ) {
7570
7649
  opts.search = opts.filter;
7571
7650
  }
7572
7651
 
7573
- return {
7574
- search: opts.search || 'none',
7575
- order: opts.order || 'current',
7576
- page: opts.page || 'all'
7577
- };
7652
+ return $.extend( {
7653
+ search: 'none',
7654
+ order: 'current',
7655
+ page: 'all'
7656
+ }, opts );
7578
7657
  };
7579
7658
 
7580
7659
 
@@ -7586,6 +7665,7 @@
7586
7665
  // Assign the first element to the first item in the instance
7587
7666
  // and truncate the instance and context
7588
7667
  inst[0] = inst[i];
7668
+ inst[0].length = 1;
7589
7669
  inst.length = 1;
7590
7670
  inst.context = [ inst.context[i] ];
7591
7671
 
@@ -7672,7 +7752,7 @@
7672
7752
 
7673
7753
  var __row_selector = function ( settings, selector, opts )
7674
7754
  {
7675
- return _selector_run( selector, function ( sel ) {
7755
+ var run = function ( sel ) {
7676
7756
  var selInt = _intVal( sel );
7677
7757
  var i, ien;
7678
7758
 
@@ -7715,6 +7795,26 @@
7715
7795
  }
7716
7796
  }
7717
7797
 
7798
+ // ID selector. Want to always be able to select rows by id, regardless
7799
+ // of if the tr element has been created or not, so can't rely upon
7800
+ // jQuery here - hence a custom implementation. This does not match
7801
+ // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7802
+ // but to select it using a CSS selector engine (like Sizzle or
7803
+ // querySelect) it would need to need to be escaped for some characters.
7804
+ // DataTables simplifies this for row selectors since you can select
7805
+ // only a row. A # indicates an id any anything that follows is the id -
7806
+ // unescaped.
7807
+ if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7808
+ // get row index from id
7809
+ var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7810
+ if ( rowObj !== undefined ) {
7811
+ return [ rowObj.idx ];
7812
+ }
7813
+
7814
+ // need to fall through to jQuery in case there is DOM id that
7815
+ // matches
7816
+ }
7817
+
7718
7818
  // Selector - jQuery selector string, array of nodes or jQuery object/
7719
7819
  // As jQuery's .filter() allows jQuery objects to be passed in filter,
7720
7820
  // it also allows arrays, so this will cope with all three options
@@ -7724,7 +7824,9 @@
7724
7824
  return this._DT_RowIndex;
7725
7825
  } )
7726
7826
  .toArray();
7727
- } );
7827
+ };
7828
+
7829
+ return _selector_run( 'row', selector, run, settings, opts );
7728
7830
  };
7729
7831
 
7730
7832
 
@@ -7782,23 +7884,49 @@
7782
7884
  }, 1 );
7783
7885
  } );
7784
7886
 
7887
+ _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
7888
+ var a = [];
7889
+ var context = this.context;
7890
+
7891
+ // `iterator` will drop undefined values, but in this case we want them
7892
+ for ( var i=0, ien=context.length ; i<ien ; i++ ) {
7893
+ for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
7894
+ var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
7895
+ a.push( (hash === true ? '#' : '' )+ id );
7896
+ }
7897
+ }
7898
+
7899
+ return new _Api( context, a );
7900
+ } );
7901
+
7785
7902
  _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7786
7903
  var that = this;
7787
7904
 
7788
- return this.iterator( 'row', function ( settings, row, thatIdx ) {
7905
+ this.iterator( 'row', function ( settings, row, thatIdx ) {
7789
7906
  var data = settings.aoData;
7907
+ var rowData = data[ row ];
7908
+ var i, ien, j, jen;
7909
+ var loopRow, loopCells;
7790
7910
 
7791
7911
  data.splice( row, 1 );
7792
7912
 
7793
- // Update the _DT_RowIndex parameter on all rows in the table
7794
- for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7795
- if ( data[i].nTr !== null ) {
7796
- data[i].nTr._DT_RowIndex = i;
7913
+ // Update the cached indexes
7914
+ for ( i=0, ien=data.length ; i<ien ; i++ ) {
7915
+ loopRow = data[i];
7916
+ loopCells = loopRow.anCells;
7917
+
7918
+ // Rows
7919
+ if ( loopRow.nTr !== null ) {
7920
+ loopRow.nTr._DT_RowIndex = i;
7797
7921
  }
7798
- }
7799
7922
 
7800
- // Remove the target row from the search array
7801
- var displayIndex = $.inArray( row, settings.aiDisplay );
7923
+ // Cells
7924
+ if ( loopCells !== null ) {
7925
+ for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
7926
+ loopCells[j]._DT_CellIndex.row = i;
7927
+ }
7928
+ }
7929
+ }
7802
7930
 
7803
7931
  // Delete from the display arrays
7804
7932
  _fnDeleteIndex( settings.aiDisplayMaster, row );
@@ -7807,7 +7935,21 @@
7807
7935
 
7808
7936
  // Check for an 'overflow' they case for displaying the table
7809
7937
  _fnLengthOverflow( settings );
7938
+
7939
+ // Remove the row's ID reference if there is one
7940
+ var id = settings.rowIdFn( rowData._aData );
7941
+ if ( id !== undefined ) {
7942
+ delete settings.aIds[ id ];
7943
+ }
7810
7944
  } );
7945
+
7946
+ this.iterator( 'table', function ( settings ) {
7947
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7948
+ settings.aoData[i].idx = i;
7949
+ }
7950
+ } );
7951
+
7952
+ return this;
7811
7953
  } );
7812
7954
 
7813
7955
 
@@ -7833,7 +7975,7 @@
7833
7975
  // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7834
7976
  var modRows = this.rows( -1 );
7835
7977
  modRows.pop();
7836
- modRows.push.apply( modRows, newRows.toArray() );
7978
+ $.merge( modRows, newRows );
7837
7979
 
7838
7980
  return modRows;
7839
7981
  } );
@@ -7951,7 +8093,7 @@
7951
8093
  if ( ctx.length ) {
7952
8094
  var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
7953
8095
 
7954
- if ( row._details ) {
8096
+ if ( row && row._details ) {
7955
8097
  row._details.remove();
7956
8098
 
7957
8099
  row._detailsShow = undefined;
@@ -8154,7 +8296,7 @@
8154
8296
  names = _pluck( columns, 'sName' ),
8155
8297
  nodes = _pluck( columns, 'nTh' );
8156
8298
 
8157
- return _selector_run( selector, function ( s ) {
8299
+ var run = function ( s ) {
8158
8300
  var selInt = _intVal( s );
8159
8301
 
8160
8302
  // Selector - all
@@ -8220,7 +8362,9 @@
8220
8362
  } )
8221
8363
  .toArray();
8222
8364
  }
8223
- } );
8365
+ };
8366
+
8367
+ return _selector_run( 'column', selector, run, settings, opts );
8224
8368
  };
8225
8369
 
8226
8370
 
@@ -8277,7 +8421,7 @@
8277
8421
  }
8278
8422
  }
8279
8423
 
8280
- _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );
8424
+ _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, recalc] );
8281
8425
 
8282
8426
  _fnSaveState( settings );
8283
8427
  };
@@ -8395,7 +8539,7 @@
8395
8539
  var columns = settings.aoColumns.length;
8396
8540
  var a, i, ien, j, o, host;
8397
8541
 
8398
- return _selector_run( selector, function ( s ) {
8542
+ var run = function ( s ) {
8399
8543
  var fnSelector = typeof s === 'function';
8400
8544
 
8401
8545
  if ( s === null || s === undefined || fnSelector ) {
@@ -8413,9 +8557,9 @@
8413
8557
 
8414
8558
  if ( fnSelector ) {
8415
8559
  // Selector - function
8416
- host = settings.aoData[ row ];
8560
+ host = data[ row ];
8417
8561
 
8418
- if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) {
8562
+ if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8419
8563
  a.push( o );
8420
8564
  }
8421
8565
  }
@@ -8438,15 +8582,15 @@
8438
8582
  return allCells
8439
8583
  .filter( s )
8440
8584
  .map( function (i, el) {
8441
- row = el.parentNode._DT_RowIndex;
8442
-
8443
- return {
8444
- row: row,
8445
- column: $.inArray( el, data[ row ].anCells )
8446
- };
8585
+ return { // use a new object, in case someone changes the values
8586
+ row: el._DT_CellIndex.row,
8587
+ column: el._DT_CellIndex.column
8588
+ };
8447
8589
  } )
8448
8590
  .toArray();
8449
- } );
8591
+ };
8592
+
8593
+ return _selector_run( 'cell', selector, run, settings, opts );
8450
8594
  };
8451
8595
 
8452
8596
 
@@ -8658,6 +8802,24 @@
8658
8802
  } );
8659
8803
 
8660
8804
 
8805
+ _api_register( 'order.fixed()', function ( set ) {
8806
+ if ( ! set ) {
8807
+ var ctx = this.context;
8808
+ var fixed = ctx.length ?
8809
+ ctx[0].aaSortingFixed :
8810
+ undefined;
8811
+
8812
+ return $.isArray( fixed ) ?
8813
+ { pre: fixed } :
8814
+ fixed;
8815
+ }
8816
+
8817
+ return this.iterator( 'table', function ( settings ) {
8818
+ settings.aaSortingFixed = $.extend( true, {}, set );
8819
+ } );
8820
+ } );
8821
+
8822
+
8661
8823
  // Order by the selected column(s)
8662
8824
  _api_register( [
8663
8825
  'columns().order()',
@@ -8856,11 +9018,22 @@
8856
9018
  */
8857
9019
  DataTable.tables = DataTable.fnTables = function ( visible )
8858
9020
  {
8859
- return $.map( DataTable.settings, function (o) {
9021
+ var api = false;
9022
+
9023
+ if ( $.isPlainObject( visible ) ) {
9024
+ api = visible.api;
9025
+ visible = visible.visible;
9026
+ }
9027
+
9028
+ var a = $.map( DataTable.settings, function (o) {
8860
9029
  if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8861
9030
  return o.nTable;
8862
9031
  }
8863
9032
  } );
9033
+
9034
+ return api ?
9035
+ new _Api( a ) :
9036
+ a;
8864
9037
  };
8865
9038
 
8866
9039
 
@@ -9015,10 +9188,6 @@
9015
9188
  jqTable.append( tfoot );
9016
9189
  }
9017
9190
 
9018
- // Remove the DataTables generated nodes, events and classes
9019
- jqTable.detach();
9020
- jqWrapper.detach();
9021
-
9022
9191
  settings.aaSorting = [];
9023
9192
  settings.aaSortingFixed = [];
9024
9193
  _fnSortingClasses( settings );
@@ -9038,30 +9207,36 @@
9038
9207
  } );
9039
9208
  }
9040
9209
 
9041
- if ( ! remove && orig ) {
9042
- // insertBefore acts like appendChild if !arg[1]
9043
- orig.insertBefore( table, settings.nTableReinsertBefore );
9044
- }
9045
-
9046
9210
  // Add the TR elements back into the table in their original order
9047
9211
  jqTbody.children().detach();
9048
9212
  jqTbody.append( rows );
9049
9213
 
9050
- // Restore the width of the original table - was read from the style property,
9051
- // so we can restore directly to that
9052
- jqTable
9053
- .css( 'width', settings.sDestroyWidth )
9054
- .removeClass( classes.sTable );
9214
+ // Remove the DataTables generated nodes, events and classes
9215
+ var removedMethod = remove ? 'remove' : 'detach';
9216
+ jqTable[ removedMethod ]();
9217
+ jqWrapper[ removedMethod ]();
9218
+
9219
+ // If we need to reattach the table to the document
9220
+ if ( ! remove && orig ) {
9221
+ // insertBefore acts like appendChild if !arg[1]
9222
+ orig.insertBefore( table, settings.nTableReinsertBefore );
9055
9223
 
9056
- // If the were originally stripe classes - then we add them back here.
9057
- // Note this is not fool proof (for example if not all rows had stripe
9058
- // classes - but it's a good effort without getting carried away
9059
- ien = settings.asDestroyStripes.length;
9224
+ // Restore the width of the original table - was read from the style property,
9225
+ // so we can restore directly to that
9226
+ jqTable
9227
+ .css( 'width', settings.sDestroyWidth )
9228
+ .removeClass( classes.sTable );
9060
9229
 
9061
- if ( ien ) {
9062
- jqTbody.children().each( function (i) {
9063
- $(this).addClass( settings.asDestroyStripes[i % ien] );
9064
- } );
9230
+ // If the were originally stripe classes - then we add them back here.
9231
+ // Note this is not fool proof (for example if not all rows had stripe
9232
+ // classes - but it's a good effort without getting carried away
9233
+ ien = settings.asDestroyStripes.length;
9234
+
9235
+ if ( ien ) {
9236
+ jqTbody.children().each( function (i) {
9237
+ $(this).addClass( settings.asDestroyStripes[i % ien] );
9238
+ } );
9239
+ }
9065
9240
  }
9066
9241
 
9067
9242
  /* Remove the settings object from the settings array */
@@ -9076,13 +9251,51 @@
9076
9251
  // Add the `every()` method for rows, columns and cells in a compact form
9077
9252
  $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9078
9253
  _api_register( type+'s().every()', function ( fn ) {
9079
- return this.iterator( type, function ( settings, idx, idx2 ) {
9080
- // idx2 is undefined for rows and columns.
9081
- fn.call( new _Api( settings )[ type ]( idx, idx2 ) );
9254
+ var opts = this.selector.opts;
9255
+ var api = this;
9256
+
9257
+ return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9258
+ // Rows and columns:
9259
+ // arg1 - index
9260
+ // arg2 - table counter
9261
+ // arg3 - loop counter
9262
+ // arg4 - undefined
9263
+ // Cells:
9264
+ // arg1 - row index
9265
+ // arg2 - column index
9266
+ // arg3 - table counter
9267
+ // arg4 - loop counter
9268
+ fn.call(
9269
+ api[ type ](
9270
+ arg1,
9271
+ type==='cell' ? arg2 : opts,
9272
+ type==='cell' ? opts : undefined
9273
+ ),
9274
+ arg1, arg2, arg3, arg4
9275
+ );
9082
9276
  } );
9083
9277
  } );
9084
9278
  } );
9085
9279
 
9280
+
9281
+ // i18n method for extensions to be able to use the language object from the
9282
+ // DataTable
9283
+ _api_register( 'i18n()', function ( token, def, plural ) {
9284
+ var ctx = this.context[0];
9285
+ var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9286
+
9287
+ if ( resolved === undefined ) {
9288
+ resolved = def;
9289
+ }
9290
+
9291
+ if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9292
+ resolved = resolved[ plural ] !== undefined ?
9293
+ resolved[ plural ] :
9294
+ resolved._;
9295
+ }
9296
+
9297
+ return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9298
+ } );
9086
9299
 
9087
9300
  /**
9088
9301
  * Version string for plug-ins to check compatibility. Allowed format is
@@ -9092,7 +9305,7 @@
9092
9305
  * @type string
9093
9306
  * @default Version number
9094
9307
  */
9095
- DataTable.version = "1.10.6";
9308
+ DataTable.version = "1.10.10";
9096
9309
 
9097
9310
  /**
9098
9311
  * Private data store, containing all of the settings objects that are
@@ -9244,7 +9457,16 @@
9244
9457
  * @default null
9245
9458
  * @private
9246
9459
  */
9247
- "src": null
9460
+ "src": null,
9461
+
9462
+ /**
9463
+ * Index in the aoData array. This saves an indexOf lookup when we have the
9464
+ * object, but want to know the index
9465
+ * @type integer
9466
+ * @default -1
9467
+ * @private
9468
+ */
9469
+ "idx": -1
9248
9470
  };
9249
9471
 
9250
9472
 
@@ -11685,7 +11907,18 @@
11685
11907
  * @name DataTable.defaults.renderer
11686
11908
  *
11687
11909
  */
11688
- "renderer": null
11910
+ "renderer": null,
11911
+
11912
+
11913
+ /**
11914
+ * Set the data property name that DataTables should use to get a row's id
11915
+ * to set as the `id` property in the node.
11916
+ * @type string
11917
+ * @default DT_RowId
11918
+ *
11919
+ * @name DataTable.defaults.rowId
11920
+ */
11921
+ "rowId": "DT_RowId"
11689
11922
  };
11690
11923
 
11691
11924
  _fnHungarianMap( DataTable.defaults );
@@ -12784,7 +13017,21 @@
12784
13017
  * @type boolean
12785
13018
  * @default false
12786
13019
  */
12787
- "bScrollbarLeft": false
13020
+ "bScrollbarLeft": false,
13021
+
13022
+ /**
13023
+ * Flag for if `getBoundingClientRect` is fully supported or not
13024
+ * @type boolean
13025
+ * @default false
13026
+ */
13027
+ "bBounding": false,
13028
+
13029
+ /**
13030
+ * Browser scrollbar width
13031
+ * @type integer
13032
+ * @default 0
13033
+ */
13034
+ "barWidth": 0
12788
13035
  },
12789
13036
 
12790
13037
 
@@ -12829,6 +13076,13 @@
12829
13076
  */
12830
13077
  "aiDisplayMaster": [],
12831
13078
 
13079
+ /**
13080
+ * Map of row ids to data indexes
13081
+ * @type object
13082
+ * @default {}
13083
+ */
13084
+ "aIds": {},
13085
+
12832
13086
  /**
12833
13087
  * Store information about each column that is in use
12834
13088
  * @type array
@@ -13437,7 +13691,21 @@
13437
13691
  * @type object
13438
13692
  * @default {}
13439
13693
  */
13440
- "oPlugins": {}
13694
+ "oPlugins": {},
13695
+
13696
+ /**
13697
+ * Function used to get a row's id from the row's data
13698
+ * @type function
13699
+ * @default null
13700
+ */
13701
+ "rowIdFn": null,
13702
+
13703
+ /**
13704
+ * Data location where to store a row's id
13705
+ * @type string
13706
+ * @default null
13707
+ */
13708
+ "rowId": null
13441
13709
  };
13442
13710
 
13443
13711
  /**
@@ -13486,6 +13754,14 @@
13486
13754
  classes: {},
13487
13755
 
13488
13756
 
13757
+ /**
13758
+ * DataTables build type (expanded by the download builder)
13759
+ *
13760
+ * @type string
13761
+ */
13762
+ builder: "-source-",
13763
+
13764
+
13489
13765
  /**
13490
13766
  * Error reporting.
13491
13767
  *
@@ -13599,6 +13875,37 @@
13599
13875
  search: [],
13600
13876
 
13601
13877
 
13878
+ /**
13879
+ * Selector extensions
13880
+ *
13881
+ * The `selector` option can be used to extend the options available for the
13882
+ * selector modifier options (`selector-modifier` object data type) that
13883
+ * each of the three built in selector types offer (row, column and cell +
13884
+ * their plural counterparts). For example the Select extension uses this
13885
+ * mechanism to provide an option to select only rows, columns and cells
13886
+ * that have been marked as selected by the end user (`{selected: true}`),
13887
+ * which can be used in conjunction with the existing built in selector
13888
+ * options.
13889
+ *
13890
+ * Each property is an array to which functions can be pushed. The functions
13891
+ * take three attributes:
13892
+ *
13893
+ * * Settings object for the host table
13894
+ * * Options object (`selector-modifier` object type)
13895
+ * * Array of selected item indexes
13896
+ *
13897
+ * The return is an array of the resulting item indexes after the custom
13898
+ * selector has been applied.
13899
+ *
13900
+ * @type object
13901
+ */
13902
+ selector: {
13903
+ cell: [],
13904
+ column: [],
13905
+ row: []
13906
+ },
13907
+
13908
+
13602
13909
  /**
13603
13910
  * Internal functions, exposed for used in plug-ins.
13604
13911
  *
@@ -14113,6 +14420,10 @@
14113
14420
  return [ 'first', 'previous', 'next', 'last' ];
14114
14421
  },
14115
14422
 
14423
+ numbers: function ( page, pages ) {
14424
+ return [ _numbers(page, pages) ];
14425
+ },
14426
+
14116
14427
  simple_numbers: function ( page, pages ) {
14117
14428
  return [ 'previous', _numbers(page, pages), 'next' ];
14118
14429
  },
@@ -14134,6 +14445,7 @@
14134
14445
  _: function ( settings, host, idx, buttons, page, pages ) {
14135
14446
  var classes = settings.oClasses;
14136
14447
  var lang = settings.oLanguage.oPaginate;
14448
+ var aria = settings.oLanguage.oAria.paginate || {};
14137
14449
  var btnDisplay, btnClass, counter=0;
14138
14450
 
14139
14451
  var attach = function( container, buttons ) {
@@ -14151,7 +14463,7 @@
14151
14463
  attach( inner, button );
14152
14464
  }
14153
14465
  else {
14154
- btnDisplay = '';
14466
+ btnDisplay = null;
14155
14467
  btnClass = '';
14156
14468
 
14157
14469
  switch ( button ) {
@@ -14190,10 +14502,11 @@
14190
14502
  break;
14191
14503
  }
14192
14504
 
14193
- if ( btnDisplay ) {
14505
+ if ( btnDisplay !== null ) {
14194
14506
  node = $('<a>', {
14195
14507
  'class': classes.sPageButton+' '+btnClass,
14196
14508
  'aria-controls': settings.sTableId,
14509
+ 'aria-label': aria[ button ],
14197
14510
  'data-dt-idx': counter,
14198
14511
  'tabindex': settings.iTabIndex,
14199
14512
  'id': idx === 0 && typeof button === 'string' ?
@@ -14223,7 +14536,7 @@
14223
14536
  // elements, focus is lost on the select button which is bad for
14224
14537
  // accessibility. So we want to restore focus once the draw has
14225
14538
  // completed
14226
- activeEl = $(document.activeElement).data('dt-idx');
14539
+ activeEl = $(host).find(document.activeElement).data('dt-idx');
14227
14540
  }
14228
14541
  catch (e) {}
14229
14542
 
@@ -14521,11 +14834,14 @@
14521
14834
  *
14522
14835
  * * `number` - Will format numeric data (defined by `columns.data`) for
14523
14836
  * display, retaining the original unformatted data for sorting and filtering.
14524
- * It takes 4 parameters:
14837
+ * It takes 5 parameters:
14525
14838
  * * `string` - Thousands grouping separator
14526
14839
  * * `string` - Decimal point indicator
14527
14840
  * * `integer` - Number of decimal points to show
14528
14841
  * * `string` (optional) - Prefix.
14842
+ * * `string` (optional) - Postfix (/suffix).
14843
+ * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14844
+ * parameters.
14529
14845
  *
14530
14846
  * @example
14531
14847
  * // Column definition using the number renderer
@@ -14537,7 +14853,7 @@
14537
14853
  * @namespace
14538
14854
  */
14539
14855
  DataTable.render = {
14540
- number: function ( thousands, decimal, precision, prefix ) {
14856
+ number: function ( thousands, decimal, precision, prefix, postfix ) {
14541
14857
  return {
14542
14858
  display: function ( d ) {
14543
14859
  if ( typeof d !== 'number' && typeof d !== 'string' ) {
@@ -14545,7 +14861,15 @@
14545
14861
  }
14546
14862
 
14547
14863
  var negative = d < 0 ? '-' : '';
14548
- d = Math.abs( parseFloat( d ) );
14864
+ var flo = parseFloat( d );
14865
+
14866
+ // If NaN then there isn't much formatting that we can do - just
14867
+ // return immediately
14868
+ if ( isNaN( flo ) ) {
14869
+ return d;
14870
+ }
14871
+
14872
+ d = Math.abs( flo );
14549
14873
 
14550
14874
  var intPart = parseInt( d, 10 );
14551
14875
  var floatPart = precision ?
@@ -14556,7 +14880,18 @@
14556
14880
  intPart.toString().replace(
14557
14881
  /\B(?=(\d{3})+(?!\d))/g, thousands
14558
14882
  ) +
14559
- floatPart;
14883
+ floatPart +
14884
+ (postfix||'');
14885
+ }
14886
+ };
14887
+ },
14888
+
14889
+ text: function () {
14890
+ return {
14891
+ display: function ( d ) {
14892
+ return typeof d === 'string' ?
14893
+ d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
14894
+ d;
14560
14895
  }
14561
14896
  };
14562
14897
  }
@@ -14660,11 +14995,9 @@
14660
14995
  _fnCalculateColumnWidths: _fnCalculateColumnWidths,
14661
14996
  _fnThrottle: _fnThrottle,
14662
14997
  _fnConvertToWidth: _fnConvertToWidth,
14663
- _fnScrollingWidthAdjust: _fnScrollingWidthAdjust,
14664
14998
  _fnGetWidestNode: _fnGetWidestNode,
14665
14999
  _fnGetMaxLenString: _fnGetMaxLenString,
14666
15000
  _fnStringToCss: _fnStringToCss,
14667
- _fnScrollBarWidth: _fnScrollBarWidth,
14668
15001
  _fnSortFlatten: _fnSortFlatten,
14669
15002
  _fnSort: _fnSort,
14670
15003
  _fnSortAria: _fnSortAria,
@@ -14693,6 +15026,9 @@
14693
15026
  // jQuery access
14694
15027
  $.fn.dataTable = DataTable;
14695
15028
 
15029
+ // Provide access to the host jQuery object (circular reference)
15030
+ DataTable.$ = $;
15031
+
14696
15032
  // Legacy aliases
14697
15033
  $.fn.dataTableSettings = DataTable.settings;
14698
15034
  $.fn.dataTableExt = DataTable.ext;
@@ -14874,6 +15210,3 @@
14874
15210
 
14875
15211
  return $.fn.dataTable;
14876
15212
  }));
14877
-
14878
- }(window, document));
14879
-