jquery-datatables 1.10.19.1 → 1.10.20

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -0
  3. data/README.md +28 -1
  4. data/app/assets/javascripts/datatables/dataTables.uikit.js +2 -2
  5. data/app/assets/javascripts/datatables/extensions/AutoFill/dataTables.autoFill.js +42 -29
  6. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.bootstrap.js +1 -1
  7. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.bootstrap4.js +8 -2
  8. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.colVis.js +6 -3
  9. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.foundation.js +5 -4
  10. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.html5.js +58 -6
  11. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.print.js +16 -5
  12. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.semanticui.js +1 -1
  13. data/app/assets/javascripts/datatables/extensions/Buttons/dataTables.buttons.js +267 -152
  14. data/app/assets/javascripts/datatables/extensions/ColReorder/colReorder.foundation.js +1 -1
  15. data/app/assets/javascripts/datatables/extensions/ColReorder/dataTables.colReorder.js +121 -52
  16. data/app/assets/javascripts/datatables/extensions/FixedColumns/dataTables.fixedColumns.js +32 -5
  17. data/app/assets/javascripts/datatables/extensions/KeyTable/dataTables.keyTable.js +166 -63
  18. data/app/assets/javascripts/datatables/extensions/KeyTable/keyTable.foundation.js +1 -1
  19. data/app/assets/javascripts/datatables/extensions/RowGroup/dataTables.rowGroup.js +105 -53
  20. data/app/assets/javascripts/datatables/extensions/RowGroup/rowGroup.foundation.js +1 -1
  21. data/app/assets/javascripts/datatables/extensions/RowGroup/{rowGroup.semanicui.js → rowGroup.semanticui.js} +0 -0
  22. data/app/assets/javascripts/datatables/extensions/RowReorder/dataTables.rowReorder.js +10 -9
  23. data/app/assets/javascripts/datatables/extensions/RowReorder/rowReorder.foundation.js +1 -1
  24. data/app/assets/javascripts/datatables/extensions/Scroller/dataTables.scroller.js +519 -636
  25. data/app/assets/javascripts/datatables/extensions/Scroller/scroller.foundation.js +1 -1
  26. data/app/assets/javascripts/datatables/extensions/Select/dataTables.select.js +49 -18
  27. data/app/assets/javascripts/datatables/extensions/Select/select.foundation.js +1 -1
  28. data/app/assets/javascripts/datatables/jquery.dataTables.js +97 -60
  29. data/app/assets/javascripts/datatables/plugins/api/average.js +7 -6
  30. data/app/assets/javascripts/datatables/plugins/api/sum.js +7 -6
  31. data/app/assets/javascripts/datatables/plugins/pagination/ellipses.js +160 -0
  32. data/app/assets/javascripts/datatables/plugins/pagination/extjs.js +137 -0
  33. data/app/assets/javascripts/datatables/plugins/pagination/four_button.js +110 -0
  34. data/app/assets/javascripts/datatables/plugins/pagination/full_numbers_no_ellipses.js +59 -0
  35. data/app/assets/javascripts/datatables/plugins/pagination/input.js +22 -19
  36. data/app/assets/javascripts/datatables/plugins/pagination/scrolling.js +130 -0
  37. data/app/assets/javascripts/datatables/plugins/pagination/select.js +97 -0
  38. data/app/assets/javascripts/datatables/plugins/pagination/simple_incremental_bootstrap.js +154 -0
  39. data/app/assets/javascripts/datatables/plugins/pagination/simple_numbers_no_ellipses.js +59 -0
  40. data/app/assets/javascripts/datatables/plugins/search/dataTables.alphabetSearch.js +440 -399
  41. data/app/assets/javascripts/datatables/plugins/sorting/enum.js +51 -0
  42. data/app/assets/javascripts/datatables/plugins/type-detection/date-dd-MMM-yyyy.js +63 -0
  43. data/app/assets/javascripts/datatables/plugins/type-detection/date-de.js +125 -0
  44. data/app/assets/javascripts/datatables/plugins/type-detection/date-eu.js +64 -0
  45. data/app/assets/javascripts/datatables/plugins/type-detection/date-euro.js +48 -0
  46. data/app/assets/javascripts/datatables/plugins/type-detection/date-uk.js +35 -12
  47. data/app/assets/javascripts/datatables/plugins/type-detection/datetime-moment.js +74 -0
  48. data/app/assets/javascripts/datatables/plugins/type-detection/datetime-us.js +86 -0
  49. data/app/assets/javascripts/datatables/plugins/type-detection/file-size.js +37 -13
  50. data/app/assets/javascripts/datatables/plugins/type-detection/ip-address.js +113 -11
  51. data/app/assets/javascripts/datatables/plugins/type-detection/numString.js +63 -0
  52. data/app/assets/javascripts/datatables/plugins/type-detection/percent.js +34 -0
  53. data/app/assets/javascripts/datatables/plugins/type-detection/time-elapsed-dhms.js +42 -0
  54. data/app/assets/javascripts/datatables/plugins/type-detection/time.js +56 -0
  55. data/app/assets/javascripts/datatables/plugins/type-detection/title-numeric.js +40 -0
  56. data/app/assets/javascripts/datatables/plugins/type-detection/title-string.js +36 -0
  57. data/app/assets/stylesheets/datatables/extensions/AutoFill/autoFill.dataTables.scss +10 -3
  58. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.bootstrap.scss +12 -3
  59. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.bootstrap4.scss +13 -6
  60. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.dataTables.scss +2 -0
  61. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.foundation.scss +5 -1
  62. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.jqueryui.scss +1 -0
  63. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.semanticui.scss +2 -1
  64. data/app/assets/stylesheets/datatables/extensions/Buttons/common.scss +10 -0
  65. data/app/assets/stylesheets/datatables/extensions/Buttons/mixins.scss +42 -30
  66. data/app/assets/stylesheets/datatables/extensions/FixedColumns/fixedColumns.bootstrap.scss +11 -7
  67. data/app/assets/stylesheets/datatables/extensions/FixedColumns/fixedColumns.foundation.scss +1 -0
  68. data/app/assets/stylesheets/datatables/extensions/KeyTable/keyTable.dataTables.scss +13 -5
  69. data/app/assets/stylesheets/datatables/extensions/RowGroup/rowGroup.dataTables.scss +20 -2
  70. data/app/assets/stylesheets/datatables/extensions/Scroller/scroller.dataTables.scss +15 -2
  71. data/lib/jquery-datatables/version.rb +1 -1
  72. metadata +26 -12
  73. data/app/assets/javascripts/datatables/dataTables.bootstrap2.js +0 -162
  74. data/app/assets/javascripts/datatables/extensions/ColReorder/colReorder.semanicui.js +0 -38
  75. data/app/assets/javascripts/datatables/extensions/FixedColumns/fixedColumns.semanicui.js +0 -38
  76. data/app/assets/javascripts/datatables/extensions/FixedHeader/fixedHeader.semanicui.js +0 -38
  77. data/app/assets/javascripts/datatables/extensions/KeyTable/keyTable.semanicui.js +0 -38
  78. data/app/assets/javascripts/datatables/extensions/RowReorder/rowReorder.semanicui.js +0 -38
  79. data/app/assets/stylesheets/datatables/dataTables.bootstrap2.scss +0 -178
@@ -91,9 +91,13 @@ DataTable.ext.buttons.print = {
91
91
  $.extend( {decodeEntities: false}, config.exportOptions ) // XSS protection
92
92
  );
93
93
  var exportInfo = dt.buttons.exportInfo( config );
94
- var columnClasses = $.map( dt.settings()[0].aoColumns, function (col, key) {
95
- return col.sClass;
96
- } );
94
+ var columnClasses = dt
95
+ .columns( config.exportOptions.columns )
96
+ .flatten()
97
+ .map( function (idx) {
98
+ return dt.settings()[0].aoColumns[dt.column(idx).index()].sClass;
99
+ } )
100
+ .toArray();
97
101
 
98
102
  var addRow = function ( d, tag ) {
99
103
  var str = '<tr>';
@@ -169,12 +173,19 @@ DataTable.ext.buttons.print = {
169
173
  }
170
174
 
171
175
  // Allow stylesheets time to load
172
- win.setTimeout( function () {
176
+ var autoPrint = function () {
173
177
  if ( config.autoPrint ) {
174
178
  win.print(); // blocking - so close will not
175
179
  win.close(); // execute until this is done
176
180
  }
177
- }, 1000 );
181
+ };
182
+
183
+ if ( navigator.userAgent.match(/Trident\/\d.\d/) ) { // IE needs to call this without a setTimeout
184
+ autoPrint();
185
+ }
186
+ else {
187
+ win.setTimeout( autoPrint, 1000 );
188
+ }
178
189
  },
179
190
 
180
191
  title: '*',
@@ -47,7 +47,7 @@ $.extend( true, DataTable.Buttons.defaults, {
47
47
  },
48
48
  collection: {
49
49
  tag: 'div',
50
- className: 'dt-button-collection ui basic vertical buttons'
50
+ className: 'ui basic vertical buttons'
51
51
  }
52
52
  }
53
53
  } );
@@ -1,5 +1,5 @@
1
- /*! Buttons for DataTables 1.5.2
2
- * ©2016-2018 SpryMedia Ltd - datatables.net/license
1
+ /*! Buttons for DataTables 1.6.1
2
+ * ©2016-2019 SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
5
5
  (function( factory ){
@@ -48,6 +48,15 @@ var _dtButtons = DataTable.ext.buttons;
48
48
  */
49
49
  var Buttons = function( dt, config )
50
50
  {
51
+ // If not created with a `new` keyword then we return a wrapper function that
52
+ // will take the settings object for a DT. This allows easy use of new instances
53
+ // with the `layout` option - e.g. `topLeft: $.fn.dataTable.Buttons( ... )`.
54
+ if ( !(this instanceof Buttons) ) {
55
+ return function (settings) {
56
+ return new Buttons( settings, dt ).container();
57
+ };
58
+ }
59
+
51
60
  // If there is no config set it to an empty object
52
61
  if ( typeof( config ) === 'undefined' ) {
53
62
  config = {};
@@ -157,7 +166,7 @@ $.extend( Buttons.prototype, {
157
166
  idx = split[ split.length-1 ]*1;
158
167
  }
159
168
 
160
- this._expandButton( buttons, config, false, idx );
169
+ this._expandButton( buttons, config, base !== undefined, idx );
161
170
  this._draw();
162
171
 
163
172
  return this;
@@ -248,23 +257,29 @@ $.extend( Buttons.prototype, {
248
257
  },
249
258
 
250
259
  /**
251
- * Get a button's node
252
- * @param {node} node Button node
253
- * @return {jQuery} Button element
260
+ * Get a button's node of the buttons container if no button is given
261
+ * @param {node} [node] Button node
262
+ * @return {jQuery} Button element, or container
254
263
  */
255
264
  node: function ( node )
256
265
  {
266
+ if ( ! node ) {
267
+ return this.dom.container;
268
+ }
269
+
257
270
  var button = this._nodeToButton( node );
258
271
  return $(button.node);
259
272
  },
260
273
 
261
274
  /**
262
275
  * Set / get a processing class on the selected button
276
+ * @param {element} node Triggering button node
263
277
  * @param {boolean} flag true to add, false to remove, undefined to get
264
278
  * @return {boolean|Buttons} Getter value or this if a setter.
265
279
  */
266
280
  processing: function ( node, flag )
267
281
  {
282
+ var dt = this.s.dt;
268
283
  var button = this._nodeToButton( node );
269
284
 
270
285
  if ( flag === undefined ) {
@@ -273,6 +288,10 @@ $.extend( Buttons.prototype, {
273
288
 
274
289
  $(button.node).toggleClass( 'processing', flag );
275
290
 
291
+ $(dt.table().node()).triggerHandler( 'buttons-processing.dt', [
292
+ flag, dt.button( node ), dt, $(node), button.conf
293
+ ] );
294
+
276
295
  return this;
277
296
  },
278
297
 
@@ -486,10 +505,8 @@ $.extend( Buttons.prototype, {
486
505
  }
487
506
 
488
507
  if ( built.conf.buttons ) {
489
- var collectionDom = this.c.dom.collection;
490
- built.collection = $('<'+collectionDom.tag+'/>')
491
- .addClass( collectionDom.className )
492
- .attr( 'role', 'menu') ;
508
+ built.collection = $('<'+this.c.dom.collection.tag+'/>');
509
+
493
510
  built.conf._collection = built.collection;
494
511
 
495
512
  this._expandButton( built.buttons, built.conf.buttons, true, attachPoint );
@@ -547,6 +564,7 @@ $.extend( Buttons.prototype, {
547
564
  };
548
565
 
549
566
  var tag = config.tag || buttonDom.tag;
567
+ var clickBlurs = config.clickBlurs === undefined ? true : config.clickBlurs
550
568
  var button = $('<'+tag+'/>')
551
569
  .addClass( buttonDom.className )
552
570
  .attr( 'tabindex', this.s.dt.settings()[0].iTabIndex )
@@ -557,8 +575,9 @@ $.extend( Buttons.prototype, {
557
575
  if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
558
576
  action( e, dt, button, config );
559
577
  }
560
-
561
- button.blur();
578
+ if( clickBlurs ) {
579
+ button.blur();
580
+ }
562
581
  } )
563
582
  .on( 'keyup.dtb', function (e) {
564
583
  if ( e.keyCode === 13 ) {
@@ -626,6 +645,13 @@ $.extend( Buttons.prototype, {
626
645
 
627
646
  this._addKey( config );
628
647
 
648
+ // Style integration callback for DOM manipulation
649
+ // Note that this is _not_ documented. It is currently
650
+ // for style integration only
651
+ if( this.c.buttonCreated ) {
652
+ inserter = this.c.buttonCreated( config, inserter );
653
+ }
654
+
629
655
  return {
630
656
  conf: config,
631
657
  node: button.get(0),
@@ -892,6 +918,180 @@ $.extend( Buttons.prototype, {
892
918
  }
893
919
 
894
920
  return conf;
921
+ },
922
+
923
+ /**
924
+ * Display (and replace if there is an existing one) a popover attached to a button
925
+ * @param {string|node} content Content to show
926
+ * @param {DataTable.Api} hostButton DT API instance of the button
927
+ * @param {object} inOpts Options (see object below for all options)
928
+ */
929
+ _popover: function ( content, hostButton, inOpts ) {
930
+ var dt = hostButton;
931
+ var buttonsSettings = this.c;
932
+ var options = $.extend( {
933
+ align: 'button-left', // button-right, dt-container
934
+ autoClose: false,
935
+ background: true,
936
+ backgroundClassName: 'dt-button-background',
937
+ contentClassName: buttonsSettings.dom.collection.className,
938
+ collectionLayout: '',
939
+ collectionTitle: '',
940
+ dropup: false,
941
+ fade: 400,
942
+ rightAlignClassName: 'dt-button-right',
943
+ tag: buttonsSettings.dom.collection.tag
944
+ }, inOpts );
945
+ var hostNode = hostButton.node();
946
+
947
+ var close = function () {
948
+ $('.dt-button-collection').stop().fadeOut( options.fade, function () {
949
+ $(this).detach();
950
+ } );
951
+
952
+ $(dt.buttons( '[aria-haspopup="true"][aria-expanded="true"]' ).nodes())
953
+ .attr('aria-expanded', 'false');
954
+
955
+ $('div.dt-button-background').off( 'click.dtb-collection' );
956
+ Buttons.background( false, options.backgroundClassName, options.fade, hostNode );
957
+
958
+ $('body').off( '.dtb-collection' );
959
+ dt.off( 'buttons-action.b-internal' );
960
+ };
961
+
962
+ if (content === false) {
963
+ close();
964
+ }
965
+
966
+ var existingExpanded = $(dt.buttons( '[aria-haspopup="true"][aria-expanded="true"]' ).nodes());
967
+ if ( existingExpanded.length ) {
968
+ hostNode = existingExpanded.eq(0);
969
+
970
+ close();
971
+ }
972
+
973
+ var display = $('<div/>')
974
+ .addClass('dt-button-collection')
975
+ .addClass(options.collectionLayout)
976
+ .css('display', 'none');
977
+
978
+ content = $(content)
979
+ .addClass(options.contentClassName)
980
+ .attr('role', 'menu')
981
+ .appendTo(display);
982
+
983
+ hostNode.attr( 'aria-expanded', 'true' );
984
+
985
+ if ( hostNode.parents('body')[0] !== document.body ) {
986
+ hostNode = document.body.lastChild;
987
+ }
988
+
989
+ if ( options.collectionTitle ) {
990
+ display.prepend('<div class="dt-button-collection-title">'+options.collectionTitle+'</div>');
991
+ }
992
+
993
+ display
994
+ .insertAfter( hostNode )
995
+ .fadeIn( options.fade );
996
+
997
+ var tableContainer = $( hostButton.table().container() );
998
+ var position = display.css( 'position' );
999
+
1000
+ if ( options.align === 'dt-container' ) {
1001
+ hostNode = hostNode.parent();
1002
+ display.css('width', tableContainer.width());
1003
+ }
1004
+
1005
+ if ( position === 'absolute' ) {
1006
+ var hostPosition = hostNode.position();
1007
+
1008
+ display.css( {
1009
+ top: hostPosition.top + hostNode.outerHeight(),
1010
+ left: hostPosition.left
1011
+ } );
1012
+
1013
+ // calculate overflow when positioned beneath
1014
+ var collectionHeight = display.outerHeight();
1015
+ var collectionWidth = display.outerWidth();
1016
+ var tableBottom = tableContainer.offset().top + tableContainer.height();
1017
+ var listBottom = hostPosition.top + hostNode.outerHeight() + collectionHeight;
1018
+ var bottomOverflow = listBottom - tableBottom;
1019
+
1020
+ // calculate overflow when positioned above
1021
+ var listTop = hostPosition.top - collectionHeight;
1022
+ var tableTop = tableContainer.offset().top;
1023
+ var topOverflow = tableTop - listTop;
1024
+
1025
+ // if bottom overflow is larger, move to the top because it fits better, or if dropup is requested
1026
+ var moveTop = hostPosition.top - collectionHeight - 5;
1027
+ if ( (bottomOverflow > topOverflow || options.dropup) && -moveTop < tableTop ) {
1028
+ display.css( 'top', moveTop);
1029
+ }
1030
+
1031
+ // Right alignment is enabled on a class, e.g. bootstrap:
1032
+ // $.fn.dataTable.Buttons.defaults.dom.collection.className += " dropdown-menu-right";
1033
+ if ( display.hasClass( options.rightAlignClassName ) || options.align === 'button-right' ) {
1034
+ display.css( 'left', hostPosition.left + hostNode.outerWidth() - collectionWidth );
1035
+ }
1036
+
1037
+ // Right alignment in table container
1038
+ var listRight = hostPosition.left + collectionWidth;
1039
+ var tableRight = tableContainer.offset().left + tableContainer.width();
1040
+ if ( listRight > tableRight ) {
1041
+ display.css( 'left', hostPosition.left - ( listRight - tableRight ) );
1042
+ }
1043
+
1044
+ // Right alignment to window
1045
+ var listOffsetRight = hostNode.offset().left + collectionWidth;
1046
+ if ( listOffsetRight > $(window).width() ) {
1047
+ display.css( 'left', hostPosition.left - (listOffsetRight-$(window).width()) );
1048
+ }
1049
+ }
1050
+ else {
1051
+ // Fix position - centre on screen
1052
+ var top = display.height() / 2;
1053
+ if ( top > $(window).height() / 2 ) {
1054
+ top = $(window).height() / 2;
1055
+ }
1056
+
1057
+ display.css( 'marginTop', top*-1 );
1058
+ }
1059
+
1060
+ if ( options.background ) {
1061
+ Buttons.background( true, options.backgroundClassName, options.fade, hostNode );
1062
+ }
1063
+
1064
+ // This is bonkers, but if we don't have a click listener on the
1065
+ // background element, iOS Safari will ignore the body click
1066
+ // listener below. An empty function here is all that is
1067
+ // required to make it work...
1068
+ $('div.dt-button-background').on( 'click.dtb-collection', function () {} );
1069
+
1070
+ $('body')
1071
+ .on( 'click.dtb-collection', function (e) {
1072
+ // andSelf is deprecated in jQ1.8, but we want 1.7 compat
1073
+ var back = $.fn.addBack ? 'addBack' : 'andSelf';
1074
+
1075
+ if ( ! $(e.target).parents()[back]().filter( content ).length ) {
1076
+ close();
1077
+ }
1078
+ } )
1079
+ .on( 'keyup.dtb-collection', function (e) {
1080
+ if ( e.keyCode === 27 ) {
1081
+ close();
1082
+ }
1083
+ } );
1084
+
1085
+ if ( options.autoClose ) {
1086
+ setTimeout( function () {
1087
+ dt.on( 'buttons-action.b-internal', function (e, btn, dt, node) {
1088
+ if ( node[0] === hostNode[0] ) {
1089
+ return;
1090
+ }
1091
+ close();
1092
+ } );
1093
+ }, 0);
1094
+ }
895
1095
  }
896
1096
  } );
897
1097
 
@@ -908,20 +1108,25 @@ $.extend( Buttons.prototype, {
908
1108
  * @param {string} Class to assign to the background
909
1109
  * @static
910
1110
  */
911
- Buttons.background = function ( show, className, fade ) {
1111
+ Buttons.background = function ( show, className, fade, insertPoint ) {
912
1112
  if ( fade === undefined ) {
913
1113
  fade = 400;
914
1114
  }
1115
+ if ( ! insertPoint ) {
1116
+ insertPoint = document.body;
1117
+ }
915
1118
 
916
1119
  if ( show ) {
917
1120
  $('<div/>')
918
1121
  .addClass( className )
919
1122
  .css( 'display', 'none' )
920
- .appendTo( 'body' )
1123
+ .insertAfter( insertPoint )
1124
+ .stop()
921
1125
  .fadeIn( fade );
922
1126
  }
923
1127
  else {
924
- $('body > div.'+className)
1128
+ $('div.'+className)
1129
+ .stop()
925
1130
  .fadeOut( fade, function () {
926
1131
  $(this)
927
1132
  .removeClass( className )
@@ -943,7 +1148,7 @@ Buttons.background = function ( show, className, fade ) {
943
1148
  */
944
1149
  Buttons.instanceSelector = function ( group, buttons )
945
1150
  {
946
- if ( ! group ) {
1151
+ if ( group === undefined || group === null ) {
947
1152
  return $.map( buttons, function ( v ) {
948
1153
  return v.inst;
949
1154
  } );
@@ -1142,10 +1347,13 @@ Buttons.defaults = {
1142
1347
  },
1143
1348
  collection: {
1144
1349
  tag: 'div',
1145
- className: 'dt-button-collection'
1350
+ className: ''
1146
1351
  },
1147
1352
  button: {
1148
- tag: 'button',
1353
+ // Flash buttons will not work with `<button>` in IE - it has to be `<a>`
1354
+ tag: 'ActiveXObject' in window ?
1355
+ 'a' :
1356
+ 'button',
1149
1357
  className: 'dt-button',
1150
1358
  active: 'active',
1151
1359
  disabled: 'disabled'
@@ -1162,7 +1370,7 @@ Buttons.defaults = {
1162
1370
  * @type {string}
1163
1371
  * @static
1164
1372
  */
1165
- Buttons.version = '1.5.2';
1373
+ Buttons.version = '1.6.1';
1166
1374
 
1167
1375
 
1168
1376
  $.extend( _dtButtons, {
@@ -1171,140 +1379,23 @@ $.extend( _dtButtons, {
1171
1379
  return dt.i18n( 'buttons.collection', 'Collection' );
1172
1380
  },
1173
1381
  className: 'buttons-collection',
1382
+ init: function ( dt, button, config ) {
1383
+ button.attr( 'aria-expanded', false );
1384
+ },
1174
1385
  action: function ( e, dt, button, config ) {
1175
- var host = button;
1176
- var collectionParent = $(button).parents('div.dt-button-collection');
1177
- var hostPosition = host.position();
1178
- var tableContainer = $( dt.table().container() );
1179
- var multiLevel = false;
1180
- var insertPoint = host;
1181
-
1182
- // Remove any old collection
1183
- if ( collectionParent.length ) {
1184
- multiLevel = $('.dt-button-collection').position();
1185
- insertPoint = collectionParent;
1186
- $('body').trigger( 'click.dtb-collection' );
1187
- }
1188
-
1189
- if ( insertPoint.parents('body')[0] !== document.body ) {
1190
- insertPoint = document.body.lastChild;
1191
- }
1192
-
1193
- config._collection
1194
- .addClass( config.collectionLayout )
1195
- .css( 'display', 'none' )
1196
- .insertAfter( insertPoint )
1197
- .fadeIn( config.fade );
1198
-
1199
-
1200
- var position = config._collection.css( 'position' );
1386
+ e.stopPropagation();
1201
1387
 
1202
- if ( multiLevel && position === 'absolute' ) {
1203
- config._collection.css( {
1204
- top: multiLevel.top,
1205
- left: multiLevel.left
1206
- } );
1207
- }
1208
- else if ( position === 'absolute' ) {
1209
- config._collection.css( {
1210
- top: hostPosition.top + host.outerHeight(),
1211
- left: hostPosition.left
1212
- } );
1213
-
1214
- // calculate overflow when positioned beneath
1215
- var tableBottom = tableContainer.offset().top + tableContainer.height();
1216
- var listBottom = hostPosition.top + host.outerHeight() + config._collection.outerHeight();
1217
- var bottomOverflow = listBottom - tableBottom;
1218
-
1219
- // calculate overflow when positioned above
1220
- var listTop = hostPosition.top - config._collection.outerHeight();
1221
- var tableTop = tableContainer.offset().top;
1222
- var topOverflow = tableTop - listTop;
1223
-
1224
- // if bottom overflow is larger, move to the top because it fits better, or if dropup is requested
1225
- if (bottomOverflow > topOverflow || config.dropup) {
1226
- config._collection.css( 'top', hostPosition.top - config._collection.outerHeight() - 5);
1227
- }
1228
-
1229
- // Right alignment in table container
1230
- var listRight = hostPosition.left + config._collection.outerWidth();
1231
- var tableRight = tableContainer.offset().left + tableContainer.width();
1232
- if ( listRight > tableRight ) {
1233
- config._collection.css( 'left', hostPosition.left - ( listRight - tableRight ) );
1234
- }
1235
-
1236
- // Right alignment to window
1237
- var listOffsetRight = host.offset().left + config._collection.outerWidth();
1238
- if ( listOffsetRight > $(window).width() ) {
1239
- config._collection.css( 'left', hostPosition.left - (listOffsetRight-$(window).width()) );
1240
- }
1388
+ if ( config._collection.parents('body').length ) {
1389
+ this.popover(false, config);
1241
1390
  }
1242
1391
  else {
1243
- // Fix position - centre on screen
1244
- var top = config._collection.height() / 2;
1245
- if ( top > $(window).height() / 2 ) {
1246
- top = $(window).height() / 2;
1247
- }
1248
-
1249
- config._collection.css( 'marginTop', top*-1 );
1392
+ this.popover(config._collection, config);
1250
1393
  }
1251
-
1252
- if ( config.background ) {
1253
- Buttons.background( true, config.backgroundClassName, config.fade );
1254
- }
1255
-
1256
- var close = function () {
1257
- config._collection
1258
- .fadeOut( config.fade, function () {
1259
- config._collection.detach();
1260
- } );
1261
-
1262
- $('div.dt-button-background').off( 'click.dtb-collection' );
1263
- Buttons.background( false, config.backgroundClassName, config.fade );
1264
-
1265
- $('body').off( '.dtb-collection' );
1266
- dt.off( 'buttons-action.b-internal' );
1267
- };
1268
-
1269
- // Need to break the 'thread' for the collection button being
1270
- // activated by a click - it would also trigger this event
1271
- setTimeout( function () {
1272
- // This is bonkers, but if we don't have a click listener on the
1273
- // background element, iOS Safari will ignore the body click
1274
- // listener below. An empty function here is all that is
1275
- // required to make it work...
1276
- $('div.dt-button-background').on( 'click.dtb-collection', function () {} );
1277
-
1278
- $('body')
1279
- .on( 'click.dtb-collection', function (e) {
1280
- // andSelf is deprecated in jQ1.8, but we want 1.7 compat
1281
- var back = $.fn.addBack ? 'addBack' : 'andSelf';
1282
-
1283
- if ( ! $(e.target).parents()[back]().filter( config._collection ).length ) {
1284
- close();
1285
- }
1286
- } )
1287
- .on( 'keyup.dtb-collection', function (e) {
1288
- if ( e.keyCode === 27 ) {
1289
- close();
1290
- }
1291
- } );
1292
-
1293
- if ( config.autoClose ) {
1294
- dt.on( 'buttons-action.b-internal', function () {
1295
- close();
1296
- } );
1297
- }
1298
- }, 10 );
1299
1394
  },
1300
- background: true,
1301
- collectionLayout: '',
1302
- backgroundClassName: 'dt-button-background',
1303
- autoClose: false,
1304
- fade: 400,
1305
1395
  attr: {
1306
1396
  'aria-haspopup': true
1307
1397
  }
1398
+ // Also the popover options, defined in Buttons.popover
1308
1399
  },
1309
1400
  copy: function ( dt, conf ) {
1310
1401
  if ( _dtButtons.copyHtml5 ) {
@@ -1381,7 +1472,7 @@ $.extend( _dtButtons, {
1381
1472
  init: function ( dt, node, conf ) {
1382
1473
  var that = this;
1383
1474
  dt.on( 'length.dt'+conf.namespace, function () {
1384
- that.text( text( dt ) );
1475
+ that.text( conf.text );
1385
1476
  } );
1386
1477
  },
1387
1478
  destroy: function ( dt, node, conf ) {
@@ -1519,8 +1610,15 @@ DataTable.Api.registerPlural( 'buttons().trigger()', 'button().trigger()', funct
1519
1610
  } );
1520
1611
  } );
1521
1612
 
1613
+ // Button resolver to the popover
1614
+ DataTable.Api.register( 'button().popover()', function (content, options) {
1615
+ return this.map( function ( set ) {
1616
+ return set.inst._popover( content, this.button(this[0].node), options );
1617
+ } );
1618
+ } );
1619
+
1522
1620
  // Get the container elements
1523
- DataTable.Api.registerPlural( 'buttons().containers()', 'buttons().container()', function () {
1621
+ DataTable.Api.register( 'buttons().containers()', function () {
1524
1622
  var jq = $();
1525
1623
  var groupSelector = this._groupSelector;
1526
1624
 
@@ -1539,6 +1637,11 @@ DataTable.Api.registerPlural( 'buttons().containers()', 'buttons().container()',
1539
1637
  return jq;
1540
1638
  } );
1541
1639
 
1640
+ DataTable.Api.register( 'buttons().container()', function () {
1641
+ // API level of nesting is `buttons()` so we can zip into the containers method
1642
+ return this.containers().eq(0);
1643
+ } );
1644
+
1542
1645
  // Add a new button
1543
1646
  DataTable.Api.register( 'button().add()', function ( idx, conf ) {
1544
1647
  var ctx = this.context;
@@ -1579,6 +1682,7 @@ DataTable.Api.register( 'buttons.info()', function ( title, message, time ) {
1579
1682
  var that = this;
1580
1683
 
1581
1684
  if ( title === false ) {
1685
+ this.off('destroy.btn-info');
1582
1686
  $('#datatables_buttons_info').fadeOut( function () {
1583
1687
  $(this).remove();
1584
1688
  } );
@@ -1611,6 +1715,10 @@ DataTable.Api.register( 'buttons.info()', function ( title, message, time ) {
1611
1715
  }, time );
1612
1716
  }
1613
1717
 
1718
+ this.on('destroy.btn-info', function () {
1719
+ that.buttons.info(false);
1720
+ });
1721
+
1614
1722
  return this;
1615
1723
  } );
1616
1724
 
@@ -1884,17 +1992,24 @@ $(document).on( 'init.dt plugin-init.dt', function (e, settings) {
1884
1992
  }
1885
1993
  } );
1886
1994
 
1995
+ function _init ( settings ) {
1996
+ var api = new DataTable.Api( settings );
1997
+ var opts = api.init().buttons || DataTable.defaults.buttons;
1998
+
1999
+ return new Buttons( api, opts ).container();
2000
+ }
2001
+
1887
2002
  // DataTables `dom` feature option
1888
2003
  DataTable.ext.feature.push( {
1889
- fnInit: function( settings ) {
1890
- var api = new DataTable.Api( settings );
1891
- var opts = api.init().buttons || DataTable.defaults.buttons;
1892
-
1893
- return new Buttons( api, opts ).container();
1894
- },
2004
+ fnInit: _init,
1895
2005
  cFeature: "B"
1896
2006
  } );
1897
2007
 
2008
+ // DataTables 2 layout feature
2009
+ if ( DataTable.ext.features ) {
2010
+ DataTable.ext.features.register( 'buttons', _init );
2011
+ }
2012
+
1898
2013
 
1899
2014
  return Buttons;
1900
2015
  }));