effective_datatables 2.12.2 → 3.0.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +632 -512
  3. data/app/assets/javascripts/dataTables/buttons/buttons.html5.js +176 -177
  4. data/app/assets/javascripts/dataTables/buttons/buttons.print.js +2 -0
  5. data/app/assets/javascripts/dataTables/buttons/dataTables.buttons.js +14 -14
  6. data/app/assets/javascripts/dataTables/dataTables.bootstrap.js +1 -1
  7. data/app/assets/javascripts/dataTables/jquery.dataTables.js +246 -217
  8. data/app/assets/javascripts/effective_datatables.js +2 -3
  9. data/app/assets/javascripts/effective_datatables/events.js.coffee +7 -0
  10. data/app/assets/javascripts/effective_datatables/filters.js.coffee +6 -0
  11. data/app/assets/javascripts/effective_datatables/initialize.js.coffee +42 -39
  12. data/app/assets/javascripts/effective_datatables/reset.js.coffee +7 -0
  13. data/app/assets/javascripts/vendor/jquery.delayedChange.js +1 -1
  14. data/app/assets/stylesheets/dataTables/dataTables.bootstrap.css +0 -1
  15. data/app/assets/stylesheets/effective_datatables.scss +1 -2
  16. data/app/assets/stylesheets/effective_datatables/{_scopes.scss → _filters.scss} +1 -1
  17. data/app/assets/stylesheets/effective_datatables/_overrides.scss +1 -1
  18. data/app/controllers/effective/datatables_controller.rb +2 -4
  19. data/app/helpers/effective_datatables_helper.rb +56 -91
  20. data/app/helpers/effective_datatables_private_helper.rb +55 -64
  21. data/app/models/effective/datatable.rb +103 -177
  22. data/app/models/effective/datatable_column.rb +28 -0
  23. data/app/models/effective/datatable_column_tool.rb +110 -0
  24. data/app/models/effective/datatable_dsl_tool.rb +28 -0
  25. data/app/models/effective/datatable_value_tool.rb +142 -0
  26. data/app/models/effective/effective_datatable/attributes.rb +25 -0
  27. data/app/models/effective/effective_datatable/collection.rb +38 -0
  28. data/app/models/effective/effective_datatable/compute.rb +154 -0
  29. data/app/models/effective/effective_datatable/cookie.rb +29 -0
  30. data/app/models/effective/effective_datatable/dsl.rb +14 -8
  31. data/app/models/effective/effective_datatable/dsl/bulk_actions.rb +5 -6
  32. data/app/models/effective/effective_datatable/dsl/charts.rb +7 -9
  33. data/app/models/effective/effective_datatable/dsl/datatable.rb +107 -57
  34. data/app/models/effective/effective_datatable/dsl/filters.rb +50 -0
  35. data/app/models/effective/effective_datatable/format.rb +157 -0
  36. data/app/models/effective/effective_datatable/hooks.rb +0 -18
  37. data/app/models/effective/effective_datatable/params.rb +34 -0
  38. data/app/models/effective/effective_datatable/resource.rb +108 -0
  39. data/app/models/effective/effective_datatable/state.rb +178 -0
  40. data/app/views/effective/datatables/_actions_column.html.haml +9 -42
  41. data/app/views/effective/datatables/_bulk_actions_column.html.haml +1 -1
  42. data/app/views/effective/datatables/_bulk_actions_dropdown.html.haml +2 -3
  43. data/app/views/effective/datatables/_chart.html.haml +1 -1
  44. data/app/views/effective/datatables/_datatable.html.haml +7 -25
  45. data/app/views/effective/datatables/_filters.html.haml +21 -0
  46. data/app/views/effective/datatables/_reset.html.haml +2 -0
  47. data/app/views/effective/datatables/_resource_column.html.haml +8 -0
  48. data/app/views/effective/datatables/index.html.haml +0 -1
  49. data/config/effective_datatables.rb +9 -32
  50. data/lib/effective_datatables.rb +2 -6
  51. data/lib/effective_datatables/engine.rb +1 -1
  52. data/lib/effective_datatables/version.rb +1 -1
  53. data/lib/generators/effective_datatables/install_generator.rb +2 -2
  54. metadata +39 -19
  55. data/app/assets/javascripts/dataTables/colreorder/dataTables.colReorder.js +0 -27
  56. data/app/assets/javascripts/dataTables/jszip/jszip.js +0 -9155
  57. data/app/assets/javascripts/effective_datatables/scopes.js.coffee +0 -9
  58. data/app/models/effective/active_record_datatable_tool.rb +0 -242
  59. data/app/models/effective/array_datatable_tool.rb +0 -97
  60. data/app/models/effective/effective_datatable/ajax.rb +0 -101
  61. data/app/models/effective/effective_datatable/charts.rb +0 -20
  62. data/app/models/effective/effective_datatable/dsl/scopes.rb +0 -23
  63. data/app/models/effective/effective_datatable/helpers.rb +0 -24
  64. data/app/models/effective/effective_datatable/options.rb +0 -309
  65. data/app/models/effective/effective_datatable/rendering.rb +0 -365
  66. data/app/views/effective/datatables/_scopes.html.haml +0 -21
@@ -144,6 +144,8 @@ DataTable.ext.buttons.print = {
144
144
  '</div>'+
145
145
  html;
146
146
 
147
+ $(win.document.body).addClass('dt-print-view');
148
+
147
149
  if ( config.customize ) {
148
150
  config.customize( win );
149
151
  }
@@ -1,4 +1,4 @@
1
- /*! Buttons for DataTables 1.2.2
1
+ /*! Buttons for DataTables 1.2.4
2
2
  * ©2016 SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
@@ -49,7 +49,7 @@ var _dtButtons = DataTable.ext.buttons;
49
49
  var Buttons = function( dt, config )
50
50
  {
51
51
  // Allow a boolean true for defaults
52
- if ( config === true || config === undefined ) {
52
+ if ( config === true ) {
53
53
  config = {};
54
54
  }
55
55
 
@@ -194,7 +194,7 @@ $.extend( Buttons.prototype, {
194
194
  // needed). Take a copy as the array is modified by `remove`
195
195
  var buttons = this.s.buttons.slice();
196
196
  var i, ien;
197
-
197
+
198
198
  for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
199
199
  this.remove( buttons[i].node );
200
200
  }
@@ -515,7 +515,7 @@ $.extend( Buttons.prototype, {
515
515
  config.action.call( dt.button( button ), e, dt, button, config );
516
516
 
517
517
  $(dt.table().node()).triggerHandler( 'buttons-action.dt', [
518
- dt.button( button ), dt, button, config
518
+ dt.button( button ), dt, button, config
519
519
  ] );
520
520
  };
521
521
 
@@ -860,7 +860,7 @@ $.extend( Buttons.prototype, {
860
860
  /**
861
861
  * Show / hide a background layer behind a collection
862
862
  * @param {boolean} Flag to indicate if the background should be shown or
863
- * hidden
863
+ * hidden
864
864
  * @param {string} Class to assign to the background
865
865
  * @static
866
866
  */
@@ -938,7 +938,7 @@ Buttons.instanceSelector = function ( group, buttons )
938
938
  ret.push( buttons[ input ].inst );
939
939
  }
940
940
  };
941
-
941
+
942
942
  process( group );
943
943
 
944
944
  return ret;
@@ -1118,7 +1118,7 @@ Buttons.defaults = {
1118
1118
  * @type {string}
1119
1119
  * @static
1120
1120
  */
1121
- Buttons.version = '1.2.2';
1121
+ Buttons.version = '1.2.4';
1122
1122
 
1123
1123
 
1124
1124
  $.extend( _dtButtons, {
@@ -1135,7 +1135,7 @@ $.extend( _dtButtons, {
1135
1135
 
1136
1136
  // Remove any old collection
1137
1137
  if ( $('div.dt-button-background').length ) {
1138
- multiLevel = $('div.dt-button-collection').offset();
1138
+ multiLevel = $('.dt-button-collection').offset();
1139
1139
  $('body').trigger( 'click.dtb-collection' );
1140
1140
  }
1141
1141
 
@@ -1149,8 +1149,8 @@ $.extend( _dtButtons, {
1149
1149
 
1150
1150
  if ( multiLevel && position === 'absolute' ) {
1151
1151
  config._collection.css( {
1152
- top: multiLevel.top + 5, // magic numbers for a little offset
1153
- left: multiLevel.left + 5
1152
+ top: multiLevel.top,
1153
+ left: multiLevel.left
1154
1154
  } );
1155
1155
  }
1156
1156
  else if ( position === 'absolute' ) {
@@ -1273,6 +1273,7 @@ $.extend( _dtButtons, {
1273
1273
  buttons: $.map( vals, function ( val, i ) {
1274
1274
  return {
1275
1275
  text: lang[i],
1276
+ className: 'button-page-length',
1276
1277
  action: function ( e, dt ) {
1277
1278
  dt.page.len( val ).draw();
1278
1279
  },
@@ -1589,12 +1590,11 @@ var _exportData = function ( dt, inOpts )
1589
1590
  null;
1590
1591
 
1591
1592
  var rowIndexes = dt.rows( config.rows, config.modifier ).indexes().toArray();
1592
- var cells = dt
1593
- .cells( rowIndexes, config.columns )
1593
+ var selectedCells = dt.cells( rowIndexes, config.columns );
1594
+ var cells = selectedCells
1594
1595
  .render( config.orthogonal )
1595
1596
  .toArray();
1596
- var cellNodes = dt
1597
- .cells( rowIndexes, config.columns )
1597
+ var cellNodes = selectedCells
1598
1598
  .nodes()
1599
1599
  .toArray();
1600
1600
 
@@ -172,7 +172,7 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
172
172
  buttons
173
173
  );
174
174
 
175
- if ( activeEl ) {
175
+ if ( activeEl !== undefined ) {
176
176
  $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
177
177
  }
178
178
  };
@@ -1,15 +1,15 @@
1
- /*! DataTables 1.10.12
2
- * ©2008-2015 SpryMedia Ltd - datatables.net/license
1
+ /*! DataTables 1.10.13
2
+ * ©2008-2016 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.12
8
+ * @version 1.10.13
9
9
  * @file jquery.dataTables.js
10
- * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
- * @contact www.sprymedia.co.uk/contact
12
- * @copyright Copyright 2008-2015 SpryMedia Ltd.
10
+ * @author SpryMedia Ltd
11
+ * @contact www.datatables.net
12
+ * @copyright Copyright 2008-2016 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
@@ -279,7 +279,7 @@
279
279
  * "bPaginate": false
280
280
  * } );
281
281
  *
282
- * $(window).bind('resize', function () {
282
+ * $(window).on('resize', function () {
283
283
  * oTable.fnAdjustColumnSizing();
284
284
  * } );
285
285
  * } );
@@ -1101,7 +1101,7 @@
1101
1101
  var oLanguage = oSettings.oLanguage;
1102
1102
  $.extend( true, oLanguage, oInit.oLanguage );
1103
1103
 
1104
- if ( oLanguage.sUrl !== "" )
1104
+ if ( oLanguage.sUrl )
1105
1105
  {
1106
1106
  /* Get the language definitions from a file - because this Ajax call makes the language
1107
1107
  * get async to the remainder of this function we use bInitHandedOff to indicate that
@@ -1213,131 +1213,125 @@
1213
1213
  }
1214
1214
 
1215
1215
  var features = oSettings.oFeatures;
1216
+ var loadedInit = function () {
1217
+ /*
1218
+ * Sorting
1219
+ * @todo For modularisation (1.11) this needs to do into a sort start up handler
1220
+ */
1216
1221
 
1217
- /* Must be done after everything which can be overridden by the state saving! */
1218
- if ( oInit.bStateSave )
1219
- {
1220
- features.bStateSave = true;
1221
- _fnLoadState( oSettings, oInit );
1222
- _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
1223
- }
1222
+ // If aaSorting is not defined, then we use the first indicator in asSorting
1223
+ // in case that has been altered, so the default sort reflects that option
1224
+ if ( oInit.aaSorting === undefined ) {
1225
+ var sorting = oSettings.aaSorting;
1226
+ for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
1227
+ sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
1228
+ }
1229
+ }
1224
1230
 
1231
+ /* Do a first pass on the sorting classes (allows any size changes to be taken into
1232
+ * account, and also will apply sorting disabled classes if disabled
1233
+ */
1234
+ _fnSortingClasses( oSettings );
1225
1235
 
1226
- /*
1227
- * Sorting
1228
- * @todo For modularisation (1.11) this needs to do into a sort start up handler
1229
- */
1236
+ if ( features.bSort ) {
1237
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1238
+ if ( oSettings.bSorted ) {
1239
+ var aSort = _fnSortFlatten( oSettings );
1240
+ var sortedColumns = {};
1230
1241
 
1231
- // If aaSorting is not defined, then we use the first indicator in asSorting
1232
- // in case that has been altered, so the default sort reflects that option
1233
- if ( oInit.aaSorting === undefined )
1234
- {
1235
- var sorting = oSettings.aaSorting;
1236
- for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
1237
- {
1238
- sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
1239
- }
1240
- }
1242
+ $.each( aSort, function (i, val) {
1243
+ sortedColumns[ val.src ] = val.dir;
1244
+ } );
1241
1245
 
1242
- /* Do a first pass on the sorting classes (allows any size changes to be taken into
1243
- * account, and also will apply sorting disabled classes if disabled
1244
- */
1245
- _fnSortingClasses( oSettings );
1246
+ _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
1247
+ _fnSortAria( oSettings );
1248
+ }
1249
+ } );
1250
+ }
1246
1251
 
1247
- if ( features.bSort )
1248
- {
1249
1252
  _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1250
- if ( oSettings.bSorted ) {
1251
- var aSort = _fnSortFlatten( oSettings );
1252
- var sortedColumns = {};
1253
+ if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
1254
+ _fnSortingClasses( oSettings );
1255
+ }
1256
+ }, 'sc' );
1253
1257
 
1254
- $.each( aSort, function (i, val) {
1255
- sortedColumns[ val.src ] = val.dir;
1256
- } );
1257
1258
 
1258
- _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
1259
- _fnSortAria( oSettings );
1260
- }
1259
+ /*
1260
+ * Final init
1261
+ * Cache the header, body and footer as required, creating them if needed
1262
+ */
1263
+
1264
+ // Work around for Webkit bug 83867 - store the caption-side before removing from doc
1265
+ var captions = $this.children('caption').each( function () {
1266
+ this._captionSide = $(this).css('caption-side');
1261
1267
  } );
1262
- }
1263
1268
 
1264
- _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1265
- if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
1266
- _fnSortingClasses( oSettings );
1269
+ var thead = $this.children('thead');
1270
+ if ( thead.length === 0 ) {
1271
+ thead = $('<thead/>').appendTo($this);
1267
1272
  }
1268
- }, 'sc' );
1273
+ oSettings.nTHead = thead[0];
1269
1274
 
1275
+ var tbody = $this.children('tbody');
1276
+ if ( tbody.length === 0 ) {
1277
+ tbody = $('<tbody/>').appendTo($this);
1278
+ }
1279
+ oSettings.nTBody = tbody[0];
1270
1280
 
1271
- /*
1272
- * Final init
1273
- * Cache the header, body and footer as required, creating them if needed
1274
- */
1281
+ var tfoot = $this.children('tfoot');
1282
+ if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
1283
+ // If we are a scrolling table, and no footer has been given, then we need to create
1284
+ // a tfoot element for the caption element to be appended to
1285
+ tfoot = $('<tfoot/>').appendTo($this);
1286
+ }
1275
1287
 
1276
- // Work around for Webkit bug 83867 - store the caption-side before removing from doc
1277
- var captions = $this.children('caption').each( function () {
1278
- this._captionSide = $this.css('caption-side');
1279
- } );
1288
+ if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
1289
+ $this.addClass( oClasses.sNoFooter );
1290
+ }
1291
+ else if ( tfoot.length > 0 ) {
1292
+ oSettings.nTFoot = tfoot[0];
1293
+ _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
1294
+ }
1280
1295
 
1281
- var thead = $this.children('thead');
1282
- if ( thead.length === 0 )
1283
- {
1284
- thead = $('<thead/>').appendTo(this);
1285
- }
1286
- oSettings.nTHead = thead[0];
1296
+ /* Check if there is data passing into the constructor */
1297
+ if ( oInit.aaData ) {
1298
+ for ( i=0 ; i<oInit.aaData.length ; i++ ) {
1299
+ _fnAddData( oSettings, oInit.aaData[ i ] );
1300
+ }
1301
+ }
1302
+ else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
1303
+ /* Grab the data from the page - only do this when deferred loading or no Ajax
1304
+ * source since there is no point in reading the DOM data if we are then going
1305
+ * to replace it with Ajax data
1306
+ */
1307
+ _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
1308
+ }
1287
1309
 
1288
- var tbody = $this.children('tbody');
1289
- if ( tbody.length === 0 )
1290
- {
1291
- tbody = $('<tbody/>').appendTo(this);
1292
- }
1293
- oSettings.nTBody = tbody[0];
1310
+ /* Copy the data index array */
1311
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1294
1312
 
1295
- var tfoot = $this.children('tfoot');
1296
- if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
1297
- {
1298
- // If we are a scrolling table, and no footer has been given, then we need to create
1299
- // a tfoot element for the caption element to be appended to
1300
- tfoot = $('<tfoot/>').appendTo(this);
1301
- }
1313
+ /* Initialisation complete - table can be drawn */
1314
+ oSettings.bInitialised = true;
1302
1315
 
1303
- if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
1304
- $this.addClass( oClasses.sNoFooter );
1305
- }
1306
- else if ( tfoot.length > 0 ) {
1307
- oSettings.nTFoot = tfoot[0];
1308
- _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
1309
- }
1316
+ /* Check if we need to initialise the table (it might not have been handed off to the
1317
+ * language processor)
1318
+ */
1319
+ if ( bInitHandedOff === false ) {
1320
+ _fnInitialise( oSettings );
1321
+ }
1322
+ };
1310
1323
 
1311
- /* Check if there is data passing into the constructor */
1312
- if ( oInit.aaData )
1324
+ /* Must be done after everything which can be overridden by the state saving! */
1325
+ if ( oInit.bStateSave )
1313
1326
  {
1314
- for ( i=0 ; i<oInit.aaData.length ; i++ )
1315
- {
1316
- _fnAddData( oSettings, oInit.aaData[ i ] );
1317
- }
1327
+ features.bStateSave = true;
1328
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
1329
+ _fnLoadState( oSettings, oInit, loadedInit );
1318
1330
  }
1319
- else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
1320
- {
1321
- /* Grab the data from the page - only do this when deferred loading or no Ajax
1322
- * source since there is no point in reading the DOM data if we are then going
1323
- * to replace it with Ajax data
1324
- */
1325
- _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
1331
+ else {
1332
+ loadedInit();
1326
1333
  }
1327
1334
 
1328
- /* Copy the data index array */
1329
- oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1330
-
1331
- /* Initialisation complete - table can be drawn */
1332
- oSettings.bInitialised = true;
1333
-
1334
- /* Check if we need to initialise the table (it might not have been handed off to the
1335
- * language processor)
1336
- */
1337
- if ( bInitHandedOff === false )
1338
- {
1339
- _fnInitialise( oSettings );
1340
- }
1341
1335
  } );
1342
1336
  _that = null;
1343
1337
  return this;
@@ -1368,8 +1362,10 @@
1368
1362
  var _re_dic = {};
1369
1363
  var _re_new_lines = /[\r\n]/g;
1370
1364
  var _re_html = /<.*?>/g;
1371
- var _re_date_start = /^[\w\+\-]/;
1372
- var _re_date_end = /[\w\+\-]$/;
1365
+
1366
+ // This is not strict ISO8601 - Date.parse() is quite lax, although
1367
+ // implementations differ between browsers.
1368
+ var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
1373
1369
 
1374
1370
  // Escape regular expression special characters
1375
1371
  var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
@@ -1851,7 +1847,7 @@
1851
1847
  .css( {
1852
1848
  position: 'fixed',
1853
1849
  top: 0,
1854
- left: 0,
1850
+ left: $(window).scrollLeft()*-1, // allow for scrolling
1855
1851
  height: 1,
1856
1852
  width: 1,
1857
1853
  overflow: 'hidden'
@@ -2544,7 +2540,7 @@
2544
2540
  function _fnSplitObjNotation( str )
2545
2541
  {
2546
2542
  return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
2547
- return s.replace(/\\./g, '.');
2543
+ return s.replace(/\\\./g, '.');
2548
2544
  } );
2549
2545
  }
2550
2546
 
@@ -4202,13 +4198,13 @@
4202
4198
  var jqFilter = $('input', filter)
4203
4199
  .val( previousSearch.sSearch )
4204
4200
  .attr( 'placeholder', language.sSearchPlaceholder )
4205
- .bind(
4201
+ .on(
4206
4202
  'keyup.DT search.DT input.DT paste.DT cut.DT',
4207
4203
  searchDelay ?
4208
4204
  _fnThrottle( searchFn, searchDelay ) :
4209
4205
  searchFn
4210
4206
  )
4211
- .bind( 'keypress.DT', function(e) {
4207
+ .on( 'keypress.DT', function(e) {
4212
4208
  /* Prevent form submission */
4213
4209
  if ( e.keyCode == 13 ) {
4214
4210
  return false;
@@ -4338,16 +4334,19 @@
4338
4334
  }
4339
4335
 
4340
4336
  var data;
4337
+ var out = [];
4341
4338
  var display = settings.aiDisplay;
4342
4339
  var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
4343
4340
 
4344
- for ( var i=display.length-1 ; i>=0 ; i-- ) {
4341
+ for ( var i=0 ; i<display.length ; i++ ) {
4345
4342
  data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
4346
4343
 
4347
- if ( ! rpSearch.test( data ) ) {
4348
- display.splice( i, 1 );
4344
+ if ( rpSearch.test( data ) ) {
4345
+ out.push( display[i] );
4349
4346
  }
4350
4347
  }
4348
+
4349
+ settings.aiDisplay = out;
4351
4350
  }
4352
4351
 
4353
4352
 
@@ -4367,6 +4366,7 @@
4367
4366
  var prevSearch = settings.oPreviousSearch.sSearch;
4368
4367
  var displayMaster = settings.aiDisplayMaster;
4369
4368
  var display, invalidated, i;
4369
+ var filtered = [];
4370
4370
 
4371
4371
  // Need to take account of custom filtering functions - always filter
4372
4372
  if ( DataTable.ext.search.length !== 0 ) {
@@ -4395,11 +4395,13 @@
4395
4395
  // Search the display array
4396
4396
  display = settings.aiDisplay;
4397
4397
 
4398
- for ( i=display.length-1 ; i>=0 ; i-- ) {
4399
- if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4400
- display.splice( i, 1 );
4398
+ for ( i=0 ; i<display.length ; i++ ) {
4399
+ if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4400
+ filtered.push( display[i] );
4401
4401
  }
4402
4402
  }
4403
+
4404
+ settings.aiDisplay = filtered;
4403
4405
  }
4404
4406
  }
4405
4407
 
@@ -4812,13 +4814,13 @@
4812
4814
  // reference is broken by the use of outerHTML
4813
4815
  $('select', div)
4814
4816
  .val( settings._iDisplayLength )
4815
- .bind( 'change.DT', function(e) {
4817
+ .on( 'change.DT', function(e) {
4816
4818
  _fnLengthChange( settings, $(this).val() );
4817
4819
  _fnDraw( settings );
4818
4820
  } );
4819
4821
 
4820
4822
  // Update node value whenever anything changes the table's length
4821
- $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
4823
+ $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
4822
4824
  if ( settings === s ) {
4823
4825
  $('select', div).val( len );
4824
4826
  }
@@ -5683,7 +5685,7 @@
5683
5685
 
5684
5686
  if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
5685
5687
  var bindResize = function () {
5686
- $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
5688
+ $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
5687
5689
  _fnAdjustColumnSizing( oSettings );
5688
5690
  } ) );
5689
5691
  };
@@ -6294,86 +6296,102 @@
6294
6296
  * Attempt to load a saved table state
6295
6297
  * @param {object} oSettings dataTables settings object
6296
6298
  * @param {object} oInit DataTables init object so we can override settings
6299
+ * @param {function} callback Callback to execute when the state has been loaded
6297
6300
  * @memberof DataTable#oApi
6298
6301
  */
6299
- function _fnLoadState ( settings, oInit )
6302
+ function _fnLoadState ( settings, oInit, callback )
6300
6303
  {
6301
6304
  var i, ien;
6302
6305
  var columns = settings.aoColumns;
6306
+ var loaded = function ( s ) {
6307
+ if ( ! s || ! s.time ) {
6308
+ callback();
6309
+ return;
6310
+ }
6303
6311
 
6304
- if ( ! settings.oFeatures.bStateSave ) {
6305
- return;
6306
- }
6307
-
6308
- var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
6309
- if ( ! state || ! state.time ) {
6310
- return;
6311
- }
6312
+ // Allow custom and plug-in manipulation functions to alter the saved data set and
6313
+ // cancelling of loading by returning false
6314
+ var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
6315
+ if ( $.inArray( false, abStateLoad ) !== -1 ) {
6316
+ callback();
6317
+ return;
6318
+ }
6312
6319
 
6313
- /* Allow custom and plug-in manipulation functions to alter the saved data set and
6314
- * cancelling of loading by returning false
6315
- */
6316
- var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
6317
- if ( $.inArray( false, abStateLoad ) !== -1 ) {
6318
- return;
6319
- }
6320
+ // Reject old data
6321
+ var duration = settings.iStateDuration;
6322
+ if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6323
+ callback();
6324
+ return;
6325
+ }
6320
6326
 
6321
- /* Reject old data */
6322
- var duration = settings.iStateDuration;
6323
- if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
6324
- return;
6325
- }
6327
+ // Number of columns have changed - all bets are off, no restore of settings
6328
+ if ( s.columns && columns.length !== s.columns.length ) {
6329
+ callback();
6330
+ return;
6331
+ }
6326
6332
 
6327
- // Number of columns have changed - all bets are off, no restore of settings
6328
- if ( columns.length !== state.columns.length ) {
6329
- return;
6330
- }
6333
+ // Store the saved state so it might be accessed at any time
6334
+ settings.oLoadedState = $.extend( true, {}, state );
6331
6335
 
6332
- // Store the saved state so it might be accessed at any time
6333
- settings.oLoadedState = $.extend( true, {}, state );
6336
+ // Restore key features - todo - for 1.11 this needs to be done by
6337
+ // subscribed events
6338
+ if ( s.start !== undefined ) {
6339
+ settings._iDisplayStart = s.start;
6340
+ settings.iInitDisplayStart = s.start;
6341
+ }
6342
+ if ( s.length !== undefined ) {
6343
+ settings._iDisplayLength = s.length;
6344
+ }
6334
6345
 
6335
- // Restore key features - todo - for 1.11 this needs to be done by
6336
- // subscribed events
6337
- if ( state.start !== undefined ) {
6338
- settings._iDisplayStart = state.start;
6339
- settings.iInitDisplayStart = state.start;
6340
- }
6341
- if ( state.length !== undefined ) {
6342
- settings._iDisplayLength = state.length;
6343
- }
6346
+ // Order
6347
+ if ( s.order !== undefined ) {
6348
+ settings.aaSorting = [];
6349
+ $.each( s.order, function ( i, col ) {
6350
+ settings.aaSorting.push( col[0] >= columns.length ?
6351
+ [ 0, col[1] ] :
6352
+ col
6353
+ );
6354
+ } );
6355
+ }
6344
6356
 
6345
- // Order
6346
- if ( state.order !== undefined ) {
6347
- settings.aaSorting = [];
6348
- $.each( state.order, function ( i, col ) {
6349
- settings.aaSorting.push( col[0] >= columns.length ?
6350
- [ 0, col[1] ] :
6351
- col
6352
- );
6353
- } );
6354
- }
6357
+ // Search
6358
+ if ( s.search !== undefined ) {
6359
+ $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
6360
+ }
6355
6361
 
6356
- // Search
6357
- if ( state.search !== undefined ) {
6358
- $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
6359
- }
6362
+ // Columns
6363
+ //
6364
+ if ( s.columns ) {
6365
+ for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6366
+ var col = s.columns[i];
6360
6367
 
6361
- // Columns
6362
- for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
6363
- var col = state.columns[i];
6368
+ // Visibility
6369
+ if ( col.visible !== undefined ) {
6370
+ columns[i].bVisible = col.visible;
6371
+ }
6364
6372
 
6365
- // Visibility
6366
- if ( col.visible !== undefined ) {
6367
- columns[i].bVisible = col.visible;
6373
+ // Search
6374
+ if ( col.search !== undefined ) {
6375
+ $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
6376
+ }
6377
+ }
6368
6378
  }
6369
6379
 
6370
- // Search
6371
- if ( col.search !== undefined ) {
6372
- $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
6373
- }
6380
+ _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
6381
+ callback();
6374
6382
  }
6375
6383
 
6376
- _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
6384
+ if ( ! settings.oFeatures.bStateSave ) {
6385
+ callback();
6386
+ return;
6387
+ }
6388
+
6389
+ var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6390
+
6391
+ if ( state !== undefined ) {
6392
+ loaded( state );
6393
+ }
6394
+ // otherwise, wait for the loaded callback to be executed
6377
6395
  }
6378
6396
 
6379
6397
 
@@ -6526,17 +6544,17 @@
6526
6544
  function _fnBindAction( n, oData, fn )
6527
6545
  {
6528
6546
  $(n)
6529
- .bind( 'click.DT', oData, function (e) {
6547
+ .on( 'click.DT', oData, function (e) {
6530
6548
  n.blur(); // Remove focus outline for mouse users
6531
6549
  fn(e);
6532
6550
  } )
6533
- .bind( 'keypress.DT', oData, function (e){
6551
+ .on( 'keypress.DT', oData, function (e){
6534
6552
  if ( e.which === 13 ) {
6535
6553
  e.preventDefault();
6536
6554
  fn(e);
6537
6555
  }
6538
6556
  } )
6539
- .bind( 'selectstart.DT', function () {
6557
+ .on( 'selectstart.DT', function () {
6540
6558
  /* Take the brutal approach to cancelling text selection */
6541
6559
  return false;
6542
6560
  } );
@@ -7664,7 +7682,8 @@
7664
7682
  }
7665
7683
 
7666
7684
  for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7667
- a = selector[i] && selector[i].split ?
7685
+ // Only split on simple strings - complex expressions will be jQuery selectors
7686
+ a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
7668
7687
  selector[i].split(',') :
7669
7688
  [ selector[i] ];
7670
7689
 
@@ -7804,6 +7823,7 @@
7804
7823
 
7805
7824
  var __row_selector = function ( settings, selector, opts )
7806
7825
  {
7826
+ var rows;
7807
7827
  var run = function ( sel ) {
7808
7828
  var selInt = _intVal( sel );
7809
7829
  var i, ien;
@@ -7815,13 +7835,15 @@
7815
7835
  return [ selInt ];
7816
7836
  }
7817
7837
 
7818
- var rows = _selector_row_indexes( settings, opts );
7838
+ if ( ! rows ) {
7839
+ rows = _selector_row_indexes( settings, opts );
7840
+ }
7819
7841
 
7820
7842
  if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7821
7843
  // Selector - integer
7822
7844
  return [ selInt ];
7823
7845
  }
7824
- else if ( ! sel ) {
7846
+ else if ( sel === null || sel === undefined || sel === '' ) {
7825
7847
  // Selector - none
7826
7848
  return rows;
7827
7849
  }
@@ -8134,7 +8156,7 @@
8134
8156
  addRow( data, klass );
8135
8157
 
8136
8158
  if ( row._details ) {
8137
- row._details.remove();
8159
+ row._details.detach();
8138
8160
  }
8139
8161
 
8140
8162
  row._details = $(rows);
@@ -8335,7 +8357,7 @@
8335
8357
  // can be an array of these items, comma separated list, or an array of comma
8336
8358
  // separated lists
8337
8359
 
8338
- var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
8360
+ var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
8339
8361
 
8340
8362
 
8341
8363
  // r1 and r2 are redundant - but it means that the parameters match for the
@@ -9082,6 +9104,10 @@
9082
9104
  var t = $(table).get(0);
9083
9105
  var is = false;
9084
9106
 
9107
+ if ( table instanceof DataTable.Api ) {
9108
+ return true;
9109
+ }
9110
+
9085
9111
  $.each( DataTable.settings, function (i, o) {
9086
9112
  var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9087
9113
  var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
@@ -9170,9 +9196,11 @@
9170
9196
  var args = Array.prototype.slice.call(arguments);
9171
9197
 
9172
9198
  // Add the `dt` namespace automatically if it isn't already present
9173
- if ( ! args[0].match(/\.dt\b/) ) {
9174
- args[0] += '.dt';
9175
- }
9199
+ args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
9200
+ return ! e.match(/\.dt\b/) ?
9201
+ e+'.dt' :
9202
+ e;
9203
+ } ).join( ' ' );
9176
9204
 
9177
9205
  var inst = $( this.tables().nodes() );
9178
9206
  inst[key].apply( inst, args );
@@ -9237,8 +9265,8 @@
9237
9265
  // Blitz all `DT` namespaced events (these are internal events, the
9238
9266
  // lowercase, `dt` events are user subscribed and they are responsible
9239
9267
  // for removing them
9240
- jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
9241
- $(window).unbind('.DT-'+settings.sInstance);
9268
+ jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9269
+ $(window).off('.DT-'+settings.sInstance);
9242
9270
 
9243
9271
  // When scrolling we had to break the table up - restore it
9244
9272
  if ( table != thead.parentNode ) {
@@ -9368,7 +9396,7 @@
9368
9396
  * @type string
9369
9397
  * @default Version number
9370
9398
  */
9371
- DataTable.version = "1.10.12";
9399
+ DataTable.version = "1.10.13";
9372
9400
 
9373
9401
  /**
9374
9402
  * Private data store, containing all of the settings objects that are
@@ -10876,6 +10904,8 @@
10876
10904
  * @type function
10877
10905
  * @member
10878
10906
  * @param {object} settings DataTables settings object
10907
+ * @param {object} callback Callback that can be executed when done. It
10908
+ * should be passed the loaded state object.
10879
10909
  * @return {object} The DataTables state object to be loaded
10880
10910
  *
10881
10911
  * @dtopt Callbacks
@@ -10885,21 +10915,14 @@
10885
10915
  * $(document).ready( function() {
10886
10916
  * $('#example').dataTable( {
10887
10917
  * "stateSave": true,
10888
- * "stateLoadCallback": function (settings) {
10889
- * var o;
10890
- *
10891
- * // Send an Ajax request to the server to get the data. Note that
10892
- * // this is a synchronous request.
10918
+ * "stateLoadCallback": function (settings, callback) {
10893
10919
  * $.ajax( {
10894
10920
  * "url": "/state_load",
10895
- * "async": false,
10896
10921
  * "dataType": "json",
10897
10922
  * "success": function (json) {
10898
- * o = json;
10923
+ * callback( json );
10899
10924
  * }
10900
10925
  * } );
10901
- *
10902
- * return o;
10903
10926
  * }
10904
10927
  * } );
10905
10928
  * } );
@@ -11838,14 +11861,15 @@
11838
11861
 
11839
11862
 
11840
11863
  /**
11841
- * DataTables features four different built-in options for the buttons to
11864
+ * DataTables features six different built-in options for the buttons to
11842
11865
  * display for pagination control:
11843
11866
  *
11867
+ * * `numbers` - Page number buttons only
11844
11868
  * * `simple` - 'Previous' and 'Next' buttons only
11845
11869
  * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11846
11870
  * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11847
- * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
11848
- * page numbers
11871
+ * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11872
+ * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11849
11873
  *
11850
11874
  * Further methods can be added using {@link DataTable.ext.oPagination}.
11851
11875
  * @type string
@@ -14495,6 +14519,10 @@
14495
14519
  return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14496
14520
  },
14497
14521
 
14522
+ first_last_numbers: function (page, pages) {
14523
+ return ['first', _numbers(page, pages), 'last'];
14524
+ },
14525
+
14498
14526
  // For testing and plug-ins to use
14499
14527
  _numbers: _numbers,
14500
14528
 
@@ -14605,7 +14633,7 @@
14605
14633
 
14606
14634
  attach( $(host).empty(), buttons );
14607
14635
 
14608
- if ( activeEl ) {
14636
+ if ( activeEl !== undefined ) {
14609
14637
  $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14610
14638
  }
14611
14639
  }
@@ -14628,10 +14656,10 @@
14628
14656
  // Dates (only those recognised by the browser's Date.parse)
14629
14657
  function ( d, settings )
14630
14658
  {
14631
- // V8 will remove any unknown characters at the start and end of the
14632
- // expression, leading to false matches such as `$245.12` or `10%` being
14633
- // a valid date. See forum thread 18941 for detail.
14634
- if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14659
+ // V8 tries _very_ hard to make a string passed into `Date.parse()`
14660
+ // valid, so we need to use a regex to restrict date formats. Use a
14661
+ // plug-in for anything other than ISO8601 style strings
14662
+ if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
14635
14663
  return null;
14636
14664
  }
14637
14665
  var parsed = Date.parse(d);
@@ -14768,7 +14796,7 @@
14768
14796
  $.extend( _ext.type.order, {
14769
14797
  // Dates
14770
14798
  "date-pre": function ( d ) {
14771
- return Date.parse( d ) || 0;
14799
+ return Date.parse( d ) || -Infinity;
14772
14800
  },
14773
14801
 
14774
14802
  // html
@@ -14939,6 +14967,7 @@
14939
14967
  return __htmlEscapeEntities( d );
14940
14968
  }
14941
14969
 
14970
+ flo = flo.toFixed( precision );
14942
14971
  d = Math.abs( flo );
14943
14972
 
14944
14973
  var intPart = parseInt( d, 10 );